From ad84944d20c9dd86058f6bdd6c10ea15d0f62425 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 1 Dec 2020 03:55:41 +0300 Subject: [PATCH 01/47] [make] change AES support check --- Makefile.linux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.linux b/Makefile.linux index ee6a902b..da5f68b4 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -58,7 +58,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),yes) -ifeq (, $(findstring arm, $(SYS))$(findstring aarch64, $(SYS))) # no arm and aarch64 in dumpmachine +ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that NEEDED_CXXFLAGS += -D__AES__ -maes endif endif From 2f57013e02cb105926e6919551b67bfcee751f89 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 1 Dec 2020 05:07:41 +0300 Subject: [PATCH 02/47] [qt] update project file Some build systems didn't create required folders for object files, so create them manually with additional call of `mk_obj_dir` target. --- qt/i2pd_qt/i2pd_qt.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index eed4cd7b..004b6273 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -79,7 +79,7 @@ libi2pd.commands = @echo Building i2pd libraries libi2pd.target = $$PWD/../../libi2pd.a libi2pd.depends = i2pd FORCE -i2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE api_client +i2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE mk_obj_dir api_client i2pd.target += $$PWD/../../libi2pdclient.a i2pd.depends = FORCE From ce14ea6fe5b6b849a734d4683b3a97e076a7fb53 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 3 Dec 2020 09:35:43 +0300 Subject: [PATCH 03/47] [windows] add file version to installer Signed-off-by: R4SAS --- build/build_mingw.cmd | 2 +- build/win_installer.iss | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index aaf25843..e8f1378b 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -64,7 +64,7 @@ call :BUILDING_XP echo. REM compile installer -C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_ver="%tag%" build\win_installer.iss >> build\build.log 2>&1 +C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_TextVer="%tag%" /dI2Pd_Ver="%tag%.0" build\win_installer.iss >> build\build.log 2>&1 del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul diff --git a/build/win_installer.iss b/build/win_installer.iss index 8a93a2c7..97cd4408 100644 --- a/build/win_installer.iss +++ b/build/win_installer.iss @@ -6,25 +6,35 @@ [Setup] AppName={#I2Pd_AppName} -AppVersion={#I2Pd_ver} +AppVersion={#I2Pd_TextVer} AppPublisher={#I2Pd_Publisher} + DefaultDirName={pf}\I2Pd DefaultGroupName=I2Pd UninstallDisplayIcon={app}\I2Pd.exe OutputDir=. +OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_TextVer} + LicenseFile=..\LICENSE -OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver} SetupIconFile=..\Win32\mask.ico + InternalCompressLevel=ultra64 Compression=lzma/ultra64 SolidCompression=true + ArchitecturesInstallIn64BitMode=x64 -AppVerName={#I2Pd_AppName} ExtraDiskSpaceRequired=15 + AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2} +AppVerName={#I2Pd_AppName} +AppCopyright=Copyright (c) 2013-2020, The PurpleI2P Project AppPublisherURL=http://i2pd.website/ AppSupportURL=https://github.com/PurpleI2P/i2pd/issues AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases + +VersionInfoProductVersion={#I2Pd_Ver} +VersionInfoVersion={#I2Pd_Ver} + CloseApplications=yes [Files] From 32fc6482ccc3394f19a86b15ee920cbcffb92417 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Dec 2020 17:58:37 -0500 Subject: [PATCH 04/47] moved Noise initializations to Crypto.cpp --- libi2pd/Crypto.cpp | 61 +++++++++++++++++++++++ libi2pd/Crypto.h | 4 ++ libi2pd/ECIESX25519AEADRatchetSession.cpp | 24 ++------- libi2pd/ECIESX25519AEADRatchetSession.h | 1 - libi2pd/NTCP2.cpp | 18 +------ libi2pd/RouterContext.cpp | 4 +- libi2pd/TunnelConfig.cpp | 15 +----- libi2pd/TunnelConfig.h | 2 - 8 files changed, 71 insertions(+), 58 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 523828ce..6055f888 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1316,6 +1316,8 @@ namespace crypto #endif } +// Noise + void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) { SHA256_CTX ctx; @@ -1331,6 +1333,65 @@ namespace crypto // new ck is m_CK[0:31], key is m_CK[32:63] } + void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) + { + // pub is Bob's public static key + static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars + static const uint8_t hh[32] = + { + 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, + 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 + }; // hh = SHA256(protocol_name || 0) + memcpy (state.m_CK, protocolName, 32); // ck = protocol_name || 0 + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + } + + void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) + { + // pub is Bob's public static key + static const uint8_t protocolNameHash[] = + { + 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, + 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 + }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") + static const uint8_t hh[32] = + { + 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, + 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e + }; // SHA256 (protocolNameHash) + memcpy (state.m_CK, protocolNameHash, 32); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + } + + void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) + { + // pub is Bob's public static key + static const uint8_t protocolNameHash[32] = + { + 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba, + 0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c + }; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes + static const uint8_t hh[32] = + { + 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, + 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c + }; // SHA256 (protocolNameHash) + memcpy (state.m_CK, protocolNameHash, 32); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + } + // init and terminate /* std::vector > m_OpenSSLMutexes; diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index da7a4bf4..c63cc45e 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -318,6 +318,10 @@ namespace crypto void MixKey (const uint8_t * sharedSecret); }; + void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router) + void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2) + void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) + // init and terminate void InitCrypto (bool precomputation, bool aesni, bool avx, bool force); void TerminateCrypto (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 00efee48..b3b30a1b 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -153,29 +153,12 @@ namespace garlic GarlicRoutingSession (owner, attachLeaseSet) { RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0; - ResetKeys (); } ECIESX25519AEADRatchetSession::~ECIESX25519AEADRatchetSession () { } - void ECIESX25519AEADRatchetSession::ResetKeys () - { - static const uint8_t protocolNameHash[32] = - { - 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba, - 0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c - }; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes - static const uint8_t hh[32] = - { - 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, - 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c - }; // SHA256 (protocolNameHash) - memcpy (m_CK, protocolNameHash, 32); - memcpy (m_H, hh, 32); - } - void ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce) { memset (nonce, 0, 4); @@ -236,8 +219,8 @@ namespace garlic if (!GetOwner ()) return false; // we are Bob // KDF1 - MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD), 32); // h = SHA256(h || bpk) - + i2p::crypto::InitNoiseIKState (*this, GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk + if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) { LogPrint (eLogError, "Garlic: Can't decode elligator"); @@ -448,7 +431,6 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic) { - ResetKeys (); // we are Alice, bpk is m_RemoteStaticKey size_t offset = 0; if (!GenerateEphemeralKeysAndEncode (out + offset)) @@ -459,7 +441,7 @@ namespace garlic offset += 32; // KDF1 - MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk) + i2p::crypto::InitNoiseIKState (*this, m_RemoteStaticKey); // bpk MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 755531a3..e71d9782 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -178,7 +178,6 @@ namespace garlic private: - void ResetKeys (); void CreateNonce (uint64_t seqn, uint8_t * nonce); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes std::shared_ptr CreateNewSessionTagset (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index bb54437e..1706399d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -41,23 +41,7 @@ namespace transport void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) { - static const uint8_t protocolNameHash[] = - { - 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, - 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 - }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") - static const uint8_t hh[32] = - { - 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, - 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e - }; // SHA256 (protocolNameHash) - memcpy (m_CK, protocolNameHash, 32); - // h = SHA256(hh || rs) - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, rs, 32); - SHA256_Final (m_H, &ctx); + i2p::crypto::InitNoiseXKState (*this, rs); // h = SHA256(h || epub) MixHash (epub, 32); // x25519 between pub and priv diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index cdab624c..3c066532 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -19,7 +19,6 @@ #include "version.h" #include "Log.h" #include "Family.h" -#include "TunnelConfig.h" #include "RouterContext.h" namespace i2p @@ -45,8 +44,7 @@ namespace i2p if (IsECIES ()) { auto initState = new i2p::crypto::NoiseSymmetricState (); - i2p::tunnel::InitBuildRequestRecordNoiseState (*initState); - initState->MixHash (GetIdentity ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || hepk) + i2p::crypto::InitNoiseNState (*initState, GetIdentity ()->GetEncryptionPublicKey ()); m_InitialNoiseState.reset (initState); } } diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index a1b234a1..d43483c0 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -127,10 +127,9 @@ namespace tunnel void TunnelHopConfig::EncryptECIES (std::shared_ptr& encryptor, const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx) { - InitBuildRequestRecordNoiseState (*this); uint8_t hepk[32]; encryptor->Encrypt (nullptr, hepk, nullptr, false); - MixHash (hepk, 32); // h = SHA256(h || hepk) + i2p::crypto::InitNoiseNState (*this, hepk); auto ephemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32); MixHash (encrypted, 32); // h = SHA256(h || sepk) @@ -148,17 +147,5 @@ namespace tunnel } MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) } - - void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state) - { - static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars - static const uint8_t hh[32] = - { - 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, - 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 - }; // SHA256 (protocol_name || 0) - memcpy (state.m_CK, protocolName, 32); // ck = h = protocol_name || 0 - memcpy (state.m_H, hh, 32); // h = SHA256(h) - } } } \ No newline at end of file diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 9aed0d25..45693970 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -44,8 +44,6 @@ namespace tunnel void EncryptECIES (std::shared_ptr& encryptor, const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx); }; - - void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state); class TunnelConfig { From abdf92c084e825008f5539ae7fcee9435fa7ee47 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Dec 2020 19:43:43 -0500 Subject: [PATCH 05/47] encrypt message for ECIES router --- libi2pd/Crypto.cpp | 38 ++++++++++------------- libi2pd/ECIESX25519AEADRatchetSession.cpp | 36 +++++++++++++++++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 8 +++-- libi2pd/Garlic.cpp | 2 +- 4 files changed, 55 insertions(+), 29 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 6055f888..68712fc7 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1333,26 +1333,31 @@ namespace crypto // new ck is m_CK[0:31], key is m_CK[32:63] } + static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck, + const uint8_t * hh, const uint8_t * pub) + { + // pub is Bob's public static key, hh = SHA256(h) + memcpy (state.m_CK, ck, 32); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + } + void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) { - // pub is Bob's public static key static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars static const uint8_t hh[32] = { 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 }; // hh = SHA256(protocol_name || 0) - memcpy (state.m_CK, protocolName, 32); // ck = protocol_name || 0 - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, pub, 32); - SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0 } - + void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) { - // pub is Bob's public static key static const uint8_t protocolNameHash[] = { 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, @@ -1363,17 +1368,11 @@ namespace crypto 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) - memcpy (state.m_CK, protocolNameHash, 32); - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, pub, 32); - SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + InitNoiseState (state, protocolNameHash, hh, pub); } void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) { - // pub is Bob's public static key static const uint8_t protocolNameHash[32] = { 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba, @@ -1384,12 +1383,7 @@ namespace crypto 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c }; // SHA256 (protocolNameHash) - memcpy (state.m_CK, protocolNameHash, 32); - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, pub, 32); - SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + InitNoiseState (state, protocolNameHash, hh, pub); } // init and terminate diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index b3b30a1b..042a318c 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -490,6 +490,31 @@ namespace garlic return true; } + bool ECIESX25519AEADRatchetSession::NewOutgoingMessageForRouter (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) + { + // we are Alice, router's bpk is m_RemoteStaticKey + i2p::crypto::InitNoiseNState (*this, m_RemoteStaticKey); + size_t offset = 0; + m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); + memcpy (out + offset, m_EphemeralKeys->GetPublicKey (), 32); + MixHash (out + offset, 32); // h = SHA256(h || aepk) + offset += 32; + uint8_t sharedSecret[32]; + m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) + MixKey (sharedSecret); + uint8_t nonce[12]; + memset (nonce, 0, 12); + // encrypt payload + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Payload for router AEAD encryption failed"); + return false; + } + + m_State = eSessionStateNewSessionSent; + return true; + } + bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Bob @@ -549,7 +574,7 @@ namespace garlic return true; } - + bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Bob and sent NSR already @@ -781,6 +806,11 @@ namespace garlic return nullptr; len += 96; break; + case eSessionStateForRouter: + if (!NewOutgoingMessageForRouter (payload.data (), payload.size (), buf, m->maxLen)) + return nullptr; + len += 48; + break; default: return nullptr; } @@ -791,9 +821,9 @@ namespace garlic return m; } - std::shared_ptr ECIESX25519AEADRatchetSession::WrapOneTimeMessage (std::shared_ptr msg) + std::shared_ptr ECIESX25519AEADRatchetSession::WrapOneTimeMessage (std::shared_ptr msg, bool isForRouter) { - m_State = eSessionStateOneTime; + m_State = isForRouter ? eSessionStateForRouter : eSessionStateOneTime; return WrapSingleMessage (msg); } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index e71d9782..1788eeb8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -140,7 +140,8 @@ namespace garlic eSessionStateNewSessionSent, eSessionStateNewSessionReplySent, eSessionStateEstablished, - eSessionStateOneTime + eSessionStateOneTime, + eSessionStateForRouter }; struct DHRatchet @@ -158,7 +159,7 @@ namespace garlic bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); - std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg); + std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg, bool isForRouter = false); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } @@ -192,7 +193,8 @@ namespace garlic bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); - + bool NewOutgoingMessageForRouter (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + std::vector CreatePayload (std::shared_ptr msg, bool first); size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len); size_t CreateLeaseSetClove (std::shared_ptr ls, uint64_t ts, uint8_t * buf, size_t len); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 2fe97156..1d228811 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -716,7 +716,7 @@ namespace garlic { auto session = std::make_shared(this, false); session->SetRemoteStaticKey (router->GetIdentity ()->GetEncryptionPublicKey ()); - return session->WrapOneTimeMessage (msg); + return session->WrapOneTimeMessage (msg, true); } else { From e2fcab34b71c182f94bed304588897fd46c0ab5f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Dec 2020 22:01:58 -0500 Subject: [PATCH 06/47] deccrypt and handle garlic message for ECIES router --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 24 ++++++++++++++++++++++- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + libi2pd/RouterContext.cpp | 17 +++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 042a318c..ecc7412f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -503,7 +503,7 @@ namespace garlic m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) MixKey (sharedSecret); uint8_t nonce[12]; - memset (nonce, 0, 12); + CreateNonce (0, nonce); // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt { @@ -770,6 +770,28 @@ namespace garlic return true; } + bool ECIESX25519AEADRatchetSession::HandleNextMessageForRouter (const uint8_t * buf, size_t len) + { + if (!GetOwner ()) return false; + // we are Bob + i2p::crypto::InitNoiseNState (*this, GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk + MixHash (buf, 32); + uint8_t sharedSecret[32]; + GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, aepk) + MixKey (sharedSecret); + buf += 32; len -= 32; + uint8_t nonce[12]; + CreateNonce (0, nonce); + std::vector payload (len - 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt + { + LogPrint (eLogWarning, "Garlic: Payload for router AEAD verification failed"); + return false; + } + HandlePayload (payload.data (), len - 16, nullptr, 0); + return true; + } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { auto payload = CreatePayload (msg, m_State != eSessionStateEstablished); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 1788eeb8..59be94c1 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -158,6 +158,7 @@ namespace garlic ~ECIESX25519AEADRatchetSession (); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); + bool HandleNextMessageForRouter (const uint8_t * buf, size_t len); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg, bool isForRouter = false); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 3c066532..5cfbd943 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -19,6 +19,7 @@ #include "version.h" #include "Log.h" #include "Family.h" +#include "ECIESX25519AEADRatchetSession.h" #include "RouterContext.h" namespace i2p @@ -672,7 +673,21 @@ namespace i2p void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) { std::unique_lock l(m_GarlicMutex); - i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); + if (IsECIES ()) + { + uint8_t * buf = msg->GetPayload (); + uint32_t len = bufbe32toh (buf); + if (len > msg->GetLength ()) + { + LogPrint (eLogWarning, "Router: garlic message length ", len, " exceeds I2NP message length ", msg->GetLength ()); + return; + } + buf += 4; + auto session = std::make_shared(this, false); + session->HandleNextMessageForRouter (buf, len); + } + else + i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); } void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) From 36473e388903b38b64364a30c72642096bfab386 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 4 Dec 2020 18:36:49 +0300 Subject: [PATCH 07/47] add naming to threads Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 2 ++ daemon/I2PControl.cpp | 2 ++ daemon/UPnP.cpp | 2 ++ libi2pd/Log.cpp | 2 ++ libi2pd/NTCP2.h | 1 - libi2pd/NetDb.cpp | 3 +++ libi2pd/SSU.cpp | 13 ++++++++++--- libi2pd/Timestamp.cpp | 2 ++ libi2pd/Transports.cpp | 5 +++++ libi2pd/Tunnel.cpp | 2 ++ libi2pd/util.cpp | 1 + libi2pd_client/AddressBook.cpp | 1 + libi2pd_client/I2PTunnel.cpp | 10 ++++++---- 13 files changed, 38 insertions(+), 8 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 9f420cf0..73849e4d 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -1312,6 +1313,7 @@ namespace http { void HTTPServer::Run () { + pthread_setname_np(pthread_self(), "Webconsole"); while (m_IsRunning) { try diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index e8c6e031..1fde9109 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "Crypto.h" #include "FS.h" @@ -131,6 +132,7 @@ namespace client void I2PControlService::Run () { + pthread_setname_np(pthread_self(), "I2PC"); while (m_IsRunning) { try { diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index 92a41011..0076ddd7 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -1,6 +1,7 @@ #ifdef USE_UPNP #include #include +#include #include #include @@ -60,6 +61,7 @@ namespace transport void UPnP::Run () { + pthread_setname_np(pthread_self(), "UPnP"); while (m_IsRunning) { try diff --git a/libi2pd/Log.cpp b/libi2pd/Log.cpp index a0014841..d7386642 100644 --- a/libi2pd/Log.cpp +++ b/libi2pd/Log.cpp @@ -7,6 +7,7 @@ */ #include "Log.h" +#include //for std::transform #include @@ -179,6 +180,7 @@ namespace log { void Log::Run () { + pthread_setname_np(pthread_self(), "Logging"); Reopen (); while (m_IsRunning) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 351f17b5..5c9ecac9 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e280e31b..66dac010 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "I2PEndian.h" #include "Base.h" @@ -88,6 +89,8 @@ namespace data void NetDb::Run () { + pthread_setname_np(pthread_self(), "NetDB"); + uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; while (m_IsRunning) { diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index d29f5cd7..a75306bb 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "Log.h" #include "Timestamp.h" #include "RouterContext.h" @@ -23,7 +24,7 @@ namespace transport { SSUServer::SSUServer (const boost::asio::ip::address & addr, int port): - m_OnlyV6(true), m_IsRunning(false), m_Thread (nullptr), + m_OnlyV6(true), m_IsRunning(false), m_Thread (nullptr), m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint), @@ -36,7 +37,7 @@ namespace transport SSUServer::SSUServer (int port): m_OnlyV6(false), m_IsRunning(false), m_Thread (nullptr), - m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), + m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6), @@ -100,7 +101,7 @@ namespace transport if (context.SupportsV6 ()) { m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this)); - if (!m_Thread) + if (!m_Thread) m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this)); ScheduleTerminationV6 (); @@ -142,6 +143,8 @@ namespace transport void SSUServer::Run () { + pthread_setname_np(pthread_self(), "SSU"); + while (m_IsRunning) { try @@ -157,6 +160,8 @@ namespace transport void SSUServer::RunReceivers () { + pthread_setname_np(pthread_self(), "SSUv4"); + while (m_IsRunning) { try @@ -179,6 +184,8 @@ namespace transport void SSUServer::RunReceiversV6 () { + pthread_setname_np(pthread_self(), "SSUv6"); + while (m_IsRunning) { try diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 0490350e..db5c3946 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "Config.h" #include "Log.h" #include "I2PEndian.h" @@ -148,6 +149,7 @@ namespace util void NTPTimeSync::Run () { + pthread_setname_np(pthread_self(), "Timesync"); while (m_IsRunning) { try diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index c6e90ad2..585ef8e0 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -6,6 +6,7 @@ * See full license text in LICENSE file at top of project tree */ +#include #include "Log.h" #include "Crypto.h" #include "RouterContext.h" @@ -59,6 +60,8 @@ namespace transport template void EphemeralKeysSupplier::Run () { + pthread_setname_np(pthread_self(), "Ephemerals"); + while (m_IsRunning) { int num, total = 0; @@ -272,6 +275,8 @@ namespace transport void Transports::Run () { + pthread_setname_np(pthread_self(), "Transports"); + while (m_IsRunning && m_Service) { try diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index ad918787..a5f20963 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -10,6 +10,7 @@ #include "I2PEndian.h" #include #include +#include #include #include #include "Crypto.h" @@ -472,6 +473,7 @@ namespace tunnel void Tunnels::Run () { + pthread_setname_np(pthread_self(), "Tunnels"); std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready uint64_t lastTs = 0, lastPoolsTs = 0; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 24814ad3..e98f939f 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -94,6 +94,7 @@ namespace util void RunnableService::Run () { + pthread_setname_np(pthread_self(), m_Name.c_str()); while (m_IsRunning) { try diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index d695b8eb..6ecbddaf 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -748,6 +748,7 @@ namespace client void AddressBookSubscription::CheckUpdates () { + pthread_setname_np(pthread_self(), "Addressbook"); bool result = MakeRequest (); m_Book.DownloadComplete (result, m_Ident, m_Etag, m_LastModified); } diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 081294c6..18b7c5a0 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "Base.h" #include "Log.h" #include "Destination.h" @@ -862,7 +863,7 @@ namespace client std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); dgram->SetRawReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); } void I2PUDPClientTunnel::Start() { @@ -891,11 +892,11 @@ namespace client } auto remotePort = m_RecvEndpoint.port(); if (!m_LastPort || m_LastPort != remotePort) - { + { auto itr = m_Sessions.find(remotePort); - if (itr != m_Sessions.end()) + if (itr != m_Sessions.end()) m_LastSession = itr->second; - else + else { m_LastSession = std::make_shared(boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0); m_Sessions.emplace (remotePort, m_LastSession); @@ -941,6 +942,7 @@ namespace client void I2PUDPClientTunnel::TryResolving() { LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); + pthread_setname_np(pthread_self(), "UDP Resolver"); std::shared_ptr addr; while(!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) From a843165cb49661d0d134eab013d09b781ab99dd5 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Dec 2020 19:15:06 -0500 Subject: [PATCH 08/47] try ratchets tag first --- libi2pd/Garlic.cpp | 73 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 1d228811..9c008bc0 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -485,42 +485,43 @@ namespace garlic } auto mod = length & 0x0f; // %16 buf += 4; // length - auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16 - // AES tag might be used even if encryption type is not ElGamal/AES - if (it != m_Tags.end ()) - { - // tag found. Use AES - auto decryption = it->second; - m_Tags.erase (it); // tag might be used only once - if (length >= 32) - { - uint8_t iv[32]; // IV is first 16 bytes - SHA256(buf, 32, iv); - decryption->SetIV (iv); - decryption->Decrypt (buf + 32, length - 32, buf + 32); - HandleAESBlock (buf + 32, length - 32, decryption, msg->from); - } - else - LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes"); - } - else - { - bool found = false; - if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) - { - // try ECIESx25519 tag - uint64_t tag; - memcpy (&tag, buf, 8); - auto it1 = m_ECIESx25519Tags.find (tag); - if (it1 != m_ECIESx25519Tags.end ()) - { - found = true; - if (!it1->second.tagset->HandleNextMessage (buf, length, it1->second.index)) - LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); - m_ECIESx25519Tags.erase (it1); - } - } + bool found = false; + if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + { + // try ECIESx25519 tag + uint64_t tag; + memcpy (&tag, buf, 8); + auto it1 = m_ECIESx25519Tags.find (tag); + if (it1 != m_ECIESx25519Tags.end ()) + { + found = true; + if (!it1->second.tagset->HandleNextMessage (buf, length, it1->second.index)) + LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); + m_ECIESx25519Tags.erase (it1); + } + } + if (!found) + { + auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16 + // AES tag might be used even if encryption type is not ElGamal/AES + if (it != m_Tags.end ()) // try AES tag + { + // tag found. Use AES + auto decryption = it->second; + m_Tags.erase (it); // tag might be used only once + if (length >= 32) + { + uint8_t iv[32]; // IV is first 16 bytes + SHA256(buf, 32, iv); + decryption->SetIV (iv); + decryption->Decrypt (buf + 32, length - 32, buf + 32); + HandleAESBlock (buf + 32, length - 32, decryption, msg->from); + found = true; + } + else + LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes"); + } if (!found) // assume new session { // AES tag not found. Handle depending on encryption type @@ -545,7 +546,7 @@ namespace garlic } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); - } + } } } From aace200899a26c840f320794d30e8327fee17ad4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 5 Dec 2020 08:26:21 -0500 Subject: [PATCH 09/47] don't create paired zero hops tunnel --- libi2pd/TunnelPool.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 87413c3f..94462c93 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -235,7 +235,7 @@ namespace tunnel for (const auto& it : m_InboundTunnels) if (it->IsEstablished ()) num++; } - if (!num && !m_OutboundTunnels.empty ()) + if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0) { for (auto it: m_OutboundTunnels) { @@ -559,7 +559,7 @@ namespace tunnel { config = std::make_shared(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()); } - if(m_NumOutboundHops == 0 || config) + if (!m_NumOutboundHops || config) { auto newTunnel = tunnels.CreateOutboundTunnel (config); newTunnel->SetTunnelPool (shared_from_this ()); @@ -574,8 +574,12 @@ namespace tunnel void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr outboundTunnel) { LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel..."); - auto tunnel = tunnels.CreateInboundTunnel (std::make_shared(outboundTunnel->GetInvertedPeers ()), outboundTunnel); + auto tunnel = tunnels.CreateInboundTunnel ( + m_NumOutboundHops > 0 ? std::make_shared(outboundTunnel->GetInvertedPeers ()) : nullptr, + outboundTunnel); tunnel->SetTunnelPool (shared_from_this ()); + if (tunnel->IsEstablished ()) // zero hops + TunnelCreated (tunnel); } void TunnelPool::SetCustomPeerSelector(ITunnelPeerSelector * selector) From 3100d4f90224094608215bba049f52e81e4e75da Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 7 Dec 2020 06:22:16 +0300 Subject: [PATCH 10/47] move thread naming to util Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 4 ++-- daemon/I2PControl.cpp | 4 ++-- daemon/UPnP.cpp | 4 ++-- libi2pd/Log.cpp | 5 +++-- libi2pd/NetDb.cpp | 12 +++++------ libi2pd/SSU.cpp | 8 ++++---- libi2pd/Timestamp.cpp | 5 +++-- libi2pd/Transports.cpp | 6 +++--- libi2pd/Tunnel.cpp | 4 ++-- libi2pd/util.cpp | 40 +++++++++++++++++++++++++++--------- libi2pd/util.h | 6 ++++-- libi2pd_client/I2PTunnel.cpp | 4 ++-- 12 files changed, 63 insertions(+), 39 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 73849e4d..25b6ab19 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -1313,7 +1312,8 @@ namespace http { void HTTPServer::Run () { - pthread_setname_np(pthread_self(), "Webconsole"); + i2p::util::SetThreadName("Webconsole"); + while (m_IsRunning) { try diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 1fde9109..3f0033e5 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "Crypto.h" #include "FS.h" @@ -132,7 +131,8 @@ namespace client void I2PControlService::Run () { - pthread_setname_np(pthread_self(), "I2PC"); + i2p::util::SetThreadName("I2PC"); + while (m_IsRunning) { try { diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index 0076ddd7..6ea33c46 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -1,7 +1,6 @@ #ifdef USE_UPNP #include #include -#include #include #include @@ -61,7 +60,8 @@ namespace transport void UPnP::Run () { - pthread_setname_np(pthread_self(), "UPnP"); + i2p::util::SetThreadName("UPnP"); + while (m_IsRunning) { try diff --git a/libi2pd/Log.cpp b/libi2pd/Log.cpp index d7386642..2b555663 100644 --- a/libi2pd/Log.cpp +++ b/libi2pd/Log.cpp @@ -7,7 +7,7 @@ */ #include "Log.h" -#include +#include "util.h" //for std::transform #include @@ -180,7 +180,8 @@ namespace log { void Log::Run () { - pthread_setname_np(pthread_self(), "Logging"); + i2p::util::SetThreadName("Logging"); + Reopen (); while (m_IsRunning) { diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 66dac010..20b54376 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include "I2PEndian.h" #include "Base.h" @@ -27,6 +26,7 @@ #include "ECIESX25519AEADRatchetSession.h" #include "Config.h" #include "NetDb.hpp" +#include "util.h" using namespace i2p::transport; @@ -89,7 +89,7 @@ namespace data void NetDb::Run () { - pthread_setname_np(pthread_self(), "NetDB"); + i2p::util::SetThreadName("NetDB"); uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; while (m_IsRunning) @@ -116,7 +116,7 @@ namespace data break; case eI2NPDeliveryStatus: HandleDeliveryStatusMsg (msg); - break; + break; case eI2NPDummyMsg: // plain RouterInfo from NTCP2 with flags for now HandleNTCP2RouterInfoMsg (msg); @@ -158,12 +158,12 @@ namespace data if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) { bool publish = false; - if (m_PublishReplyToken) - { + if (m_PublishReplyToken) + { if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true; } else if (i2p::context.GetLastUpdateTime () > lastPublish || - ts - lastPublish >= NETDB_PUBLISH_INTERVAL) publish = true; + ts - lastPublish >= NETDB_PUBLISH_INTERVAL) publish = true; if (publish) // update timestamp and publish { i2p::context.UpdateTimestamp (ts); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index a75306bb..3b6280dd 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -7,12 +7,12 @@ */ #include -#include #include "Log.h" #include "Timestamp.h" #include "RouterContext.h" #include "NetDb.hpp" #include "SSU.h" +#include "util.h" #ifdef _WIN32 #include @@ -143,7 +143,7 @@ namespace transport void SSUServer::Run () { - pthread_setname_np(pthread_self(), "SSU"); + i2p::util::SetThreadName("SSU"); while (m_IsRunning) { @@ -160,7 +160,7 @@ namespace transport void SSUServer::RunReceivers () { - pthread_setname_np(pthread_self(), "SSUv4"); + i2p::util::SetThreadName("SSUv4"); while (m_IsRunning) { @@ -184,7 +184,7 @@ namespace transport void SSUServer::RunReceiversV6 () { - pthread_setname_np(pthread_self(), "SSUv6"); + i2p::util::SetThreadName("SSUv6"); while (m_IsRunning) { diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index db5c3946..3cd336ed 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -14,11 +14,11 @@ #include #include #include -#include #include "Config.h" #include "Log.h" #include "I2PEndian.h" #include "Timestamp.h" +#include "util.h" #ifdef _WIN32 #ifndef _WIN64 @@ -149,7 +149,8 @@ namespace util void NTPTimeSync::Run () { - pthread_setname_np(pthread_self(), "Timesync"); + i2p::util::SetThreadName("Timesync"); + while (m_IsRunning) { try diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 585ef8e0..5c2fcb6d 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -6,7 +6,6 @@ * See full license text in LICENSE file at top of project tree */ -#include #include "Log.h" #include "Crypto.h" #include "RouterContext.h" @@ -15,6 +14,7 @@ #include "Transports.h" #include "Config.h" #include "HTTP.h" +#include "util.h" using namespace i2p::data; @@ -60,7 +60,7 @@ namespace transport template void EphemeralKeysSupplier::Run () { - pthread_setname_np(pthread_self(), "Ephemerals"); + i2p::util::SetThreadName("Ephemerals"); while (m_IsRunning) { @@ -275,7 +275,7 @@ namespace transport void Transports::Run () { - pthread_setname_np(pthread_self(), "Transports"); + i2p::util::SetThreadName("Transports"); while (m_IsRunning && m_Service) { diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index a5f20963..42eeeb5d 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -10,7 +10,6 @@ #include "I2PEndian.h" #include #include -#include #include #include #include "Crypto.h" @@ -23,6 +22,7 @@ #include "Config.h" #include "Tunnel.h" #include "TunnelPool.h" +#include "util.h" namespace i2p { @@ -473,7 +473,7 @@ namespace tunnel void Tunnels::Run () { - pthread_setname_np(pthread_self(), "Tunnels"); + i2p::util::SetThreadName("Tunnels"); std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready uint64_t lastTs = 0, lastPoolsTs = 0; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index e98f939f..2e8e67ba 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -13,6 +13,15 @@ #include "util.h" #include "Log.h" +#if not defined (__FreeBSD__) +#include +#endif + +#if defined(__OpenBSD__) || defined(__FreeBSD__) +#include +#endif + + #ifdef _WIN32 #include #include @@ -32,7 +41,7 @@ // inet_pton exists Windows since Vista, but XP doesn't have that function! // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found -int inet_pton_xp(int af, const char *src, void *dst) +int inet_pton_xp (int af, const char *src, void *dst) { struct sockaddr_storage ss; int size = sizeof (ss); @@ -94,7 +103,8 @@ namespace util void RunnableService::Run () { - pthread_setname_np(pthread_self(), m_Name.c_str()); + SetThreadName(m_Name.c_str()); + while (m_IsRunning) { try @@ -108,10 +118,20 @@ namespace util } } + void SetThreadName (const char *name) { +#if defined (__APPLE__) + pthread_setname_np(name); +#elif defined(__FreeBSD__) + pthread_set_name_np(pthread_self(), name) +#else + pthread_setname_np(pthread_self(), name); +#endif + } + namespace net { #ifdef _WIN32 - bool IsWindowsXPorLater() + bool IsWindowsXPorLater () { static bool isRequested = false; static bool isXP = false; @@ -130,7 +150,7 @@ namespace net return isXP; } - int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback) + int GetMTUWindowsIpv4 (sockaddr_in inputAddress, int fallback) { ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; @@ -184,7 +204,7 @@ namespace net return fallback; } - int GetMTUWindowsIpv6(sockaddr_in6 inputAddress, int fallback) + int GetMTUWindowsIpv6 (sockaddr_in6 inputAddress, int fallback) { ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; @@ -249,7 +269,7 @@ namespace net return fallback; } - int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback) + int GetMTUWindows (const boost::asio::ip::address& localAddress, int fallback) { #ifdef UNICODE string localAddress_temporary = localAddress.to_string(); @@ -281,7 +301,7 @@ namespace net } } #else // assume unix - int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback) + int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback) { ifaddrs* ifaddr, *ifa = nullptr; if(getifaddrs(&ifaddr) == -1) @@ -336,7 +356,7 @@ namespace net } #endif // _WIN32 - int GetMTU(const boost::asio::ip::address& localAddress) + int GetMTU (const boost::asio::ip::address& localAddress) { int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU @@ -348,7 +368,7 @@ namespace net return fallback; } - const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6) + const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6) { #ifdef _WIN32 LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32"); @@ -396,7 +416,7 @@ namespace net #endif } - bool IsInReservedRange(const boost::asio::ip::address& host) { + bool IsInReservedRange (const boost::asio::ip::address& host) { // https://en.wikipedia.org/wiki/Reserved_IP_addresses if(host.is_v4()) { diff --git a/libi2pd/util.h b/libi2pd/util.h index 56ce1e08..f6222b9f 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -168,11 +168,13 @@ namespace util boost::asio::io_service::work m_Work; }; + void SetThreadName (const char *name); + namespace net { int GetMTU (const boost::asio::ip::address& localAddress); - const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6=false); - bool IsInReservedRange(const boost::asio::ip::address& host); + const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false); + bool IsInReservedRange (const boost::asio::ip::address& host); } } } diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 18b7c5a0..61c42b24 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -7,12 +7,12 @@ */ #include -#include #include "Base.h" #include "Log.h" #include "Destination.h" #include "ClientContext.h" #include "I2PTunnel.h" +#include "util.h" namespace i2p { @@ -941,8 +941,8 @@ namespace client } void I2PUDPClientTunnel::TryResolving() { + i2p::util::SetThreadName("UDP Resolver"); LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); - pthread_setname_np(pthread_self(), "UDP Resolver"); std::shared_ptr addr; while(!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) From 9a2c6a76197ebf6531acb6b4d5cf7d7d955b3695 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 7 Dec 2020 06:31:46 +0300 Subject: [PATCH 11/47] move thread naming to util Signed-off-by: R4SAS --- libi2pd_client/AddressBook.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 6ecbddaf..a69bd660 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -748,7 +748,8 @@ namespace client void AddressBookSubscription::CheckUpdates () { - pthread_setname_np(pthread_self(), "Addressbook"); + i2p::util::SetThreadName("Addressbook"); + bool result = MakeRequest (); m_Book.DownloadComplete (result, m_Ident, m_Etag, m_LastModified); } From ac67cd7f9adf9a8ac36faaab876883fc7526ceb8 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 7 Dec 2020 08:36:06 +0300 Subject: [PATCH 12/47] add FreeBSD builder for GHA (#1595) --- .github/workflows/build-freebsd.yml | 20 ++++++++++++++++++++ libi2pd/util.cpp | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-freebsd.yml diff --git a/.github/workflows/build-freebsd.yml b/.github/workflows/build-freebsd.yml new file mode 100644 index 00000000..dbc4028c --- /dev/null +++ b/.github/workflows/build-freebsd.yml @@ -0,0 +1,20 @@ +name: Build on FreeBSD + +on: [push, pull_request] + +jobs: + build: + runs-on: macos-latest + name: with UPnP + steps: + - uses: actions/checkout@v2 + - name: Test in FreeBSD + id: test + uses: vmactions/freebsd-vm@v0.0.9 + with: + usesh: true + prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc + run: | + cd build + cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release . + gmake -j2 diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 2e8e67ba..e763a848 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -122,7 +122,7 @@ namespace util #if defined (__APPLE__) pthread_setname_np(name); #elif defined(__FreeBSD__) - pthread_set_name_np(pthread_self(), name) + pthread_set_name_np(pthread_self(), name); #else pthread_setname_np(pthread_self(), name); #endif From bfc3acb83469df640882d5cb3d02c2f26e044c11 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 7 Dec 2020 19:47:50 +0300 Subject: [PATCH 13/47] use correct function for thread naming on OpenBSD Signed-off-by: R4SAS --- libi2pd/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index e763a848..794a3f14 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -121,7 +121,7 @@ namespace util void SetThreadName (const char *name) { #if defined (__APPLE__) pthread_setname_np(name); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #else pthread_setname_np(pthread_self(), name); From ba79b94e0680c71f47200fc0b0b227a780730705 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Dec 2020 15:16:40 -0500 Subject: [PATCH 14/47] try to generate missing ECIESx25519 tag in last tagset --- libi2pd/Garlic.cpp | 35 +++++++++++++++++++++++++++++------ libi2pd/Garlic.h | 3 ++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 9c008bc0..2d08f339 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -487,17 +487,19 @@ namespace garlic buf += 4; // length bool found = false; + uint64_t tag; if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { - // try ECIESx25519 tag - uint64_t tag; + // try ECIESx25519 tag memcpy (&tag, buf, 8); auto it1 = m_ECIESx25519Tags.find (tag); if (it1 != m_ECIESx25519Tags.end ()) { found = true; - if (!it1->second.tagset->HandleNextMessage (buf, length, it1->second.index)) - LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); + if (it1->second.tagset->HandleNextMessage (buf, length, it1->second.index)) + m_LastTagset = it1->second.tagset; + else + LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); m_ECIESx25519Tags.erase (it1); } } @@ -542,7 +544,25 @@ namespace garlic // otherwise ECIESx25519 auto session = std::make_shared (this, false); // incoming if (!session->HandleNextMessage (buf, length, nullptr, 0)) - LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); + { + // try to gererate more tags for last tagset + if (m_LastTagset) + { + for (int i = 0; i < ECIESX25519_MAX_NUM_GENERATED_TAGS; i++) + { + LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); + if (AddECIESx25519SessionNextTag (m_LastTagset) == tag) + { + if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[tag].index)) + found = true; + break; + } + } + if (!found) m_LastTagset = nullptr; + } + if (!found) + LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); + } } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); @@ -845,6 +865,8 @@ namespace garlic } if (numExpiredTags > 0) LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ()); + if (m_LastTagset && m_LastTagset->IsExpired (ts)) + m_LastTagset = nullptr; } void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) @@ -1030,11 +1052,12 @@ namespace garlic } } - void GarlicDestination::AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset) + uint64_t GarlicDestination::AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset) { auto index = tagset->GetNextIndex (); uint64_t tag = tagset->GetNextSessionTag (); m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset}); + return tag; } void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 8df830c7..379477e8 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -245,7 +245,7 @@ namespace garlic void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); - void AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset); + uint64_t AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void RemoveECIESx25519Session (const uint8_t * staticKey); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); @@ -285,6 +285,7 @@ namespace garlic int m_NumRatchetInboundTags; std::unordered_map, std::hash > > m_Tags; std::unordered_map m_ECIESx25519Tags; // session tag -> session + RatchetTagSetPtr m_LastTagset; // tagset last message came for // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::unordered_map m_DeliveryStatusSessions; // msgID -> session From ca3b8191510c1006d031d02c50edcf6b4f6a6e8f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 10 Dec 2020 18:32:41 +0300 Subject: [PATCH 15/47] [avx] check ig c++ target supports AVX Signed-off-by: R4SAS --- libi2pd/Crypto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 68712fc7..3e6279ff 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -638,7 +638,7 @@ namespace crypto { uint64_t buf[256]; uint64_t hash[12]; // 96 bytes -#if defined(__x86_64__) || defined(__i386__) +#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600) if(i2p::cpu::avx) { __asm__ From 7373dae026e50f2cb3754bbd4b108b4a90291c85 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 12 Dec 2020 09:54:07 +0300 Subject: [PATCH 16/47] [avx] check if c++ target supports AVX (closes #1600) Signed-off-by: R4SAS --- libi2pd/Identity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 89f6cda0..9dfaa1fc 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -828,7 +828,7 @@ namespace data XORMetric operator^(const IdentHash& key1, const IdentHash& key2) { XORMetric m; -#if defined(__x86_64__) || defined(__i386__) +#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600) if(i2p::cpu::avx) { __asm__ From c91a8711e358fcf0970876d07e75d0eb9506c473 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 12 Dec 2020 17:14:58 -0500 Subject: [PATCH 17/47] encrypted requests to ECIES floodfills --- libi2pd/Destination.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 44180ae5..8f3b495a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -559,9 +559,7 @@ namespace client m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); - auto msg = i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound); - if (floodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented - msg = WrapMessageForRouter (floodfill, msg); + auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); @@ -755,10 +753,8 @@ namespace client AddECIESx25519Key (replyKey, replyTag); else AddSessionKey (replyKey, replyTag); - - auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES); - if (nextFloodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented - msg = WrapMessageForRouter (nextFloodfill, msg); + auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, + request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); request->outboundTunnel->SendTunnelDataMsg ( { i2p::tunnel::TunnelMessageBlock From fc2dc9a0199bf1983673ead4adde19b6ec1c9dec Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 12 Dec 2020 21:40:07 -0500 Subject: [PATCH 18/47] cumulative ACK bitfields --- libi2pd/SSUData.cpp | 35 +++++++++++++++++++---------------- libi2pd/SSUData.h | 6 ++++-- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/libi2pd/SSUData.cpp b/libi2pd/SSUData.cpp index 4e0e712f..5458cc97 100644 --- a/libi2pd/SSUData.cpp +++ b/libi2pd/SSUData.cpp @@ -185,7 +185,12 @@ namespace transport std::unique_ptr(new IncompleteMessage (msg)))).first; } std::unique_ptr& incompleteMessage = it->second; - + // mark fragment as received + if (fragmentNum < 64) + incompleteMessage->receivedFragmentsBits |= (0x01 << fragmentNum); + else + LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64"); + // handle current fragment if (fragmentNum == incompleteMessage->nextFragmentNum) { @@ -220,7 +225,7 @@ namespace transport // missing fragment LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast); - if (incompleteMessage->savedFragments.insert (std::unique_ptr(savedFragment)).second) + if (incompleteMessage->savedFragments.insert (std::unique_ptr(savedFragment)).second) incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); else LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); @@ -266,7 +271,7 @@ namespace transport } } else - SendFragmentAck (msgID, fragmentNum); + SendFragmentAck (msgID, incompleteMessage->receivedFragmentsBits); buf += fragmentSize; } } @@ -394,13 +399,9 @@ namespace transport m_Session.Send (buf, 48); } - void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum) + void SSUData::SendFragmentAck (uint32_t msgID, uint64_t bits) { - if (fragmentNum > 64) - { - LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64"); - return; - } + if (!bits) return; uint8_t buf[64 + 18] = {0}; uint8_t * payload = buf + sizeof (SSUHeader); *payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag @@ -410,14 +411,16 @@ namespace transport // one ack *(uint32_t *)(payload) = htobe32 (msgID); // msgID payload += 4; - div_t d = div (fragmentNum, 7); - memset (payload, 0x80, d.quot); // 0x80 means non-last - payload += d.quot; - *payload = 0x01 << d.rem; // set corresponding bit - payload++; + size_t len = 0; + while (bits) + { + *payload = (bits & 0x7F); // next 7 bits + bits >>= 7; + if (bits) *payload &= 0x80; // 0x80 means non-last + payload++; len++; + } *payload = 0; // number of fragments - - size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1) + len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4 // encrypt message with session key m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len); m_Session.Send (buf, len); diff --git a/libi2pd/SSUData.h b/libi2pd/SSUData.h index 2e606053..902c009a 100644 --- a/libi2pd/SSUData.h +++ b/libi2pd/SSUData.h @@ -75,9 +75,11 @@ namespace transport std::shared_ptr msg; int nextFragmentNum; uint32_t lastFragmentInsertTime; // in seconds + uint64_t receivedFragmentsBits; std::set, FragmentCmp> savedFragments; - IncompleteMessage (std::shared_ptr m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; + IncompleteMessage (std::shared_ptr m): msg (m), nextFragmentNum (0), + lastFragmentInsertTime (0), receivedFragmentsBits (0) {}; void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); }; @@ -109,7 +111,7 @@ namespace transport private: void SendMsgAck (uint32_t msgID); - void SendFragmentAck (uint32_t msgID, int fragmentNum); + void SendFragmentAck (uint32_t msgID, uint64_t bits); void ProcessAcks (uint8_t *& buf, uint8_t flag); void ProcessFragments (uint8_t * buf); void ProcessSentMessageAck (uint32_t msgID); From 31f0c350771a431710002dfffb9e94d38d913fa9 Mon Sep 17 00:00:00 2001 From: gxcreator Date: Sun, 13 Dec 2020 17:22:59 +0000 Subject: [PATCH 19/47] Docker: Move DEFAULT_ARGS to Dockerfile . --- contrib/docker/Dockerfile | 1 + contrib/docker/entrypoint.sh | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index be3feea7..adb7ba75 100644 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -11,6 +11,7 @@ ENV REPO_URL=${REPO_URL} ENV I2PD_HOME="/home/i2pd" ENV DATA_DIR="${I2PD_HOME}/data" +ENV DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --http.enabled=true --http.address=0.0.0.0 --httpproxy.enabled=true --httpproxy.address=0.0.0.0 --socksproxy.enabled=true --socksproxy.address=0.0.0.0 --sam.enabled=true --sam.address=0.0.0.0" RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \ && adduser -S -h "$I2PD_HOME" i2pd \ diff --git a/contrib/docker/entrypoint.sh b/contrib/docker/entrypoint.sh index ca9dddd4..ce897e3c 100644 --- a/contrib/docker/entrypoint.sh +++ b/contrib/docker/entrypoint.sh @@ -2,7 +2,6 @@ COMMAND=/usr/local/bin/i2pd # To make ports exposeable # Note: $DATA_DIR is defined in /etc/profile -DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --http.enabled=true --http.address=0.0.0.0 --httpproxy.enabled=true --httpproxy.address=0.0.0.0 --socksproxy.enabled=true --socksproxy.address=0.0.0.0 --sam.enabled=true --sam.address=0.0.0.0" if [ "$1" = "--help" ]; then set -- $COMMAND --help From 65945b3462a5d52dfb0b235dd4dacaea73ee30f6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 13 Dec 2020 21:55:51 -0500 Subject: [PATCH 20/47] correct offline signature size for close packet --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 05b34d9e..f6bf7e8b 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -701,7 +701,7 @@ namespace stream size++; // resend delay htobe16buf (packet + size, PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED); size += 2; // flags - size_t signatureLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetSignatureLen (); + size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen (); htobe16buf (packet + size, signatureLen); // signature only size += 2; // options size uint8_t * signature = packet + size; From bf91e16b5d7e0d922c96f95a519c8033ce790b65 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Dec 2020 15:04:20 -0500 Subject: [PATCH 21/47] gererate specified number of tags if misssing tag --- libi2pd/Garlic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 2d08f339..02ded2f4 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -548,7 +548,8 @@ namespace garlic // try to gererate more tags for last tagset if (m_LastTagset) { - for (int i = 0; i < ECIESX25519_MAX_NUM_GENERATED_TAGS; i++) + auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); + for (int i = 0; i < maxTags; i++) { LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); if (AddECIESx25519SessionNextTag (m_LastTagset) == tag) From 06a7e181cd6a44cf09aeb5046a446e821673c1f9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Dec 2020 16:06:32 -0500 Subject: [PATCH 22/47] ECIES for new routers --- libi2pd/RouterContext.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 5cfbd943..d258b341 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -52,7 +52,8 @@ namespace i2p void RouterContext::CreateNewRouter () { - m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); + m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, + i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); SaveKeys (); NewRouterInfo (); } @@ -590,7 +591,8 @@ namespace i2p // update keys LogPrint (eLogInfo, "Router: router keys are obsolete. Creating new"); oldIdentity = m_Keys.GetPublic (); - m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); + m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, + i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); SaveKeys (); } // read NTCP2 keys if available From 082c4f1104b64ede18f4524e3e75977ca35e1819 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 17 Dec 2020 22:17:05 +0800 Subject: [PATCH 23/47] qt: added about box --- qt/i2pd_qt/AboutDialog.cpp | 23 ++++ qt/i2pd_qt/AboutDialog.h | 22 ++++ qt/i2pd_qt/AboutDialog.ui | 194 +++++++++++++++++++++++++++++ qt/i2pd_qt/BuildDateTimeQt.h | 7 ++ qt/i2pd_qt/i2pd_qt.pro | 21 +++- qt/i2pd_qt/mainwindow.cpp | 44 ++++++- qt/i2pd_qt/mainwindow.h | 1 + qt/i2pd_qt/mainwindow.ui | 67 +++++++--- qt/i2pd_qt/routercommandswidget.ui | 4 +- 9 files changed, 353 insertions(+), 30 deletions(-) create mode 100644 qt/i2pd_qt/AboutDialog.cpp create mode 100644 qt/i2pd_qt/AboutDialog.h create mode 100644 qt/i2pd_qt/AboutDialog.ui create mode 100644 qt/i2pd_qt/BuildDateTimeQt.h diff --git a/qt/i2pd_qt/AboutDialog.cpp b/qt/i2pd_qt/AboutDialog.cpp new file mode 100644 index 00000000..2428c2da --- /dev/null +++ b/qt/i2pd_qt/AboutDialog.cpp @@ -0,0 +1,23 @@ +#include "AboutDialog.h" +#include "ui_AboutDialog.h" +#include +#include "version.h" +#include "BuildDateTimeQt.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + qDebug() << "AboutDialog::AboutDialog()" << endl; + ui->setupUi(this); + ui->i2pdVersionLabel->setText(I2PD_VERSION); + ui->i2pVersionLabel->setText(I2P_VERSION); + ui->buildDateTimeLabel->setText(BUILD_DATE_TIME_QT); + ui->vcsCommitInfoLabel->setText(VCS_COMMIT_INFO); +} + +AboutDialog::~AboutDialog() +{ + qDebug() << "AboutDialog::~AboutDialog()" << endl; + delete ui; +} diff --git a/qt/i2pd_qt/AboutDialog.h b/qt/i2pd_qt/AboutDialog.h new file mode 100644 index 00000000..d462de28 --- /dev/null +++ b/qt/i2pd_qt/AboutDialog.h @@ -0,0 +1,22 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_H diff --git a/qt/i2pd_qt/AboutDialog.ui b/qt/i2pd_qt/AboutDialog.ui new file mode 100644 index 00000000..6e662706 --- /dev/null +++ b/qt/i2pd_qt/AboutDialog.ui @@ -0,0 +1,194 @@ + + + AboutDialog + + + Qt::WindowModal + + + + 0 + 0 + 400 + 199 + + + + About i2pd_qt + + + + :/icons/mask:/icons/mask + + + + + 10 + 160 + 381 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + 10 + 10 + 381 + 17 + + + + <html><head/><body><p><span style=" font-weight:600;">About i2pd_qt</span></p></body></html> + + + + + + 10 + 40 + 131 + 17 + + + + i2pd Version: + + + + + + 10 + 70 + 131 + 17 + + + + Build Date/Time: + + + + + + 150 + 40 + 241 + 20 + + + + I2PD_VERSION_LABEL + + + + + + 10 + 130 + 131 + 17 + + + + I2P Version: + + + + + + 150 + 130 + 241 + 17 + + + + I2P_VERSION_LABEL + + + + + + 150 + 70 + 241 + 20 + + + + BUILD_DATE_TIME_LABEL + + + + + + 10 + 100 + 131 + 17 + + + + Version Control: + + + + + + 150 + 100 + 241 + 17 + + + + VCS_COMMIT_INFO_LABEL + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/qt/i2pd_qt/BuildDateTimeQt.h b/qt/i2pd_qt/BuildDateTimeQt.h new file mode 100644 index 00000000..139e2083 --- /dev/null +++ b/qt/i2pd_qt/BuildDateTimeQt.h @@ -0,0 +1,7 @@ +#ifndef BUILDDATETIMEQT_H +#define BUILDDATETIMEQT_H + +#include +const QString BUILD_DATE_TIME_QT = QStringLiteral(__DATE__ " " __TIME__); + +#endif // BUILDDATETIMEQT_H diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 004b6273..a572e454 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -36,7 +36,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../daemon/HTTPServer.cpp \ ../../daemon/I2PControl.cpp \ ../../daemon/i2pd.cpp \ - ../../daemon/UPnP.cpp + ../../daemon/UPnP.cpp \ + AboutDialog.cpp HEADERS += DaemonQT.h mainwindow.h \ ClientTunnelPane.h \ @@ -59,8 +60,9 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../daemon/Daemon.h \ ../../daemon/HTTPServer.h \ ../../daemon/I2PControl.h \ - ../../daemon/UPnP.h - + ../../daemon/UPnP.h \ + AboutDialog.h \ + BuildDateTimeQt.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client @@ -71,7 +73,8 @@ FORMS += mainwindow.ui \ tunnelform.ui \ statusbuttons.ui \ routercommandswidget.ui \ - generalsettingswidget.ui + generalsettingswidget.ui \ + AboutDialog.ui LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz @@ -86,6 +89,16 @@ i2pd.depends = FORCE cleani2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean cleani2pd.depends = clean +BuildDateTimeQtTarget.target = BuildDateTimeQt.h +BuildDateTimeQtTarget.depends = FORCE +# 'touch' is unix-only; will probably break on non-unix, TBD +BuildDateTimeQtTarget.commands = touch $$PWD/BuildDateTimeQt.h +PRE_TARGETDEPS += BuildDateTimeQt.h +QMAKE_EXTRA_TARGETS += BuildDateTimeQtTarget + +# git only, port to other VCS, too. TBD +DEFINES += VCS_COMMIT_INFO="\\\"git:$(shell git -C \""$$_PRO_FILE_PWD_"\" describe)\\\"" + PRE_TARGETDEPS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a QMAKE_EXTRA_TARGETS += cleani2pd i2pd libi2pd CLEAN_DEPS += cleani2pd diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 89178ee0..925992a5 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1,4 +1,5 @@ #include "mainwindow.h" +#include "AboutDialog.h" #include "ui_mainwindow.h" #include "ui_statusbuttons.h" #include "ui_routercommandswidget.h" @@ -8,6 +9,13 @@ #include #include #include + +#include +#include +#include +#include +#include + #include "RouterContext.h" #include "Config.h" #include "FS.h" @@ -65,6 +73,10 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren statusButtonsUI->setupUi(ui->statusButtonsPane); routerCommandsUI->setupUi(routerCommandsParent); uiSettings->setupUi(ui->settingsContents); + + ui->aboutHrefLabel->setText("

" + "i2pd_qt
Version " I2PD_VERSION " · About...

"); + routerCommandsParent->hide(); ui->verticalLayout_2->addWidget(routerCommandsParent); //,statusHtmlUI(new Ui::StatusHtmlPaneForm) @@ -76,15 +88,16 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren setWindowTitle(QApplication::translate("AppTitle","I2PD")); //TODO handle resizes and change the below into resize() call - setFixedHeight(550); - ui->centralWidget->setFixedHeight(550); + constexpr auto WINDOW_HEIGHT = 610; + setFixedHeight(WINDOW_HEIGHT); + ui->centralWidget->setFixedHeight(WINDOW_HEIGHT); onResize(); ui->stackedWidget->setCurrentIndex(0); ui->settingsScrollArea->resize(uiSettings->settingsContentsQVBoxLayout->sizeHint().width()+10,380); //QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar(); - int w = 683; - int h = 4550; + constexpr auto w = 683; + constexpr auto h = 4550; ui->settingsContents->setFixedSize(w, h); ui->settingsContents->setGeometry(QRect(0,0,w,h)); @@ -143,6 +156,8 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit())); QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit())); + QObject::connect(ui->aboutHrefLabel, SIGNAL(linkActivated(const QString &)), this, SLOT(showAboutBox(const QString &))); + QObject::connect(ui->logViewerPushButton, SIGNAL(released()), this, SLOT(showLogViewerPage())); QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); @@ -400,6 +415,27 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){ } wasSelectingAtStatusMainPage=false; } + +void MainWindow::showAboutBox(const QString & href) { + qDebug() << "MainWindow::showAboutBox(), href:" << href << endl; + AboutDialog dialog(this); + + if (!QGuiApplication::styleHints()->showIsFullScreen() && !QGuiApplication::styleHints()->showIsMaximized()) { + const QWindow * windowHandle = dialog.windowHandle(); + qDebug()<<"AboutDialog windowHandle ptr: "<<(size_t)windowHandle<screen():nullptr; //Qt 5.14+: dialog.screen() + qDebug()<<"AboutDialog screen ptr: "<<(size_t)screen<availableGeometry(); + //dialog.resize(availableGeometry.width() / 3, availableGeometry.height() * 2 / 3); + dialog.move((availableGeometry.width() - dialog.width()) / 2, + (availableGeometry.height() - dialog.height()) / 2); + } + } + //dialog.show(); + (void) dialog.exec(); +} + void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 77c8826b..2114155b 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -442,6 +442,7 @@ public slots: void showTunnelsPage(); void showRestartPage(); void showQuitPage(); + void showAboutBox(const QString & href); private: StatusPage statusPage; diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index dcdf88bd..8f942b08 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 908 - 554 + 604 @@ -35,13 +35,13 @@ 908 - 550 + 600 908 - 550 + 600 @@ -50,7 +50,7 @@ 10 10 888 - 531 + 596 @@ -58,7 +58,7 @@ QLayout::SetMaximumSize - + QLayout::SetMinimumSize @@ -67,7 +67,7 @@ 0 0 170 - 496 + 596 @@ -172,6 +172,33 @@ + + + + + 9 + + + + Qt::NoContextMenu + + + Show app name, version and build date + + + <html><head/><body><p><a href="about:i2pd_qt"><span style="text-decoration: none; color:#a0a0a0;"><span style="font-weight: 500;">i2pd_qt</span><br/>Version SHORT_VERSION · About...</span></a></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 6 + + + 0 + + + @@ -629,7 +656,7 @@ - 713 + 707 713 @@ -648,8 +675,8 @@ 0 0 - 713 - 531 + 707 + 586 @@ -690,8 +717,8 @@ 0 0 - 711 - 531 + 707 + 586 @@ -753,8 +780,8 @@ 0 0 - 711 - 531 + 707 + 586 @@ -798,8 +825,8 @@ 0 0 - 81 - 28 + 693 + 498 @@ -820,8 +847,8 @@ 0 0 - 711 - 531 + 707 + 586 @@ -903,8 +930,8 @@ 0 0 - 711 - 531 + 707 + 586 @@ -958,7 +985,7 @@ 0 0 - 711 + 707 531 diff --git a/qt/i2pd_qt/routercommandswidget.ui b/qt/i2pd_qt/routercommandswidget.ui index c5098e8e..f95db1fd 100644 --- a/qt/i2pd_qt/routercommandswidget.ui +++ b/qt/i2pd_qt/routercommandswidget.ui @@ -6,7 +6,7 @@ 0 0 - 711 + 707 300 @@ -24,7 +24,7 @@ 0 0 - 711 + 707 301 From 776dc7ec5277d436631fbfff917b60c2c27a4d72 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 17 Dec 2020 22:30:14 +0800 Subject: [PATCH 24/47] qt: about box fixed for older qt5 --- qt/i2pd_qt/mainwindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 925992a5..48484349 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -420,6 +420,8 @@ void MainWindow::showAboutBox(const QString & href) { qDebug() << "MainWindow::showAboutBox(), href:" << href << endl; AboutDialog dialog(this); + /* + //doesn't work on older qt5: ‘class QStyleHints’ has no member named ‘showIsMaximized’ if (!QGuiApplication::styleHints()->showIsFullScreen() && !QGuiApplication::styleHints()->showIsMaximized()) { const QWindow * windowHandle = dialog.windowHandle(); qDebug()<<"AboutDialog windowHandle ptr: "<<(size_t)windowHandle< Date: Thu, 17 Dec 2020 22:45:10 +0800 Subject: [PATCH 25/47] qt: removed a few debug log lines --- qt/i2pd_qt/AboutDialog.cpp | 2 -- qt/i2pd_qt/mainwindow.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/qt/i2pd_qt/AboutDialog.cpp b/qt/i2pd_qt/AboutDialog.cpp index 2428c2da..ac92694a 100644 --- a/qt/i2pd_qt/AboutDialog.cpp +++ b/qt/i2pd_qt/AboutDialog.cpp @@ -8,7 +8,6 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) { - qDebug() << "AboutDialog::AboutDialog()" << endl; ui->setupUi(this); ui->i2pdVersionLabel->setText(I2PD_VERSION); ui->i2pVersionLabel->setText(I2P_VERSION); @@ -18,6 +17,5 @@ AboutDialog::AboutDialog(QWidget *parent) : AboutDialog::~AboutDialog() { - qDebug() << "AboutDialog::~AboutDialog()" << endl; delete ui; } diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 48484349..70975fb2 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -417,7 +417,6 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){ } void MainWindow::showAboutBox(const QString & href) { - qDebug() << "MainWindow::showAboutBox(), href:" << href << endl; AboutDialog dialog(this); /* From d3bf8c2417a34a6dbe29d85ba82d026e51e596f8 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 17 Dec 2020 23:15:56 +0800 Subject: [PATCH 26/47] data: ignored *.tmp.xml --- qt/i2pd_qt/data/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 qt/i2pd_qt/data/.gitignore diff --git a/qt/i2pd_qt/data/.gitignore b/qt/i2pd_qt/data/.gitignore new file mode 100644 index 00000000..dde94bce --- /dev/null +++ b/qt/i2pd_qt/data/.gitignore @@ -0,0 +1,2 @@ +*.tmp.xml + From ccc604c0f4604bf18082f2effe5b2e9174980f37 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 01:13:50 +0800 Subject: [PATCH 27/47] qt: fixes #1180 --- qt/i2pd_qt/ClientTunnelPane.h | 7 +++ qt/i2pd_qt/I2pdQtUtil.cpp | 12 ++++ qt/i2pd_qt/I2pdQtUtil.h | 9 +++ qt/i2pd_qt/ServerTunnelPane.h | 11 ++++ qt/i2pd_qt/TunnelPane.cpp | 8 ++- qt/i2pd_qt/TunnelPane.h | 17 ++++++ qt/i2pd_qt/i2pd_qt.pro | 6 +- qt/i2pd_qt/mainwindow.cpp | 47 +++++++++++----- qt/i2pd_qt/mainwindow.h | 103 ++++++++++++++++++++-------------- 9 files changed, 161 insertions(+), 59 deletions(-) create mode 100644 qt/i2pd_qt/I2pdQtUtil.cpp create mode 100644 qt/i2pd_qt/I2pdQtUtil.h diff --git a/qt/i2pd_qt/ClientTunnelPane.h b/qt/i2pd_qt/ClientTunnelPane.h index 80d331de..f6bf4376 100644 --- a/qt/i2pd_qt/ClientTunnelPane.h +++ b/qt/i2pd_qt/ClientTunnelPane.h @@ -79,6 +79,13 @@ protected: ClientTunnelConfig* ctc=tunnelConfig->asClientTunnelConfig(); assert(ctc!=nullptr); + if(!isValidSingleLine(destinationLineEdit))return false; + if(!isValidSingleLine(portLineEdit))return false; + if(!isValidSingleLine(cryptoTypeLineEdit))return false; + if(!isValidSingleLine(keysLineEdit))return false; + if(!isValidSingleLine(addressLineEdit))return false; + if(!isValidSingleLine(destinationPortLineEdit))return false; + //destination ctc->setdest(destinationLineEdit->text().toStdString()); diff --git a/qt/i2pd_qt/I2pdQtUtil.cpp b/qt/i2pd_qt/I2pdQtUtil.cpp new file mode 100644 index 00000000..35a7adff --- /dev/null +++ b/qt/i2pd_qt/I2pdQtUtil.cpp @@ -0,0 +1,12 @@ +#include "I2pdQtUtil.h" + +bool isValidSingleLine(QLineEdit* widget, WrongInputPageEnum inputPage, MainWindow* mainWindow) { + bool correct = !widget->text().contains(QRegularExpression("[\r\n]"), nullptr); + if(!correct) { + mainWindow->highlightWrongInput( + QApplication::tr("Single line input expected, but it's multiline"), + inputPage, + widget); + } + return correct; +} diff --git a/qt/i2pd_qt/I2pdQtUtil.h b/qt/i2pd_qt/I2pdQtUtil.h new file mode 100644 index 00000000..90c3e521 --- /dev/null +++ b/qt/i2pd_qt/I2pdQtUtil.h @@ -0,0 +1,9 @@ +#ifndef I2pdQtUtil_H +#define I2pdQtUtil_H + +class QLineEdit; +#include "mainwindow.h" + +bool isValidSingleLine(QLineEdit* widget, WrongInputPageEnum inputPage, MainWindow* mainWindow); + +#endif // I2pdQtUtil_H diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h index 92ee4da5..de844249 100644 --- a/qt/i2pd_qt/ServerTunnelPane.h +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -124,6 +124,17 @@ protected: if(!ok)return false; ServerTunnelConfig* stc=tunnelConfig->asServerTunnelConfig(); assert(stc!=nullptr); + + if(!isValidSingleLine(hostLineEdit))return false; + if(!isValidSingleLine(portLineEdit))return false; + if(!isValidSingleLine(cryptoTypeLineEdit))return false; + if(!isValidSingleLine(keysLineEdit))return false; + if(!isValidSingleLine(inPortLineEdit))return false; + if(!isValidSingleLine(accessListLineEdit))return false; + if(!isValidSingleLine(hostOverrideLineEdit))return false; + if(!isValidSingleLine(webIRCPassLineEdit))return false; + if(!isValidSingleLine(addressLineEdit))return false; + stc->sethost(hostLineEdit->text().toStdString()); auto portStr=portLineEdit->text(); diff --git a/qt/i2pd_qt/TunnelPane.cpp b/qt/i2pd_qt/TunnelPane.cpp index 4b873ac1..7e15a6a6 100644 --- a/qt/i2pd_qt/TunnelPane.cpp +++ b/qt/i2pd_qt/TunnelPane.cpp @@ -4,6 +4,8 @@ #include "mainwindow.h" #include "ui_mainwindow.h" +#include "I2pdQtUtil.h" + TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_): QObject(), mainWindow(mainWindow_), @@ -47,8 +49,6 @@ void TunnelPane::setupTunnelPane( nameLineEdit->setText(tunnelName); setGroupBoxTitle(tunnelName); - QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString &)), - this, SLOT(setGroupBoxTitle(const QString &))); QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(updated())); @@ -399,3 +399,7 @@ void TunnelPane::hideWrongInputLabel() const { wrongInputPane->setVisible(false); mainWindow->adjustSizesAccordingToWrongLabel(); } + +bool TunnelPane::isValidSingleLine(QLineEdit* widget) { + return ::isValidSingleLine(widget, WrongInputPageEnum::tunnelsSettingsPage, mainWindow); +} diff --git a/qt/i2pd_qt/TunnelPane.h b/qt/i2pd_qt/TunnelPane.h index 59303afd..ac21181a 100644 --- a/qt/i2pd_qt/TunnelPane.h +++ b/qt/i2pd_qt/TunnelPane.h @@ -119,6 +119,21 @@ protected: public: //returns false when invalid data at UI virtual bool applyDataFromUIToTunnelConfig() { + if(!isValidSingleLine(nameLineEdit)){ + setGroupBoxTitle(QApplication::translate("tunPage", "invalid_tunnel_name")); + return false; + } + if(!isValidSingleLine(inbound_lengthLineEdit))return false; + if(!isValidSingleLine(inbound_quantityLineEdit))return false; + if(!isValidSingleLine(outbound_lengthLineEdit))return false; + if(!isValidSingleLine(outbound_quantityLineEdit))return false; + if(!isValidSingleLine(crypto_tagsToSendLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetAuthTypeLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetEncTypeLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetPrivKeyLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetTypeLineEdit))return false; + if(!isValidSingleLine(i2p_streaming_initialAckDelayLineEdit))return false; + setGroupBoxTitle(nameLineEdit->text()); tunnelConfig->setName(nameLineEdit->text().toStdString()); tunnelConfig->setType(readTunnelTypeComboboxData()); I2CPParameters& i2cpParams=tunnelConfig->getI2cpParameters(); @@ -169,6 +184,8 @@ private: i2cp_leaseSetPrivKeyLabel->setText(QApplication::translate("tunForm", "Decryption key for encrypted LeaseSet in base64. PSK or private DH:", 0)); i2cp_leaseSetAuthTypeLabel->setText(QApplication::translate("tunForm", "Auth type for encrypted LeaseSet. 0 - no auth, 1 - DH, 2 - PSK:", 0)); } +protected: + bool isValidSingleLine(QLineEdit* widget); }; #endif // TUNNELPANE_H diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index a572e454..c4e55f53 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -37,7 +37,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../daemon/I2PControl.cpp \ ../../daemon/i2pd.cpp \ ../../daemon/UPnP.cpp \ - AboutDialog.cpp + AboutDialog.cpp \ + I2pdQtUtil.cpp HEADERS += DaemonQT.h mainwindow.h \ ClientTunnelPane.h \ @@ -62,7 +63,8 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../daemon/I2PControl.h \ ../../daemon/UPnP.h \ AboutDialog.h \ - BuildDateTimeQt.h + BuildDateTimeQt.h \ + I2pdQtUtil.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 70975fb2..de2c9fb8 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1,4 +1,5 @@ #include "mainwindow.h" +#include "I2pdQtUtil.h" #include "AboutDialog.h" #include "ui_mainwindow.h" #include "ui_statusbuttons.h" @@ -16,6 +17,8 @@ #include #include +#include + #include "RouterContext.h" #include "Config.h" #include "FS.h" @@ -37,6 +40,7 @@ #include "DelayedSaveManagerImpl.h" #include "SaverImpl.h" + std::string programOptionsWriterCurrentSection; MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *parent) : @@ -647,13 +651,13 @@ MainWindow::~MainWindow() FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton){ FileChooserItem* retVal; - retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton); + retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this); MainWindowItem* super=retVal; configItems.append(super); return retVal; } void MainWindow::initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton){ - configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton)); + configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton, this)); } /*void MainWindow::initCombobox(ConfigOption option, QComboBox* comboBox){ configItems.append(new ComboBoxItem(option, comboBox)); @@ -669,25 +673,25 @@ void MainWindow::initSignatureTypeCombobox(ConfigOption option, QComboBox* combo configItems.append(new SignatureTypeComboBoxItem(option, comboBox)); } void MainWindow::initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated){ - configItems.append(new IPAddressStringItem(option, addressLineEdit, fieldNameTranslated)); + configItems.append(new IPAddressStringItem(option, addressLineEdit, fieldNameTranslated, this)); } void MainWindow::initTCPPortBox(ConfigOption option, QLineEdit* portLineEdit, QString fieldNameTranslated){ - configItems.append(new TCPPortStringItem(option, portLineEdit, fieldNameTranslated)); + configItems.append(new TCPPortStringItem(option, portLineEdit, fieldNameTranslated, this)); } void MainWindow::initCheckBox(ConfigOption option, QCheckBox* checkBox) { configItems.append(new CheckBoxItem(option, checkBox)); } void MainWindow::initIntegerBox(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ - configItems.append(new IntegerStringItem(option, numberLineEdit, fieldNameTranslated)); + configItems.append(new IntegerStringItem(option, numberLineEdit, fieldNameTranslated, this)); } void MainWindow::initUInt32Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ - configItems.append(new UInt32StringItem(option, numberLineEdit, fieldNameTranslated)); + configItems.append(new UInt32StringItem(option, numberLineEdit, fieldNameTranslated, this)); } void MainWindow::initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ - configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated)); + configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated, this)); } void MainWindow::initStringBox(ConfigOption option, QLineEdit* lineEdit){ - configItems.append(new BaseStringItem(option, lineEdit, QString())); + configItems.append(new BaseStringItem(option, lineEdit, QString(), this)); } NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) { NonGUIOptionItem * retValue; @@ -789,12 +793,17 @@ bool MainWindow::saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocu for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { MainWindowItem* item = *it; - if(!item->isValid()){ - highlightWrongInput(QApplication::tr("Invalid value for")+" "+item->getConfigOption().section+"::"+item->getConfigOption().option+". "+item->getRequirementToBeValid()+" "+cannotSaveSettings, item->getWidgetToFocus()); + bool alreadyDisplayedIfWrong=false; + if(!item->isValid(alreadyDisplayedIfWrong)){ + if(!alreadyDisplayedIfWrong) + highlightWrongInput( + QApplication::tr("Invalid value for")+" "+item->getConfigOption().section+"::"+item->getConfigOption().option+". "+item->getRequirementToBeValid()+" "+cannotSaveSettings, + WrongInputPageEnum::generalSettingsPage, + item->getWidgetToFocus()); return false; } } - delayedSaveManagerPtr->delayedSave(++dataSerial, focusOnTunnel, tunnelNameToFocus); + delayedSaveManagerPtr->delayedSave(++dataSerial, focusOnTunnel, tunnelNameToFocus);//TODO does dataSerial work? //FIXME //onLoggingOptionsChange(); return true; @@ -814,6 +823,11 @@ void FolderChooserItem::pushButtonReleased() { void BaseStringItem::installListeners(MainWindow *mainWindow) { QObject::connect(lineEdit, SIGNAL(textChanged(const QString &)), mainWindow, SLOT(updated())); } +bool BaseStringItem::isValid(bool & alreadyDisplayedIfWrong) { + alreadyDisplayedIfWrong=true; + return ::isValidSingleLine(lineEdit, WrongInputPageEnum::generalSettingsPage, mainWindow); +} + void ComboBoxItem::installListeners(MainWindow *mainWindow) { QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), mainWindow, SLOT(updated())); } @@ -825,7 +839,8 @@ void MainWindow::updated() { ui->wrongInputLabel->setVisible(false); adjustSizesAccordingToWrongLabel(); - applyTunnelsUiToConfigs(); + bool correct = applyTunnelsUiToConfigs(); + if(!correct) return; saveAllConfigs(false); } @@ -1010,11 +1025,15 @@ void MainWindow::adjustSizesAccordingToWrongLabel() { } } -void MainWindow::highlightWrongInput(QString warningText, QWidget* widgetToFocus) { +void MainWindow::highlightWrongInput(QString warningText, WrongInputPageEnum inputPage, QWidget* widgetToFocus) { bool redVisible = ui->wrongInputLabel->isVisible(); ui->wrongInputLabel->setVisible(true); ui->wrongInputLabel->setText(warningText); if(!redVisible)adjustSizesAccordingToWrongLabel(); if(widgetToFocus){ui->settingsScrollArea->ensureWidgetVisible(widgetToFocus);widgetToFocus->setFocus();} - showSettingsPage(); + switch(inputPage) { + case WrongInputPageEnum::generalSettingsPage: showSettingsPage(); break; + case WrongInputPageEnum::tunnelsSettingsPage: showTunnelsPage(); break; + default: assert(false); break; + } } diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 2114155b..34228e43 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -1,6 +1,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +enum WrongInputPageEnum { generalSettingsPage, tunnelsSettingsPage }; + #include #include #include @@ -66,6 +68,8 @@ #include "DelayedSaveManagerImpl.h" #include "SaverImpl.h" +#include "I2pdQtUtil.h" + class SaverImpl; class LogViewerManager; @@ -155,19 +159,24 @@ public: }else out << boost::any_cast(optionValue); //let it throw out << "\n\n"; } - virtual bool isValid(){return true;} + virtual bool isValid(bool & alreadyDisplayedIfWrong){alreadyDisplayedIfWrong=false;return true;} }; class NonGUIOptionItem : public MainWindowItem { public: - NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {}; + NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {} virtual ~NonGUIOptionItem(){} - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } }; class BaseStringItem : public MainWindowItem { Q_OBJECT public: QLineEdit* lineEdit; - BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_) : MainWindowItem(option_, lineEdit_, requirementToBeValid_), lineEdit(lineEdit_){}; + MainWindow *mainWindow; + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_, MainWindow* mainWindow_): + MainWindowItem(option_, lineEdit_, requirementToBeValid_), + lineEdit(lineEdit_), + mainWindow(mainWindow_) + {}; virtual ~BaseStringItem(){} virtual void installListeners(MainWindow *mainWindow); virtual QString toString(){ @@ -183,13 +192,13 @@ public: optionValue=fromString(lineEdit->text()); MainWindowItem::saveToStringStream(out); } - virtual bool isValid() { return true; } + virtual bool isValid(bool & alreadyDisplayedIfWrong); }; class FileOrFolderChooserItem : public BaseStringItem { public: QPushButton* browsePushButton; - FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : - BaseStringItem(option_, lineEdit_, QString()), browsePushButton(browsePushButton_) {} + FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : + BaseStringItem(option_, lineEdit_, QString(), mw), browsePushButton(browsePushButton_) {} virtual ~FileOrFolderChooserItem(){} }; class FileChooserItem : public FileOrFolderChooserItem { @@ -197,8 +206,8 @@ class FileChooserItem : public FileOrFolderChooserItem { private slots: void pushButtonReleased(); public: - FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_) { + FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; @@ -207,20 +216,20 @@ class FolderChooserItem : public FileOrFolderChooserItem{ private slots: void pushButtonReleased(); public: - FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_) { + FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; class ComboBoxItem : public MainWindowItem { public: QComboBox* comboBox; - ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){}; + ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){} virtual ~ComboBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption()=0; virtual void saveToStringStream(std::stringstream& out)=0; - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return ; } }; class LogDestinationComboBoxItem : public ComboBoxItem { public: @@ -237,13 +246,13 @@ public: optionValue=logDest; MainWindowItem::saveToStringStream(out); } - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } Q_OBJECT }; class LogLevelComboBoxItem : public ComboBoxItem { public: - LogLevelComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + LogLevelComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {} virtual ~LogLevelComboBoxItem(){} virtual void loadFromConfigOption(){ MainWindowItem::loadFromConfigOption(); @@ -254,11 +263,11 @@ public: optionValue=comboBox->currentText().toStdString(); MainWindowItem::saveToStringStream(out); } - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } }; class SignatureTypeComboBoxItem : public ComboBoxItem { public: - SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {} virtual ~SignatureTypeComboBoxItem(){} virtual void loadFromConfigOption(){ MainWindowItem::loadFromConfigOption(); @@ -271,12 +280,12 @@ public: optionValue=(unsigned short)selected; MainWindowItem::saveToStringStream(out); } - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } }; class CheckBoxItem : public MainWindowItem { public: QCheckBox* checkBox; - CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){}; + CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){} virtual ~CheckBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption(){ @@ -288,22 +297,25 @@ public: optionValue=checkBox->isChecked(); MainWindowItem::saveToStringStream(out); } - virtual bool isValid() { return true; } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } }; class BaseFormattedStringItem : public BaseStringItem { public: QString fieldNameTranslated; - BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_) : - BaseStringItem(option_, lineEdit_, requirementToBeValid_), fieldNameTranslated(fieldNameTranslated_) {}; + BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_, MainWindow* mw) : + BaseStringItem(option_, lineEdit_, requirementToBeValid_, mw), fieldNameTranslated(fieldNameTranslated_) {} virtual ~BaseFormattedStringItem(){} - virtual bool isValid()=0; + //virtual bool isValid(bool & alreadyDisplayedIfWrong)=0; }; class IntegerStringItem : public BaseFormattedStringItem { public: - IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer.")) {}; + IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer."), mw) {} virtual ~IntegerStringItem(){} - virtual bool isValid(){ + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; auto str=lineEdit->text(); bool ok; str.toInt(&ok); @@ -314,10 +326,13 @@ public: }; class UShortStringItem : public BaseFormattedStringItem { public: - UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer.")) {}; + UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer."), mw) {} virtual ~UShortStringItem(){} - virtual bool isValid(){ + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; auto str=lineEdit->text(); bool ok; str.toUShort(&ok); @@ -328,10 +343,13 @@ public: }; class UInt32StringItem : public BaseFormattedStringItem { public: - UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer.")) {}; + UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer."), mw) {} virtual ~UInt32StringItem(){} - virtual bool isValid(){ + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; auto str=lineEdit->text(); bool ok; str.toUInt(&ok); @@ -342,10 +360,13 @@ public: }; class UInt16StringItem : public BaseFormattedStringItem { public: - UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer.")) {}; + UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer."), mw) {} virtual ~UInt16StringItem(){} - virtual bool isValid(){ + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; auto str=lineEdit->text(); bool ok; str.toUShort(&ok); @@ -356,14 +377,14 @@ public: }; class IPAddressStringItem : public BaseFormattedStringItem { public: - IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address")) {}; - virtual bool isValid(){return true;}//todo + IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address"), mw) {} + //virtual bool isValid(bool & alreadyDisplayedIfWrong){return true;}//todo }; class TCPPortStringItem : public UShortStringItem { public: - TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - UShortStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + UShortStringItem(option_, lineEdit_, fieldNameTranslated_,mw) {} }; namespace Ui { @@ -395,7 +416,7 @@ public: void setI2PController(i2p::qt::Controller* controller_); - void highlightWrongInput(QString warningText, QWidget* widgetToFocus); + void highlightWrongInput(QString warningText, WrongInputPageEnum inputPage, QWidget* widgetToFocus); //typedef std::function DefaultValueGetter; From ca78601ada535f222198838f4d59c62bc8a8f95d Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 02:00:57 +0800 Subject: [PATCH 28/47] qt: visual fixes --- qt/i2pd_qt/mainwindow.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index de2c9fb8..3d0dc551 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -997,30 +997,33 @@ void MainWindow::backClickedFromChild() { } void MainWindow::adjustSizesAccordingToWrongLabel() { + constexpr auto HEIGHT = 581; + constexpr auto WIDTH = 707; if(ui->wrongInputLabel->isVisible()) { int dh = ui->wrongInputLabel->height()+ui->verticalLayout_7->layout()->spacing(); ui->verticalLayout_7->invalidate(); ui->wrongInputLabel->adjustSize(); ui->stackedWidget->adjustSize(); - ui->stackedWidget->setFixedHeight(531-dh); - ui->settingsPage->setFixedHeight(531-dh); - ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, 711, 531-dh)); - ui->stackedWidget->setFixedHeight(531-dh); - ui->settingsScrollArea->setFixedHeight(531-dh-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + const auto height = HEIGHT - dh; + ui->stackedWidget->setFixedHeight(height); + ui->settingsPage->setFixedHeight(height); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, WIDTH, height)); + ui->stackedWidget->setFixedHeight(height); + ui->settingsScrollArea->setFixedHeight(height-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); - ui->tunnelsScrollArea->setFixedHeight(531-dh-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsScrollArea->setFixedHeight(height-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); }else{ ui->verticalLayout_7->invalidate(); ui->wrongInputLabel->adjustSize(); ui->stackedWidget->adjustSize(); - ui->stackedWidget->setFixedHeight(531); - ui->settingsPage->setFixedHeight(531); - ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, 711, 531)); - ui->stackedWidget->setFixedHeight(531); - ui->settingsScrollArea->setFixedHeight(531-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + ui->stackedWidget->setFixedHeight(HEIGHT); + ui->settingsPage->setFixedHeight(HEIGHT); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, WIDTH, HEIGHT)); + ui->stackedWidget->setFixedHeight(HEIGHT); + ui->settingsScrollArea->setFixedHeight(HEIGHT-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); - ui->tunnelsScrollArea->setFixedHeight(531-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsScrollArea->setFixedHeight(HEIGHT-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); } } From 9c6e3ff1d774948c77e31478742a6f4096235f0d Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 03:39:08 +0800 Subject: [PATCH 29/47] qt: fixes #1582 --- qt/i2pd_qt/generalsettingswidget.ui | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qt/i2pd_qt/generalsettingswidget.ui b/qt/i2pd_qt/generalsettingswidget.ui index 7a35c0a5..e81d6f1e 100644 --- a/qt/i2pd_qt/generalsettingswidget.ui +++ b/qt/i2pd_qt/generalsettingswidget.ui @@ -495,6 +495,11 @@ QGroupBox::title { + + + None + + Error From 669fb62a541cbd28b60b095824de12a0f7237ad7 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 05:37:01 +0800 Subject: [PATCH 30/47] qt: fixed great ui pains with tunnels editing --- qt/i2pd_qt/DelayedSaveManager.h | 6 ++++-- qt/i2pd_qt/DelayedSaveManagerImpl.cpp | 28 +++++++++++++-------------- qt/i2pd_qt/DelayedSaveManagerImpl.h | 24 ++++++++++++----------- qt/i2pd_qt/I2pdQtTypes.h | 7 +++++++ qt/i2pd_qt/Saver.h | 7 +++++-- qt/i2pd_qt/SaverImpl.cpp | 10 ++++++---- qt/i2pd_qt/SaverImpl.h | 2 +- qt/i2pd_qt/i2pd_qt.pro | 3 ++- qt/i2pd_qt/mainwindow.cpp | 16 ++++++++------- qt/i2pd_qt/mainwindow.h | 18 ++++++++--------- 10 files changed, 68 insertions(+), 53 deletions(-) create mode 100644 qt/i2pd_qt/I2pdQtTypes.h diff --git a/qt/i2pd_qt/DelayedSaveManager.h b/qt/i2pd_qt/DelayedSaveManager.h index b09aa28f..23821439 100644 --- a/qt/i2pd_qt/DelayedSaveManager.h +++ b/qt/i2pd_qt/DelayedSaveManager.h @@ -2,6 +2,7 @@ #define DELAYEDSAVEMANAGER_H #include "Saver.h" +#include "I2pdQtTypes.h" class DelayedSaveManager { @@ -12,13 +13,14 @@ public: typedef unsigned int DATA_SERIAL_TYPE; - virtual void delayedSave(DATA_SERIAL_TYPE dataSerial, bool needsTunnelFocus, std::string tunnelNameToFocus)=0; + virtual void delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus)=0; //returns false iff save failed virtual bool appExiting()=0; - virtual bool needsFocusOnTunnel()=0; + virtual FocusEnum getFocusOn()=0; virtual std::string& getTunnelNameToFocus()=0; + virtual QWidget* getWidgetToFocus()=0; }; #endif // DELAYEDSAVEMANAGER_H diff --git a/qt/i2pd_qt/DelayedSaveManagerImpl.cpp b/qt/i2pd_qt/DelayedSaveManagerImpl.cpp index f6704c17..b0c7c4d2 100644 --- a/qt/i2pd_qt/DelayedSaveManagerImpl.cpp +++ b/qt/i2pd_qt/DelayedSaveManagerImpl.cpp @@ -1,6 +1,7 @@ #include "DelayedSaveManagerImpl.h" DelayedSaveManagerImpl::DelayedSaveManagerImpl() : + widgetToFocus(nullptr), saver(nullptr), lastDataSerialSeen(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL), lastSaveStartedTimestamp(A_VERY_OBSOLETE_TIMESTAMP), @@ -21,10 +22,12 @@ bool DelayedSaveManagerImpl::isSaverValid() { return saver != nullptr; } -void DelayedSaveManagerImpl::delayedSave(DATA_SERIAL_TYPE dataSerial, bool focusOnTunnel, std::string tunnelNameToFocus_) { +void DelayedSaveManagerImpl::delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus) { if(lastDataSerialSeen==dataSerial)return; - this->focusOnTunnel = focusOnTunnel; - tunnelNameToFocus = tunnelNameToFocus_; + this->reloadAfterSave = reloadAfterSave; + this->focusOn = focusOn; + this->tunnelNameToFocus = tunnelNameToFocus; + this->widgetToFocus = widgetToFocus; lastDataSerialSeen=dataSerial; assert(isSaverValid()); TIMESTAMP_TYPE now = getTime(); @@ -42,7 +45,7 @@ bool DelayedSaveManagerImpl::appExiting() { exiting=true; thread->wakeThreadAndJoinThread(); assert(isSaverValid()); - saver->save(false, ""); + saver->save(false, FocusEnum::noFocus); return true; } @@ -71,9 +74,10 @@ void DelayedSaveThread::run() { assert(saver!=nullptr); if(saveNow) { saveNow = false; - const bool focusOnTunnel = delayedSaveManagerImpl->needsFocusOnTunnel(); + const FocusEnum focusOn = delayedSaveManagerImpl->getFocusOn(); const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus(); - saver->save(focusOnTunnel, tunnelNameToFocus); + QWidget* widgetToFocus = delayedSaveManagerImpl->getWidgetToFocus(); + saver->save(delayedSaveManagerImpl->isReloadAfterSave(), focusOn, tunnelNameToFocus, widgetToFocus); continue; } if(defer) { @@ -87,9 +91,10 @@ void DelayedSaveThread::run() { if(delayedSaveManagerImpl->isExiting())return; continue; } - const bool focusOnTunnel = delayedSaveManagerImpl->needsFocusOnTunnel(); + const FocusEnum focusOn = delayedSaveManagerImpl->getFocusOn(); const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus(); - saver->save(focusOnTunnel, tunnelNameToFocus); + QWidget* widgetToFocus = delayedSaveManagerImpl->getWidgetToFocus(); + saver->save(delayedSaveManagerImpl->isReloadAfterSave(), focusOn, tunnelNameToFocus, widgetToFocus); break; //break inner loop } } @@ -131,10 +136,3 @@ Saver* DelayedSaveManagerImpl::getSaver() { return saver; } -bool DelayedSaveManagerImpl::needsFocusOnTunnel() { - return focusOnTunnel; -} - -std::string& DelayedSaveManagerImpl::getTunnelNameToFocus() { - return tunnelNameToFocus; -} diff --git a/qt/i2pd_qt/DelayedSaveManagerImpl.h b/qt/i2pd_qt/DelayedSaveManagerImpl.h index cb1f7568..c9a77c31 100644 --- a/qt/i2pd_qt/DelayedSaveManagerImpl.h +++ b/qt/i2pd_qt/DelayedSaveManagerImpl.h @@ -7,14 +7,14 @@ #include #include -#include "mainwindow.h" +#include "I2pdQtTypes.h" #include "DelayedSaveManager.h" #include "Saver.h" class DelayedSaveManagerImpl; +class Saver; -class DelayedSaveThread : public QThread -{ +class DelayedSaveThread : public QThread { Q_OBJECT public: @@ -42,14 +42,17 @@ private: volatile TIMESTAMP_TYPE wakeTime; }; -class DelayedSaveManagerImpl : public DelayedSaveManager -{ +class DelayedSaveManagerImpl : public DelayedSaveManager { + FocusEnum focusOn; + std::string tunnelNameToFocus; + QWidget* widgetToFocus; + bool reloadAfterSave; public: DelayedSaveManagerImpl(); virtual ~DelayedSaveManagerImpl(); virtual void setSaver(Saver* saver); virtual void start(); - virtual void delayedSave(DATA_SERIAL_TYPE dataSerial, bool focusOnTunnel, std::string tunnelNameToFocus); + virtual void delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus); virtual bool appExiting(); typedef DelayedSaveThread::TIMESTAMP_TYPE TIMESTAMP_TYPE; @@ -59,8 +62,10 @@ public: Saver* getSaver(); static TIMESTAMP_TYPE getTime(); - bool needsFocusOnTunnel(); - std::string& getTunnelNameToFocus(); + bool isReloadAfterSave() { return reloadAfterSave; } + FocusEnum getFocusOn() { return focusOn; } + std::string& getTunnelNameToFocus() { return tunnelNameToFocus; } + QWidget* getWidgetToFocus() { return widgetToFocus; } private: Saver* saver; @@ -74,9 +79,6 @@ private: bool exiting; DelayedSaveThread* thread; void wakeThreadAndJoinThread(); - - bool focusOnTunnel; - std::string tunnelNameToFocus; }; #endif // DELAYEDSAVEMANAGERIMPL_H diff --git a/qt/i2pd_qt/I2pdQtTypes.h b/qt/i2pd_qt/I2pdQtTypes.h new file mode 100644 index 00000000..c7b1917a --- /dev/null +++ b/qt/i2pd_qt/I2pdQtTypes.h @@ -0,0 +1,7 @@ +#ifndef I2PDQTTYPES_H +#define I2PDQTTYPES_H + +enum WrongInputPageEnum { generalSettingsPage, tunnelsSettingsPage }; +enum FocusEnum { noFocus, focusOnTunnelName, focusOnWidget }; + +#endif // I2PDQTTYPES_H diff --git a/qt/i2pd_qt/Saver.h b/qt/i2pd_qt/Saver.h index cefe0220..bf971fb6 100644 --- a/qt/i2pd_qt/Saver.h +++ b/qt/i2pd_qt/Saver.h @@ -4,6 +4,9 @@ #include #include #include +class QWidget; + +#include "I2pdQtTypes.h" class Saver : public QObject { @@ -11,8 +14,8 @@ class Saver : public QObject public: Saver(); - //false iff failures - virtual bool save(const bool focusOnTunnel, const std::string& tunnelNameToFocus)=0; + //FocusEnum::focusNone iff failures //??? wtf + virtual bool save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus="", QWidget* widgetToFocus=nullptr)=0; signals: void reloadTunnelsConfigAndUISignal(const QString); diff --git a/qt/i2pd_qt/SaverImpl.cpp b/qt/i2pd_qt/SaverImpl.cpp index f35ef5b7..fee2526b 100644 --- a/qt/i2pd_qt/SaverImpl.cpp +++ b/qt/i2pd_qt/SaverImpl.cpp @@ -15,7 +15,7 @@ SaverImpl::SaverImpl(MainWindow *mainWindowPtr_, QList * config SaverImpl::~SaverImpl() {} -bool SaverImpl::save(const bool focusOnTunnel, const std::string& tunnelNameToFocus) { +bool SaverImpl::save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus, QWidget* widgetToFocus) { //save main config { std::stringstream out; @@ -59,12 +59,14 @@ bool SaverImpl::save(const bool focusOnTunnel, const std::string& tunnelNameToFo outfile.close(); } - //reload saved configs + if(reloadAfterSave) { + //reload saved configs #if 0 - i2p::client::context.ReloadConfig(); + i2p::client::context.ReloadConfig(); #endif - if(focusOnTunnel) emit reloadTunnelsConfigAndUISignal(QString::fromStdString(tunnelNameToFocus)); + if(reloadAfterSave) emit reloadTunnelsConfigAndUISignal(focusOn==FocusEnum::focusOnTunnelName?QString::fromStdString(tunnelNameToFocus):""); + } return true; } diff --git a/qt/i2pd_qt/SaverImpl.h b/qt/i2pd_qt/SaverImpl.h index c44877a2..d20f1bbf 100644 --- a/qt/i2pd_qt/SaverImpl.h +++ b/qt/i2pd_qt/SaverImpl.h @@ -19,7 +19,7 @@ class SaverImpl : public Saver public: SaverImpl(MainWindow *mainWindowPtr_, QList * configItems_, std::map* tunnelConfigs_); virtual ~SaverImpl(); - virtual bool save(const bool focusOnTunnel, const std::string& tunnelNameToFocus); + virtual bool save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus, QWidget* widgetToFocus); void setConfPath(QString& confpath_); void setTunnelsConfPath(QString& tunconfpath_); private: diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index c4e55f53..b5830d4c 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -64,7 +64,8 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../daemon/UPnP.h \ AboutDialog.h \ BuildDateTimeQt.h \ - I2pdQtUtil.h + I2pdQtUtil.h \ + I2pdQtTypes.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 3d0dc551..2c6e7523 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -783,7 +783,7 @@ void MainWindow::deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf) { } /** returns false iff not valid items present and save was aborted */ -bool MainWindow::saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocus){ +bool MainWindow::saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus){ QString cannotSaveSettings = QApplication::tr("Cannot save settings."); programOptionsWriterCurrentSection=""; /*if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); @@ -803,7 +803,7 @@ bool MainWindow::saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocu return false; } } - delayedSaveManagerPtr->delayedSave(++dataSerial, focusOnTunnel, tunnelNameToFocus);//TODO does dataSerial work? //FIXME + delayedSaveManagerPtr->delayedSave(reloadAfterSave, ++dataSerial, focusOn, tunnelNameToFocus, widgetToFocus);//TODO does dataSerial work? //FIXME //onLoggingOptionsChange(); return true; @@ -841,7 +841,7 @@ void MainWindow::updated() { bool correct = applyTunnelsUiToConfigs(); if(!correct) return; - saveAllConfigs(false); + saveAllConfigs(false, FocusEnum::noFocus); } void MainWindowItem::installListeners(MainWindow *mainWindow) {} @@ -916,11 +916,11 @@ bool MainWindow::applyTunnelsUiToConfigs() { return true; } -void MainWindow::reloadTunnelsConfigAndUI_QString(const QString tunnelNameToFocus) { - reloadTunnelsConfigAndUI(tunnelNameToFocus.toStdString()); +void MainWindow::reloadTunnelsConfigAndUI_QString(QString tunnelNameToFocus) { + reloadTunnelsConfigAndUI(tunnelNameToFocus.toStdString(), nullptr); } -void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) { +void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus, QWidget* widgetToFocus) { deleteTunnelForms(); for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { TunnelConfig* tunconf = it->second; @@ -937,8 +937,10 @@ void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string ol std::map::const_iterator it=mainWindow->tunnelConfigs.find(oldName); if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it); mainWindow->tunnelConfigs[tunConf->getName()]=tunConf; + mainWindow->saveAllConfigs(true, FocusEnum::focusOnTunnelName, tunConf->getName()); } - mainWindow->saveAllConfigs(true, tunConf->getName()); + else + mainWindow->saveAllConfigs(false, FocusEnum::noFocus); } void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){ diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 34228e43..241d4efb 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -1,8 +1,6 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -enum WrongInputPageEnum { generalSettingsPage, tunnelsSettingsPage }; - #include #include #include @@ -136,7 +134,7 @@ public: std::string optName=""; if(!option.section.isEmpty())optName=option.section.toStdString()+std::string("."); optName+=option.option.toStdString(); - qDebug() << "Writing option" << optName.c_str() << "of type" << rtti.c_str(); + //qDebug() << "Writing option" << optName.c_str() << "of type" << rtti.c_str(); std::string sectionAsStdStr = option.section.toStdString(); if(!option.section.isEmpty() && sectionAsStdStr!=programOptionsWriterCurrentSection) { @@ -541,12 +539,12 @@ protected: public slots: /** returns false iff not valid items present and save was aborted */ - bool saveAllConfigs(bool focusOnTunnel, std::string tunnelNameToFocus=""); - void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus); + bool saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::string tunnelNameToFocus="", QWidget* widgetToFocus=nullptr); + void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus, QWidget* widgetToFocus); + void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI("", nullptr); } //focus none - void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI(""); } - void reloadTunnelsConfigAndUI_QString(const QString tunnelNameToFocus); + void reloadTunnelsConfigAndUI_QString(QString tunnelNameToFocus); void addServerTunnelPushButtonReleased(); void addClientTunnelPushButtonReleased(); @@ -651,7 +649,7 @@ private: tunnelConfigs.erase(it); delete tc; } - saveAllConfigs(false); + saveAllConfigs(true, FocusEnum::noFocus); } std::string GenerateNewTunnelName() { @@ -688,7 +686,7 @@ private: sigType, cryptoType); - saveAllConfigs(true, name); + saveAllConfigs(true, FocusEnum::focusOnTunnelName, name); } void CreateDefaultServerTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels () @@ -726,7 +724,7 @@ private: cryptoType); - saveAllConfigs(true, name); + saveAllConfigs(true, FocusEnum::focusOnTunnelName, name); } void ReadTunnelsConfig() //TODO deduplicate the code with ClientContext.cpp::ReadTunnels () From 83b10fba62b31395f82c0559665e532022308917 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 05:45:11 +0800 Subject: [PATCH 31/47] qt: added assert.h - it is needed for ci circumstances --- qt/i2pd_qt/DelayedSaveManagerImpl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qt/i2pd_qt/DelayedSaveManagerImpl.cpp b/qt/i2pd_qt/DelayedSaveManagerImpl.cpp index b0c7c4d2..bad6fdb5 100644 --- a/qt/i2pd_qt/DelayedSaveManagerImpl.cpp +++ b/qt/i2pd_qt/DelayedSaveManagerImpl.cpp @@ -1,5 +1,7 @@ #include "DelayedSaveManagerImpl.h" +#include + DelayedSaveManagerImpl::DelayedSaveManagerImpl() : widgetToFocus(nullptr), saver(nullptr), From 370ab6307a28552ee776e53710c4bfad9534bc36 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 06:34:22 +0800 Subject: [PATCH 32/47] qt: fixes #1581 --- qt/i2pd_qt/mainwindow.cpp | 31 +++++++++++++++++-------------- qt/i2pd_qt/mainwindow.h | 16 +++++++++------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 2c6e7523..1cebc230 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -177,9 +177,9 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren # define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option)) - initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton); - initFileChooser( OPTION("","tunconf",[](){return "";}), uiSettings->tunnelsConfigFileLineEdit, uiSettings->tunnelsConfigFileBrowsePushButton); - initFileChooser( OPTION("","pidfile",[]{return "";}), uiSettings->pidFileLineEdit, uiSettings->pidFileBrowsePushButton); + initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton, false); + initFileChooser( OPTION("","tunconf",[](){return "";}), uiSettings->tunnelsConfigFileLineEdit, uiSettings->tunnelsConfigFileBrowsePushButton, false); + initFileChooser( OPTION("","pidfile",[]{return "";}), uiSettings->pidFileLineEdit, uiSettings->pidFileBrowsePushButton, false); uiSettings->logDestinationComboBox->clear(); uiSettings->logDestinationComboBox->insertItems(0, QStringList() @@ -189,7 +189,7 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren ); initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox); - logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton); + logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton, false); initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), uiSettings->logLevelComboBox); initCheckBox( OPTION("","logclftime",[]{return "false";}), uiSettings->logclftimeCheckBox);//"Write full CLF-formatted date and time to log (default: write only time)" initFolderChooser( OPTION("","datadir",[]{return "";}), uiSettings->dataFolderLineEdit, uiSettings->dataFolderBrowsePushButton); @@ -232,7 +232,7 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), uiSettings->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address")); initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), uiSettings->httpProxyPortLineEdit, tr("HTTP proxy -> Port")); initCheckBox( OPTION("httpproxy","addresshelper",[]{return "true";}), uiSettings->httpProxyAddressHelperCheckBox);//Enable address helper (jump). true by default - initFileChooser( OPTION("httpproxy","keys",[]{return "";}), uiSettings->httpProxyKeyFileLineEdit, uiSettings->httpProxyKeyFilePushButton); + initFileChooser( OPTION("httpproxy","keys",[]{return "";}), uiSettings->httpProxyKeyFileLineEdit, uiSettings->httpProxyKeyFilePushButton, false); initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_httpPorxySignatureType); initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), uiSettings->httpProxyInboundTunnelsLenLineEdit); initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), uiSettings->httpProxyInboundTunnQuantityLineEdit); @@ -245,7 +245,7 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren initCheckBox( OPTION("socksproxy","enabled",[]{return "";}), uiSettings->socksProxyEnabledCheckBox); initIPAddressBox( OPTION("socksproxy","address",[]{return "";}), uiSettings->socksProxyAddressLineEdit, tr("Socks proxy -> IP address")); initTCPPortBox( OPTION("socksproxy","port",[]{return "4447";}), uiSettings->socksProxyPortLineEdit, tr("Socks proxy -> Port")); - initFileChooser( OPTION("socksproxy","keys",[]{return "";}), uiSettings->socksProxyKeyFileLineEdit, uiSettings->socksProxyKeyFilePushButton); + initFileChooser( OPTION("socksproxy","keys",[]{return "";}), uiSettings->socksProxyKeyFileLineEdit, uiSettings->socksProxyKeyFilePushButton, false); initSignatureTypeCombobox(OPTION("socksproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_socksProxySignatureType); initStringBox( OPTION("socksproxy","inbound.length",[]{return "";}), uiSettings->socksProxyInboundTunnelsLenLineEdit); initStringBox( OPTION("socksproxy","inbound.quantity",[]{return "";}), uiSettings->socksProxyInboundTunnQuantityLineEdit); @@ -275,8 +275,8 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren initIPAddressBox( OPTION("i2pcontrol","address",[]{return "";}), uiSettings->i2pControlAddressLineEdit, tr("I2PControl -> IP address")); initTCPPortBox( OPTION("i2pcontrol","port",[]{return "7650";}), uiSettings->i2pControlPortLineEdit, tr("I2PControl -> Port")); initStringBox( OPTION("i2pcontrol","password",[]{return "";}), uiSettings->i2pControlPasswordLineEdit); - initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), uiSettings->i2pControlCertFileLineEdit, uiSettings->i2pControlCertFileBrowsePushButton); - initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), uiSettings->i2pControlKeyFileLineEdit, uiSettings->i2pControlKeyFileBrowsePushButton); + initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), uiSettings->i2pControlCertFileLineEdit, uiSettings->i2pControlCertFileBrowsePushButton, true); + initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), uiSettings->i2pControlKeyFileLineEdit, uiSettings->i2pControlKeyFileBrowsePushButton, true); initCheckBox( OPTION("upnp","enabled",[]{return "true";}), uiSettings->enableUPnPCheckBox); initStringBox( OPTION("upnp","name",[]{return "I2Pd";}), uiSettings->upnpNameLineEdit); @@ -284,9 +284,9 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren initCheckBox( OPTION("precomputation","elgamal",[]{return "false";}), uiSettings->useElGamalPrecomputedTablesCheckBox); initCheckBox( OPTION("reseed","verify",[]{return "";}), uiSettings->reseedVerifyCheckBox); - initFileChooser( OPTION("reseed","file",[]{return "";}), uiSettings->reseedFileLineEdit, uiSettings->reseedFileBrowsePushButton); + initFileChooser( OPTION("reseed","file",[]{return "";}), uiSettings->reseedFileLineEdit, uiSettings->reseedFileBrowsePushButton, true); initStringBox( OPTION("reseed","urls",[]{return "";}), uiSettings->reseedURLsLineEdit); - initFileChooser( OPTION("reseed","zipfile",[]{return "";}), uiSettings->reseedZipFileLineEdit, uiSettings->reseedZipFileBrowsePushButton); //Path to local .zip file to reseed from + initFileChooser( OPTION("reseed","zipfile",[]{return "";}), uiSettings->reseedZipFileLineEdit, uiSettings->reseedZipFileBrowsePushButton, true); //Path to local .zip file to reseed from initUInt16Box( OPTION("reseed","threshold",[]{return "25";}), uiSettings->reseedThresholdNumberLineEdit, tr("reseedThreshold")); //Minimum number of known routers before requesting reseed. 25 by default initStringBox( OPTION("reseed","proxy",[]{return "";}), uiSettings->reseedProxyLineEdit);//URL for https/socks reseed proxy @@ -649,15 +649,15 @@ MainWindow::~MainWindow() //QMessageBox::information(0, "Debug", "mw destructor 2"); } -FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton){ +FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile){ FileChooserItem* retVal; - retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this); + retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this, requireExistingFile); MainWindowItem* super=retVal; configItems.append(super); return retVal; } void MainWindow::initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton){ - configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton, this)); + configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton, this, true)); } /*void MainWindow::initCombobox(ConfigOption option, QComboBox* comboBox){ configItems.append(new ComboBoxItem(option, comboBox)); @@ -811,11 +811,14 @@ bool MainWindow::saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::st void FileChooserItem::pushButtonReleased() { QString fileName = lineEdit->text().trimmed(); - fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")); + fileName = requireExistingFile ? + QFileDialog::getOpenFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")) : + QFileDialog::getSaveFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")); if(fileName.length()>0)lineEdit->setText(fileName); } void FolderChooserItem::pushButtonReleased() { QString fileName = lineEdit->text().trimmed(); + assert(requireExistingFile); fileName = QFileDialog::getExistingDirectory(nullptr, tr("Open Folder"), fileName); if(fileName.length()>0)lineEdit->setText(fileName); } diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 241d4efb..6843a98c 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -193,10 +193,12 @@ public: virtual bool isValid(bool & alreadyDisplayedIfWrong); }; class FileOrFolderChooserItem : public BaseStringItem { +protected: + const bool requireExistingFile; public: QPushButton* browsePushButton; - FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : - BaseStringItem(option_, lineEdit_, QString(), mw), browsePushButton(browsePushButton_) {} + FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile_) : + BaseStringItem(option_, lineEdit_, QString(), mw), requireExistingFile(requireExistingFile_), browsePushButton(browsePushButton_) {} virtual ~FileOrFolderChooserItem(){} }; class FileChooserItem : public FileOrFolderChooserItem { @@ -204,8 +206,8 @@ class FileChooserItem : public FileOrFolderChooserItem { private slots: void pushButtonReleased(); public: - FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw) { + FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFile) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; @@ -214,8 +216,8 @@ class FolderChooserItem : public FileOrFolderChooserItem{ private slots: void pushButtonReleased(); public: - FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw) { + FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFolder) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFolder) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; @@ -519,7 +521,7 @@ protected: //LogDestinationComboBoxItem* logOption; FileChooserItem* logFileNameOption; - FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton); + FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile); void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton); //void initCombobox(ConfigOption option, QComboBox* comboBox); void initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox); From d4b648510275705b40acdd9d93817cea48354fc1 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 06:57:49 +0800 Subject: [PATCH 33/47] qt: small improv --- qt/i2pd_qt/i2pd_qt.pro | 3 +++ qt/i2pd_qt/mainwindow.h | 7 ++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index b5830d4c..c445348a 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -9,7 +9,10 @@ CONFIG += strict_c++ c++11 CONFIG(debug, debug|release) { message(Debug build) + + # do not redirect logging to std::ostream and to Log pane DEFINES += DEBUG_WITH_DEFAULT_LOGGING + I2PDMAKE += DEBUG=yes } else { message(Release build) diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 6843a98c..412a060e 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -118,7 +118,7 @@ public: std::string optName=""; if(!option.section.isEmpty())optName=option.section.toStdString()+std::string("."); optName+=option.option.toStdString(); - qDebug() << "loadFromConfigOption[" << optName.c_str() << "]"; + //qDebug() << "loadFromConfigOption[" << optName.c_str() << "]"; boost::any programOption; i2p::config::GetOptionAsAny(optName, programOption); optionValue=programOption.empty()?boost::any(std::string("")) @@ -290,7 +290,7 @@ public: virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption(){ MainWindowItem::loadFromConfigOption(); - qDebug() << "setting value for checkbox " << checkBox->text(); + //qDebug() << "setting value for checkbox " << checkBox->text(); checkBox->setChecked(boost::any_cast(optionValue)); } virtual void saveToStringStream(std::stringstream& out){ @@ -769,16 +769,13 @@ private: std::string dest; if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); - std::cout << "had read tunnel dest: " << dest << std::endl; } int port = section.second.get (I2P_CLIENT_TUNNEL_PORT); - std::cout << "had read tunnel port: " << port << std::endl; // optional params std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); int cryptoType = section.second.get(I2P_CLIENT_TUNNEL_CRYPTO_TYPE, 0); int destinationPort = section.second.get(I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); - std::cout << "had read tunnel destinationPort: " << destinationPort << std::endl; i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // I2CP std::map options; From 242e3d007c0a733598a7486556ec05a0d6d292c8 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 07:17:01 +0800 Subject: [PATCH 34/47] qt: fixes #1529 --- qt/i2pd_qt/mainwindow.cpp | 6 +++--- qt/i2pd_qt/mainwindow.h | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 1cebc230..50698e7f 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -177,7 +177,7 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren # define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option)) - initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton, false); + initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton, false, true); initFileChooser( OPTION("","tunconf",[](){return "";}), uiSettings->tunnelsConfigFileLineEdit, uiSettings->tunnelsConfigFileBrowsePushButton, false); initFileChooser( OPTION("","pidfile",[]{return "";}), uiSettings->pidFileLineEdit, uiSettings->pidFileBrowsePushButton, false); @@ -649,9 +649,9 @@ MainWindow::~MainWindow() //QMessageBox::information(0, "Debug", "mw destructor 2"); } -FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile){ +FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile, bool readOnly){ FileChooserItem* retVal; - retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this, requireExistingFile); + retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this, requireExistingFile, readOnly); MainWindowItem* super=retVal; configItems.append(super); return retVal; diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 412a060e..9d848acf 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -102,12 +102,14 @@ class MainWindow; class MainWindowItem : public QObject { Q_OBJECT +private: ConfigOption option; QWidget* widgetToFocus; QString requirementToBeValid; + const bool readOnly; public: - MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_) : - option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_) {} + MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_, bool readOnly_=false) : + option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_), readOnly(readOnly_) {} QWidget* getWidgetToFocus(){return widgetToFocus;} QString& getRequirementToBeValid() { return requirementToBeValid; } ConfigOption& getConfigOption() { return option; } @@ -125,6 +127,7 @@ public: :boost::any_cast(programOption).value(); } virtual void saveToStringStream(std::stringstream& out){ + if(readOnly)return; //should readOnly items (conf=) error somewhere, instead of silently skipping save? if(isType(optionValue)) { std::string v = boost::any_cast(optionValue); if(v.empty())return; @@ -170,8 +173,8 @@ class BaseStringItem : public MainWindowItem { public: QLineEdit* lineEdit; MainWindow *mainWindow; - BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_, MainWindow* mainWindow_): - MainWindowItem(option_, lineEdit_, requirementToBeValid_), + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_, MainWindow* mainWindow_, bool readOnly=false): + MainWindowItem(option_, lineEdit_, requirementToBeValid_, readOnly), lineEdit(lineEdit_), mainWindow(mainWindow_) {}; @@ -197,8 +200,8 @@ protected: const bool requireExistingFile; public: QPushButton* browsePushButton; - FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile_) : - BaseStringItem(option_, lineEdit_, QString(), mw), requireExistingFile(requireExistingFile_), browsePushButton(browsePushButton_) {} + FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile_, bool readOnly) : + BaseStringItem(option_, lineEdit_, QString(), mw, readOnly), requireExistingFile(requireExistingFile_), browsePushButton(browsePushButton_) {} virtual ~FileOrFolderChooserItem(){} }; class FileChooserItem : public FileOrFolderChooserItem { @@ -206,8 +209,8 @@ class FileChooserItem : public FileOrFolderChooserItem { private slots: void pushButtonReleased(); public: - FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFile) { + FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile, bool readOnly) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFile, readOnly) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; @@ -217,7 +220,7 @@ private slots: void pushButtonReleased(); public: FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFolder) : - FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFolder) { + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFolder, false) { QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); } }; @@ -521,7 +524,7 @@ protected: //LogDestinationComboBoxItem* logOption; FileChooserItem* logFileNameOption; - FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile); + FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile, bool readOnly=false); void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton); //void initCombobox(ConfigOption option, QComboBox* comboBox); void initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox); From d7342586a696f17bf3ec293f115994d85c3331ed Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 07:44:37 +0800 Subject: [PATCH 35/47] qt: fixes #1593 --- qt/i2pd_qt/i2pd_qt.pro | 2 ++ qt/i2pd_qt/mainwindow.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index c445348a..5aefe3f5 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -13,9 +13,11 @@ CONFIG(debug, debug|release) { # do not redirect logging to std::ostream and to Log pane DEFINES += DEBUG_WITH_DEFAULT_LOGGING + DEFINES += I2PD_QT_DEBUG I2PDMAKE += DEBUG=yes } else { message(Release build) + DEFINES += I2PD_QT_RELEASE I2PDMAKE += DEBUG=no } diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 50698e7f..386b06d7 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -188,6 +188,9 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren << QApplication::translate("MainWindow", "file", 0) ); initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox); +#ifdef I2PD_QT_RELEASE + uiSettings->logDestinationComboBox->setEnabled(false); // #1593 +#endif logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton, false); initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), uiSettings->logLevelComboBox); @@ -325,7 +328,15 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren # undef OPTION //widgetlocks.add(new widgetlock(widget,lockbtn)); + + + // #1593 +#ifdef I2PD_QT_RELEASE + uiSettings->logDestComboEditPushButton->setEnabled(false); +#else widgetlocks.add(new widgetlock(uiSettings->logDestinationComboBox,uiSettings->logDestComboEditPushButton)); +#endif + widgetlocks.add(new widgetlock(uiSettings->logLevelComboBox,uiSettings->logLevelComboEditPushButton)); widgetlocks.add(new widgetlock(uiSettings->comboBox_httpPorxySignatureType,uiSettings->httpProxySignTypeComboEditPushButton)); widgetlocks.add(new widgetlock(uiSettings->comboBox_socksProxySignatureType,uiSettings->socksProxySignTypeComboEditPushButton)); From 8c61e7d227c387f2edd54d97121fb5f78324ce75 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Dec 2020 18:58:30 -0500 Subject: [PATCH 36/47] replace LeaseSet completely if store type changes --- libi2pd/Destination.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 8f3b495a..52ede959 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -379,7 +379,8 @@ namespace client LogPrint (eLogDebug, "Destination: Remote LeaseSet"); std::lock_guard lock(m_RemoteLeaseSetsMutex); auto it = m_RemoteLeaseSets.find (key); - if (it != m_RemoteLeaseSets.end ()) + if (it != m_RemoteLeaseSets.end () && + it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type { leaseSet = it->second; if (leaseSet->IsNewer (buf + offset, len - offset)) @@ -399,6 +400,7 @@ namespace client } else { + // add or replace if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET) leaseSet = std::make_shared (buf + offset, len - offset); // LeaseSet else From 0b084956e610e3c730b66aa4d2442275b6e67404 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 09:04:40 +0800 Subject: [PATCH 37/47] qt: stream.kill hrefs done - step to completion of #914 --- qt/i2pd_qt/mainwindow.cpp | 56 ++++++++++++++++++++++++++++++++++----- qt/i2pd_qt/mainwindow.h | 1 + 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 386b06d7..034b9c4a 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -45,6 +45,7 @@ std::string programOptionsWriterCurrentSection; MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *parent) : QMainWindow(parent) + ,currentLocalDestinationB32("") ,logStream(logStream_) ,delayedSaveManagerPtr(new DelayedSaveManagerImpl()) ,dataSerial(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL) @@ -135,6 +136,7 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren //childTextBrowser->setOpenExternalLinks(false); childTextBrowser->setOpenLinks(false); connect(textBrowser, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(anchorClickedHandler(const QUrl&))); + connect(childTextBrowser, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(anchorClickedHandler(const QUrl&))); pageWithBackButton = new PageWithBackButton(this, childTextBrowser); ui->verticalLayout_2->addWidget(pageWithBackButton); pageWithBackButton->hide(); @@ -992,20 +994,60 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { qDebug()< params; + i2p::http::URL url; + url.parse(str.toStdString()); + url.parse_query(params); + const std::string page = params["page"]; + const std::string cmd = params["cmd"]; + if(page == "local_destination") { + std::string b32 = params["b32"]; + currentLocalDestinationB32 = b32; pageWithBackButton->show(); textBrowser->hide(); std::stringstream s; - std::string strstd = str.toStdString(); + std::string strstd = currentLocalDestinationB32; i2p::http::ShowLocalDestination(s,strstd,0); childTextBrowser->setHtml(QString::fromStdString(s.str())); } + if(cmd == "closestream") { + std::string b32 = params["b32"]; + uint32_t streamID = std::stoul(params["streamID"], nullptr); + + i2p::data::IdentHash ident; + ident.FromBase32 (b32); + auto dest = i2p::client::context.FindLocalDestination (ident); + + if (streamID) { + if (dest) { + if(dest->DeleteStream (streamID)) + QMessageBox::information( + this, + QApplication::tr("Success"), + QApplication::tr("SUCCESS: Stream closed")); + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: Stream not found or already was closed")); + } + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: Destination not found")); + } + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: StreamID is null")); + std::stringstream s; + std::string strstd = currentLocalDestinationB32; + i2p::http::ShowLocalDestination(s,strstd,0); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } } void MainWindow::backClickedFromChild() { diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 9d848acf..789e4cb0 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -410,6 +410,7 @@ class DelayedSaveManagerImpl; class MainWindow : public QMainWindow { Q_OBJECT private: + std::string currentLocalDestinationB32; std::shared_ptr logStream; DelayedSaveManagerImpl* delayedSaveManagerPtr; DelayedSaveManager::DATA_SERIAL_TYPE dataSerial; From 5c2f1f36e8d1df08c98d87c6c141e5155012cab1 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 09:40:58 +0800 Subject: [PATCH 38/47] qt: sam session is now shown at qt->sam sessions, work towards #914 --- daemon/HTTPServer.cpp | 2 +- daemon/HTTPServer.h | 1 + qt/i2pd_qt/mainwindow.cpp | 12 +++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 25b6ab19..c0a0b72b 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -820,7 +820,7 @@ namespace http { s << "SAM Sessions: no sessions currently running.
\r\n"; } - static void ShowSAMSession (std::stringstream& s, const std::string& id) + void ShowSAMSession (std::stringstream& s, const std::string& id) { auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index a977e3e8..9b50fc32 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -98,6 +98,7 @@ namespace http void ShowSAMSessions (std::stringstream& s); void ShowI2PTunnels (std::stringstream& s); void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token); + void ShowSAMSession (std::stringstream& s, const std::string& id); } // http } // i2p diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 034b9c4a..e5ce2729 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1001,7 +1001,14 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { url.parse_query(params); const std::string page = params["page"]; const std::string cmd = params["cmd"]; - if(page == "local_destination") { + if(page == "sam_session") { + const std::string samID = params["sam_id"]; + pageWithBackButton->show(); + textBrowser->hide(); + std::stringstream s; + i2p::http::ShowSAMSession (s, samID); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } else if(page == "local_destination") { std::string b32 = params["b32"]; currentLocalDestinationB32 = b32; pageWithBackButton->show(); @@ -1010,8 +1017,7 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { std::string strstd = currentLocalDestinationB32; i2p::http::ShowLocalDestination(s,strstd,0); childTextBrowser->setHtml(QString::fromStdString(s.str())); - } - if(cmd == "closestream") { + } else if(cmd == "closestream") { std::string b32 = params["b32"]; uint32_t streamID = std::stoul(params["streamID"], nullptr); From a0d90717c335cfaf700cdb86e2819bd49e9c7a43 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 18 Dec 2020 10:06:57 +0800 Subject: [PATCH 39/47] qt: i2cp server page is now shown, work towards #914 --- daemon/HTTPServer.cpp | 2 +- daemon/HTTPServer.h | 1 + qt/i2pd_qt/mainwindow.cpp | 13 +++++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c0a0b72b..aba30fd7 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -532,7 +532,7 @@ namespace http { } } - static void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id) + void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id) { auto i2cpServer = i2p::client::context.GetI2CPServer (); if (i2cpServer) diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index 9b50fc32..8e1520b8 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -99,6 +99,7 @@ namespace http void ShowI2PTunnels (std::stringstream& s); void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token); void ShowSAMSession (std::stringstream& s, const std::string& id); + void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id); } // http } // i2p diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index e5ce2729..e0123dc8 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1001,14 +1001,13 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { url.parse_query(params); const std::string page = params["page"]; const std::string cmd = params["cmd"]; - if(page == "sam_session") { - const std::string samID = params["sam_id"]; + if (page == "sam_session") { pageWithBackButton->show(); textBrowser->hide(); std::stringstream s; - i2p::http::ShowSAMSession (s, samID); + i2p::http::ShowSAMSession (s, params["sam_id"]); childTextBrowser->setHtml(QString::fromStdString(s.str())); - } else if(page == "local_destination") { + } else if (page == "local_destination") { std::string b32 = params["b32"]; currentLocalDestinationB32 = b32; pageWithBackButton->show(); @@ -1017,6 +1016,12 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { std::string strstd = currentLocalDestinationB32; i2p::http::ShowLocalDestination(s,strstd,0); childTextBrowser->setHtml(QString::fromStdString(s.str())); + } else if (page == "i2cp_local_destination") { + pageWithBackButton->show(); + textBrowser->hide(); + std::stringstream s; + i2p::http::ShowI2CPLocalDestination (s, params["i2cp_id"]); + childTextBrowser->setHtml(QString::fromStdString(s.str())); } else if(cmd == "closestream") { std::string b32 = params["b32"]; uint32_t streamID = std::stoul(params["streamID"], nullptr); From a61d7fe115b3b3a34f10fc2877d20085ec5b0049 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 18 Dec 2020 20:48:08 -0500 Subject: [PATCH 40/47] set correct NAME for NAMING REPLY --- libi2pd_client/SAM.cpp | 14 +++++++------- libi2pd_client/SAM.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index d758f31e..9f7e771e 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -708,16 +708,16 @@ namespace client auto session = m_Owner.FindSession(m_ID); auto dest = session == nullptr ? context.GetSharedLocalDestination() : session->localDestination; if (name == "ME") - SendNamingLookupReply (dest->GetIdentity ()); + SendNamingLookupReply (name, dest->GetIdentity ()); else if ((identity = context.GetAddressBook ().GetFullAddress (name)) != nullptr) - SendNamingLookupReply (identity); + SendNamingLookupReply (name, identity); else if ((addr = context.GetAddressBook ().GetAddress (name))) { if (addr->IsIdentHash ()) { auto leaseSet = dest->FindLeaseSet (addr->identHash); if (leaseSet) - SendNamingLookupReply (leaseSet->GetIdentity ()); + SendNamingLookupReply (name, leaseSet->GetIdentity ()); else dest->RequestDestination (addr->identHash, std::bind (&SAMSocket::HandleNamingLookupLeaseSetRequestComplete, @@ -756,7 +756,7 @@ namespace client if (leaseSet) { context.GetAddressBook ().InsertFullAddress (leaseSet->GetIdentity ()); - SendNamingLookupReply (leaseSet->GetIdentity ()); + SendNamingLookupReply (name, leaseSet->GetIdentity ()); } else { @@ -770,13 +770,13 @@ namespace client } } - void SAMSocket::SendNamingLookupReply (std::shared_ptr identity) + void SAMSocket::SendNamingLookupReply (const std::string& name, std::shared_ptr identity) { auto base64 = identity->ToBase64 (); #ifdef _MSC_VER - size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ()); + size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, name.c_str (), base64.c_str ()); #else - size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ()); + size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, name.c_str (), base64.c_str ()); #endif SendMessageReply (m_Buffer, l, false); } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index fafd7d1c..9495bf6f 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -55,7 +55,7 @@ namespace client const char SAM_DEST_REPLY[] = "DEST REPLY PUB=%s PRIV=%s\n"; const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n"; const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP"; - const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n"; + const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=%s VALUE=%s\n"; const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n"; const char SAM_RAW_RECEIVED[] = "RAW RECEIVED SIZE=%lu\n"; const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n"; @@ -140,7 +140,7 @@ namespace client void Connect (std::shared_ptr remote, std::shared_ptr session = nullptr); void HandleConnectLeaseSetRequestComplete (std::shared_ptr leaseSet); - void SendNamingLookupReply (std::shared_ptr identity); + void SendNamingLookupReply (const std::string& name, std::shared_ptr identity); void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, std::string name); void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode); void SendSessionCreateReplyOk (); From ae1b1da34282ec95a244b97eb3832a70af27300d Mon Sep 17 00:00:00 2001 From: user Date: Sat, 19 Dec 2020 21:16:40 +0800 Subject: [PATCH 41/47] qt: log level ui control now synced with core and log pane ui at runtime --- qt/i2pd_qt/mainwindow.cpp | 15 +++++++++++++++ qt/i2pd_qt/mainwindow.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index e0123dc8..7aa868fc 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -196,6 +196,9 @@ MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *paren logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton, false); initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), uiSettings->logLevelComboBox); + + QObject::connect(uiSettings->logLevelComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(syncLogLevel(int))); + initCheckBox( OPTION("","logclftime",[]{return "false";}), uiSettings->logclftimeCheckBox);//"Write full CLF-formatted date and time to log (default: write only time)" initFolderChooser( OPTION("","datadir",[]{return "";}), uiSettings->dataFolderLineEdit, uiSettings->dataFolderBrowsePushButton); initIPAddressBox( OPTION("","host",[]{return "";}), uiSettings->routerExternalHostLineEdit, tr("Router external address -> Host")); @@ -1109,3 +1112,15 @@ void MainWindow::highlightWrongInput(QString warningText, WrongInputPageEnum inp default: assert(false); break; } } + +void MainWindow::syncLogLevel (int /*comboBoxIndex*/) { + std::string level = uiSettings->logLevelComboBox->currentText().toLower().toStdString(); + if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug") + i2p::log::Logger().SetLogLevel(level); + else { + LogPrint(eLogError, "unknown loglevel set attempted"); + return; + } + i2p::log::Logger().Reopen (); +} + diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 789e4cb0..e1ddcc6e 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -453,7 +453,10 @@ private slots: void runPeerTest(); void enableTransit(); void disableTransit(); + public slots: + void syncLogLevel (int comboBoxIndex); + void showStatus_local_destinations_Page(); void showStatus_leasesets_Page(); void showStatus_tunnels_Page(); From da7e2f25808bba3e5dc6c59d2e37407895cb7573 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 19 Dec 2020 15:07:12 -0500 Subject: [PATCH 42/47] don't send message through non-established session --- libi2pd/Datagram.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 559b0a8b..9d61f5e0 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -295,11 +295,11 @@ namespace datagram } } - if (!m_RoutingSession || !m_RoutingSession->GetOwner ()) + if (!m_RoutingSession || !m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) { bool found = false; for (auto& it: m_PendingRoutingSessions) - if (it->GetOwner ()) // found established session + if (it->GetOwner () && m_RoutingSession->IsReadyToSend ()) // found established session { m_RoutingSession = it; m_PendingRoutingSessions.clear (); @@ -309,7 +309,7 @@ namespace datagram if (!found) { m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true); - if (!m_RoutingSession->GetOwner ()) + if (!m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) m_PendingRoutingSessions.push_back (m_RoutingSession); } } From f2e4d5f06c8d21885f70429b0a9a2d912db1a8a1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 20 Dec 2020 19:52:06 -0500 Subject: [PATCH 43/47] trim behind not affter max generated tags --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index ecc7412f..a2c5b612 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -298,7 +298,10 @@ namespace garlic break; case eECIESx25519BlkNextKey: LogPrint (eLogDebug, "Garlic: next key"); - HandleNextKey (buf + offset, size, receiveTagset); + if (receiveTagset) + HandleNextKey (buf + offset, size, receiveTagset); + else + LogPrint (eLogError, "Garlic: Unexpected next key block"); break; case eECIESx25519BlkAck: { @@ -721,20 +724,19 @@ namespace garlic { if (receiveTagset->GetNextIndex () - index < GetOwner ()->GetNumRatchetInboundTags ()/2) moreTags = GetOwner ()->GetNumRatchetInboundTags (); + index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind } else { moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4 if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; moreTags -= (receiveTagset->GetNextIndex () - index); + index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind } if (moreTags > 0) - { GenerateMoreReceiveTags (receiveTagset, moreTags); - index -= (moreTags >> 1); // /2 - if (index > 0) - receiveTagset->SetTrimBehind (index); - } + if (index > 0) + receiveTagset->SetTrimBehind (index); } return true; } From d34dc397e880eddb4af241a420440de4d4543894 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 Dec 2020 14:06:34 -0500 Subject: [PATCH 44/47] changed to 320 tags max --- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- libi2pd/Garlic.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 59be94c1..805ea8d6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -33,7 +33,7 @@ namespace garlic const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180 const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; - const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160; + const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320; const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12; const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */ diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 02ded2f4..019cc387 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -551,9 +551,9 @@ namespace garlic auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); for (int i = 0; i < maxTags; i++) { - LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); if (AddECIESx25519SessionNextTag (m_LastTagset) == tag) { + LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[tag].index)) found = true; break; From b4236b04c6eed5d20b569df27eada2bfcab02d2d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 25 Dec 2020 09:01:55 -0500 Subject: [PATCH 45/47] leaset creation timeout --- libi2pd_client/I2CP.cpp | 24 +++++++++++++++++++++++- libi2pd_client/I2CP.h | 5 ++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index cb618b5d..c9db4a82 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -26,7 +26,8 @@ namespace client I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params): LeaseSetDestination (service, isPublic, ¶ms), - m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()) + m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()), + m_IsCreatingLeaseSet (false), m_LeaseSetCreationTimer (service) { } @@ -34,6 +35,7 @@ namespace client { LeaseSetDestination::Stop (); m_Owner = nullptr; + m_LeaseSetCreationTimer.cancel (); } void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) @@ -84,6 +86,11 @@ namespace client void I2CPDestination::CreateNewLeaseSet (std::vector > tunnels) { + if (m_IsCreatingLeaseSet) + { + LogPrint (eLogInfo, "I2CP: LeaseSet is being created"); + return; + } uint8_t priv[256] = {0}; i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only m_LeaseSetExpirationTime = ls.GetExpirationTime (); @@ -94,15 +101,28 @@ namespace client uint16_t sessionID = m_Owner->GetSessionID (); if (sessionID != 0xFFFF) { + m_IsCreatingLeaseSet = true; htobe16buf (leases - 3, sessionID); size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); + m_LeaseSetCreationTimer.expires_from_now (boost::posix_time::seconds (I2CP_LEASESET_CREATION_TIMEOUT)); + auto s = GetSharedFromThis (); + m_LeaseSetCreationTimer.async_wait ([s](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "I2CP: LeaseSet creation timeout expired. Terminate"); + if (s->m_Owner) s->m_Owner->Stop (); + } + }); } } } void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) { + m_IsCreatingLeaseSet = false; + m_LeaseSetCreationTimer.cancel (); auto ls = std::make_shared (m_Identity, buf, len); ls->SetExpirationTime (m_LeaseSetExpirationTime); SetLeaseSet (ls); @@ -110,6 +130,8 @@ namespace client void I2CPDestination::LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len) { + m_IsCreatingLeaseSet = false; + m_LeaseSetCreationTimer.cancel (); auto ls = (storeType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) ? std::make_shared (m_Identity, buf, len): std::make_shared (storeType, m_Identity, buf, len); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 32f32221..da7d8ffa 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -27,7 +27,8 @@ namespace client const size_t I2CP_SESSION_BUFFER_SIZE = 4096; const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M - + const int I2CP_LEASESET_CREATION_TIMEOUT = 10; // in seconds + const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4; const size_t I2CP_HEADER_SIZE = I2CP_HEADER_TYPE_OFFSET + 1; @@ -109,6 +110,8 @@ namespace client std::shared_ptr m_ECIESx25519Decryptor; uint8_t m_ECIESx25519PrivateKey[32]; uint64_t m_LeaseSetExpirationTime; + bool m_IsCreatingLeaseSet; + boost::asio::deadline_timer m_LeaseSetCreationTimer; }; class RunnableI2CPDestination: private i2p::util::RunnableService, public I2CPDestination From 86ff0d86dbdc3df86c7a41e7d2ba64adc00a04ab Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Dec 2020 17:18:29 -0500 Subject: [PATCH 46/47] check if new tag was created --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 18 ++++++++++++++++-- libi2pd/Garlic.cpp | 13 ++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index a2c5b612..01be859b 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -45,13 +45,13 @@ namespace garlic uint64_t RatchetTagSet::GetNextSessionTag () { - i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) m_NextIndex++; if (m_NextIndex >= 65535) { LogPrint (eLogError, "Garlic: Tagset ", GetTagSetID (), " is empty"); return 0; } + i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) return m_KeyData.GetTag (); } @@ -687,6 +687,13 @@ namespace garlic auto index = m_SendTagset->GetNextIndex (); CreateNonce (index, nonce); // tag's index uint64_t tag = m_SendTagset->GetNextSessionTag (); + if (!tag) + { + LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset"); + if (GetOwner ()) + GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey); + return false; + } memcpy (out, &tag, 8); // ad = The session tag, 8 bytes // ciphertext = ENCRYPT(k, n, payload, ad) @@ -1050,7 +1057,14 @@ namespace garlic if (GetOwner ()) { for (int i = 0; i < numTags; i++) - GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); + { + auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); + if (!tag) + { + LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset"); + break; + } + } } } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 019cc387..aff92837 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -546,12 +546,18 @@ namespace garlic if (!session->HandleNextMessage (buf, length, nullptr, 0)) { // try to gererate more tags for last tagset - if (m_LastTagset) + if (m_LastTagset && m_LastTagset->GetNextIndex () < 2*ECIESX25519_TAGSET_MAX_NUM_TAGS) { auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); for (int i = 0; i < maxTags; i++) { - if (AddECIESx25519SessionNextTag (m_LastTagset) == tag) + auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset); + if (!nextTag) + { + LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset"); + break; + } + if (nextTag == tag) { LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[tag].index)) @@ -1057,7 +1063,8 @@ namespace garlic { auto index = tagset->GetNextIndex (); uint64_t tag = tagset->GetNextSessionTag (); - m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset}); + if (tag) + m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset}); return tag; } From 7ce92118e4451956fd8b5c9b224a236e2ebe8a26 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Dec 2020 11:18:53 -0500 Subject: [PATCH 47/47] handle follow-on NSR messages --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 36 ++++++++++++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++- libi2pd/util.h | 14 +++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 01be859b..d2286b15 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -9,6 +9,7 @@ #include #include #include "Log.h" +#include "util.h" #include "Crypto.h" #include "Elligator.h" #include "Tag.h" @@ -619,18 +620,15 @@ namespace garlic } buf += 32; len -= 32; // KDF for Reply Key Section - uint8_t h[32]; memcpy (h, m_H, 32); // save m_H + i2p::util::SaveStateHelper s(*this); // restore noise state on exit MixHash (tag, 8); // h = SHA256(h || tag) MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; - if (m_State == eSessionStateNewSessionSent) - { - // only fist time, we assume ephemeral keys the same - m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) - MixKey (sharedSecret); - GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) - MixKey (sharedSecret); - } + m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) + MixKey (sharedSecret); + GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) + MixKey (sharedSecret); + uint8_t nonce[12]; CreateNonce (0, nonce); // calculate hash for zero length @@ -646,6 +644,7 @@ namespace garlic i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) if (m_State == eSessionStateNewSessionSent) { + // only first time, then we keep using existing tagsets // k_ab = keydata[0:31], k_ba = keydata[32:63] m_SendTagset = std::make_shared(shared_from_this ()); m_SendTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) @@ -667,11 +666,10 @@ namespace garlic if (m_State == eSessionStateNewSessionSent) { m_State = eSessionStateEstablished; - m_EphemeralKeys = nullptr; + //m_EphemeralKeys = nullptr; // TODO: delete after a while m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch (); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); } - memcpy (m_H, h, 32); // restore m_H HandlePayload (buf, len - 16, nullptr, 0); // we have received reply to NS with LeaseSet in it @@ -762,12 +760,16 @@ namespace garlic [[fallthrough]]; #endif case eSessionStateEstablished: - if (HandleExistingSessionMessage (buf, len, receiveTagset, index)) return true; - // check NSR just in case - LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index); - if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2) - GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS); - return HandleNewOutgoingSessionReply (buf, len); + if (receiveTagset->IsNS ()) + { + // our of sequence NSR + LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index); + if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2) + GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS); + return HandleNewOutgoingSessionReply (buf, len); + } + else + return HandleExistingSessionMessage (buf, len, receiveTagset, index); case eSessionStateNew: return HandleNewIncomingSession (buf, len); case eSessionStateNewSessionSent: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 805ea8d6..86e3ffc0 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -45,7 +45,8 @@ namespace garlic public: RatchetTagSet (std::shared_ptr session): m_Session (session) {}; - + virtual bool IsNS () const { return false; }; + void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void NextSessionTagRatchet (); uint64_t GetNextSessionTag (); @@ -91,6 +92,8 @@ namespace garlic NSRatchetTagSet (std::shared_ptr session): RatchetTagSet (session), m_DummySession (session) {}; + + bool IsNS () const { return true; }; private: diff --git a/libi2pd/util.h b/libi2pd/util.h index f6222b9f..e6de09ed 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -170,6 +170,20 @@ namespace util void SetThreadName (const char *name); + template + class SaveStateHelper + { + public: + + SaveStateHelper (T& orig): m_Original (orig), m_Copy (orig) {}; + ~SaveStateHelper () { m_Original = m_Copy; }; + + private: + + T& m_Original; + T m_Copy; + }; + namespace net { int GetMTU (const boost::asio::ip::address& localAddress);