From 59b471b9a2edd38fe4de7a9f449a746a439157ec Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 May 2021 14:10:31 -0400 Subject: [PATCH 01/64] i2cp.leaseSetPrivKey for HTTP and SOCKS proxy --- libi2pd/Config.cpp | 16 +++++++++------- libi2pd_client/ClientContext.cpp | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index b316ba83..5b584e35 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -62,11 +62,11 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", bool_switch()->default_value(false), "Deprecated option. Always false") + ("ntcp", bool_switch()->default_value(false), "Ignored. Always false") ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") - ("ntcpproxy", value()->default_value(""), "Deprecated option") + ("ntcpproxy", value()->default_value(""), "Ignored") #ifdef _WIN32 - ("svcctl", value()->default_value(""), "Deprecated option") + ("svcctl", value()->default_value(""), "Ignored") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif @@ -77,9 +77,9 @@ namespace config { ("limits.coresize", value()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.openfiles", value()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.transittunnels", value()->default_value(2500), "Maximum active transit sessions (default:2500)") - ("limits.ntcpsoft", value()->default_value(0), "Deprecated option") - ("limits.ntcphard", value()->default_value(0), "Deprecated option") - ("limits.ntcpthreads", value()->default_value(1), "Deprecated option") + ("limits.ntcpsoft", value()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)") + ("limits.ntcphard", value()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") + ("limits.ntcpthreads", value()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)") ; options_description httpserver("HTTP Server options"); @@ -113,6 +113,7 @@ namespace config { ("httpproxy.addresshelper", value()->default_value(true), "Enable or disable addresshelper") ("httpproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") + ("httpproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") ; options_description socksproxy("SOCKS Proxy options"); @@ -134,6 +135,7 @@ namespace config { ("socksproxy.outproxyport", value()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") ("socksproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("socksproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") + ("socksproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") ; options_description sam("SAM bridge options"); @@ -281,7 +283,7 @@ namespace config { options_description meshnets("Meshnet transports options"); meshnets.add_options() - ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)") + ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (deafult: false)") ("meshnets.yggaddress", value()->default_value(""), "Yggdrasil address to publish") ; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 2f3d4d48..94311297 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -495,6 +495,8 @@ namespace client options[I2CP_PARAM_LEASESET_TYPE] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, value)) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_PRIV_KEY, value) && !value.empty ()) + options[I2CP_PARAM_LEASESET_PRIV_KEY] = value; } void ClientContext::ReadTunnels () From 0e68fe4a57bd782faf9ef59e77a7d683b3dac8d2 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 22 May 2021 08:39:05 +0300 Subject: [PATCH 02/64] [i18n] start multilang support for webconsole Signed-off-by: R4SAS --- Makefile | 9 ++++--- daemon/HTTPServer.cpp | 36 +++++++++++++++++++++------- filelist.mk | 2 ++ i18n/I18N.h | 39 ++++++++++++++++++++++++++++++ i18n/russian.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++ libi2pd/FS.cpp | 17 +++++++------ 6 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 i18n/I18N.h create mode 100644 i18n/russian.cpp diff --git a/Makefile b/Makefile index 7ff74787..40e72918 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ I2PD := i2pd LIB_SRC_DIR := libi2pd LIB_CLIENT_SRC_DIR := libi2pd_client +LANG_SRC_DIR := i18n DAEMON_SRC_DIR := daemon # import source files lists @@ -49,12 +50,13 @@ ifeq ($(USE_MESHNET),yes) NEEDED_CXXFLAGS += -DMESHNET endif -NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) +NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) +LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC)) DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) -DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) +DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(LANG_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) @@ -63,6 +65,7 @@ mk_obj_dir: @mkdir -p obj/Win32 @mkdir -p obj/$(LIB_SRC_DIR) @mkdir -p obj/$(LIB_CLIENT_SRC_DIR) + @mkdir -p obj/$(LANG_SRC_DIR) @mkdir -p obj/$(DAEMON_SRC_DIR) api: mk_obj_dir $(SHLIB) $(ARLIB) @@ -82,7 +85,7 @@ obj/%.o: %.cpp # '-' is 'ignore if missing' on first run -include $(DEPS) -$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) +$(I2PD): $(LANG_OBJS) $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) $(SHLIB): $(LIB_OBJS) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index d56c2894..043d1630 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -30,6 +30,12 @@ #include "Daemon.h" #include "util.h" #include "ECIESX25519AEADRatchetSession.h" +#include "I18N.h" + +#ifdef _WIN32 +#include +#include +#endif #ifdef WIN32_APP #include "Win32App.h" @@ -130,23 +136,37 @@ namespace http { static std::string ConvertTime (uint64_t time); std::map HTTPConnection::m_Tokens; + std::string DataPath; + + static void SetDataDir () + { +#ifdef _WIN32 + boost::filesystem::wpath path (i2p::fs::GetDataDir()); + auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); + i2p::http::DataPath = path.string(); + boost::filesystem::path::imbue(loc); // Return it back +#else + i2p::http::DataPath = i2p::fs::GetDataDir(); +#endif + } + static void ShowUptime (std::stringstream& s, int seconds) { int num; if ((num = seconds / 86400) > 0) { - s << num << " days, "; + s << num << " " << tr("days", num) << ", "; seconds -= num * 86400; } if ((num = seconds / 3600) > 0) { - s << num << " hours, "; + s << num << " " << tr("hours", num) << ", "; seconds -= num * 3600; } if ((num = seconds / 60) > 0) { - s << num << " min, "; + s << num << " " << tr("minutes", num) << ", "; seconds -= num * 60; } - s << seconds << " seconds"; + s << seconds << " " << tr("seconds", seconds); } static void ShowTraffic (std::stringstream& s, uint64_t bytes) @@ -197,11 +217,7 @@ namespace http { "\r\n" "\r\n" /* TODO: Add support for locale */ " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ -#if (!defined(WIN32)) " \r\n" -#else - " \r\n" -#endif " \r\n" " \r\n" " Purple I2P " VERSION " Webconsole\r\n" @@ -315,7 +331,7 @@ namespace http { s << "Transit: "; ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; - s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; + s << "Data path: " << i2p::http::DataPath << "
\r\n"; s << "
"; if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { s << "\r\n\r\n
\r\n"; @@ -1374,6 +1390,8 @@ namespace http { LogPrint(eLogInfo, "HTTPServer: password set to ", pass); } + i2p::http::SetDataDir(); + m_IsRunning = true; m_Thread.reset (new std::thread (std::bind (&HTTPServer::Run, this))); m_Acceptor.listen (); diff --git a/filelist.mk b/filelist.mk index 7d13fb2f..e2a5d40e 100644 --- a/filelist.mk +++ b/filelist.mk @@ -19,4 +19,6 @@ LIB_CLIENT_SRC = $(wildcard $(LIB_CLIENT_SRC_DIR)/*.cpp) #DAEMON_SRC = \ # HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp +LANG_SRC = $(wildcard $(LANG_SRC_DIR)/*.cpp) + DAEMON_SRC = $(wildcard $(DAEMON_SRC_DIR)/*.cpp) diff --git a/i18n/I18N.h b/i18n/I18N.h new file mode 100644 index 00000000..4556fe25 --- /dev/null +++ b/i18n/I18N.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef __I18N_H__ +#define __I18N_H__ + +namespace i2p { +namespace i18n { + + namespace russian { + std::string GetString (std::string arg); + std::string GetPlural (std::string arg, int n); + } + + std::string translate (std::string arg) + { + return i2p::i18n::russian::GetString (arg); + } + + template + std::string translate (std::string arg, inttype&& n) + { + return i2p::i18n::russian::GetPlural (arg, (int) n); + } + +} // i18n +} // i2p + +template +std::string tr (TArgs&&... args) { + return i2p::i18n::translate(std::forward(args)...); +} + +#endif // __I18N_H__ diff --git a/i18n/russian.cpp b/i18n/russian.cpp new file mode 100644 index 00000000..892ee203 --- /dev/null +++ b/i18n/russian.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +// Russian localization file + +namespace i2p { +namespace i18n { +namespace russian { // language + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + int plural (int n) { + return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + } + + static std::map strings + { + {"Enabled", "Включено"}, + {"Disabled", "Выключено"} + }; + + static std::map> plurals + { + {"days", {"день", "дня", "дней"}}, + {"hours", {"час", "часа", "часов"}}, + {"minutes", {"минута", "минуты", "минут"}}, + {"seconds", {"секунда", "секунды", "секунд"}} + }; + + std::string GetString (std::string arg) + { + auto it = strings.find(arg); + if (it == strings.end()) + { + return arg; + } else { + return it->second; + } + } + + std::string GetPlural (std::string arg, int n) + { + auto it = plurals.find(arg); + if (it == plurals.end()) + { + return arg; + } else { + int form = plural(n); + return it->second[form]; + } + } + +} // language +} // i18n +} // i2p diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index bd1a7ad2..250b24ef 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -47,10 +47,10 @@ namespace fs { return; } #ifdef _WIN32 - char localAppData[MAX_PATH]; + wchar_t localAppData[MAX_PATH]; // check executable directory first - if(!GetModuleFileName(NULL, localAppData, MAX_PATH)) + if(!GetModuleFileNameW(NULL, localAppData, MAX_PATH)) { #ifdef WIN32_APP MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK); @@ -61,14 +61,15 @@ namespace fs { } else { - auto execPath = boost::filesystem::path(localAppData).parent_path(); + auto execPath = boost::filesystem::wpath(localAppData).parent_path(); // if config file exists in .exe's folder use it if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string - dataDir = execPath.string (); - else // otherwise %appdata% { - if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK) + dataDir = execPath.string (); + } else // otherwise %appdata% + { + if(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK) { #ifdef WIN32_APP MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK); @@ -78,7 +79,9 @@ namespace fs { exit(1); } else - dataDir = std::string(localAppData) + "\\" + appName; + { + dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName; + } } } return; From 80b44fc9a9c6a90872ccaa1988737bda67f73e3f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 22 May 2021 18:29:05 +0300 Subject: [PATCH 03/64] Support multilang, update code Signed-off-by: R4SAS --- contrib/i2pd.conf | 3 +++ daemon/Daemon.cpp | 7 +++++ daemon/HTTPServer.cpp | 23 +--------------- i18n/English.cpp | 56 +++++++++++++++++++++++++++++++++++++++ i18n/I18N.h | 21 +++++++++++++-- libi2pd/Config.cpp | 1 + libi2pd/FS.cpp | 13 +++++++++ libi2pd/FS.h | 3 +++ libi2pd/RouterContext.cpp | 7 ++++- libi2pd/RouterContext.h | 18 ++++++++++--- 10 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 i18n/English.cpp diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index e8c397f5..3c9c71ff 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -103,6 +103,9 @@ port = 7070 # auth = true # user = i2pd # pass = changeme +## Select webconsole language +## Currently supported only english (default) and russian languages +# lang = english [httpproxy] ## Uncomment and set to 'false' to disable HTTP Proxy diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 77000652..ec62f5d6 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -343,6 +343,13 @@ namespace util LogPrint(eLogInfo, "Daemon: using hidden mode"); i2p::data::netdb.SetHidden(true); } + + std::string httpLang; i2p::config::GetOption("http.lang", httpLang); + if (!httpLang.compare("russian")) + i2p::context.SetLanguage (eRussian); + else + i2p::context.SetLanguage (eEnglish); + return true; } diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 043d1630..87744f37 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -32,11 +32,6 @@ #include "ECIESX25519AEADRatchetSession.h" #include "I18N.h" -#ifdef _WIN32 -#include -#include -#endif - #ifdef WIN32_APP #include "Win32App.h" #endif @@ -136,20 +131,6 @@ namespace http { static std::string ConvertTime (uint64_t time); std::map HTTPConnection::m_Tokens; - std::string DataPath; - - static void SetDataDir () - { -#ifdef _WIN32 - boost::filesystem::wpath path (i2p::fs::GetDataDir()); - auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); - i2p::http::DataPath = path.string(); - boost::filesystem::path::imbue(loc); // Return it back -#else - i2p::http::DataPath = i2p::fs::GetDataDir(); -#endif - } - static void ShowUptime (std::stringstream& s, int seconds) { int num; @@ -331,7 +312,7 @@ namespace http { s << "Transit: "; ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; - s << "Data path: " << i2p::http::DataPath << "
\r\n"; + s << "Data path: " << i2p::fs::GetUTF8DataDir() << "
\r\n"; s << "
"; if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { s << "\r\n\r\n
\r\n"; @@ -1390,8 +1371,6 @@ namespace http { LogPrint(eLogInfo, "HTTPServer: password set to ", pass); } - i2p::http::SetDataDir(); - m_IsRunning = true; m_Thread.reset (new std::thread (std::bind (&HTTPServer::Run, this))); m_Acceptor.listen (); diff --git a/i18n/English.cpp b/i18n/English.cpp new file mode 100644 index 00000000..8664a0f0 --- /dev/null +++ b/i18n/English.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +// Russian localization file + +namespace i2p { +namespace i18n { +namespace english { // language + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + int plural (int n) { + return n != 1 ? 1 : 0; + } + + static std::map strings + { + {"Enabled", "Enabled"}, + {"Disabled", "Disabled"} + }; + + static std::map> plurals + { + {"days", {"day", "days"}}, + {"hours", {"hour", "hours"}}, + {"minutes", {"minute", "minutes"}}, + {"seconds", {"second", "seconds"}} + }; + + std::string GetString (std::string arg) + { + auto it = strings.find(arg); + if (it == strings.end()) + { + return arg; + } else { + return it->second; + } + } + + std::string GetPlural (std::string arg, int n) + { + auto it = plurals.find(arg); + if (it == plurals.end()) + { + return arg; + } else { + int form = plural(n); + return it->second[form]; + } + } + +} // language +} // i18n +} // i2p diff --git a/i18n/I18N.h b/i18n/I18N.h index 4556fe25..eddec514 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -9,9 +9,16 @@ #ifndef __I18N_H__ #define __I18N_H__ +#include "RouterContext.h" + namespace i2p { namespace i18n { + namespace english { + std::string GetString (std::string arg); + std::string GetPlural (std::string arg, int n); + } + namespace russian { std::string GetString (std::string arg); std::string GetPlural (std::string arg, int n); @@ -19,13 +26,23 @@ namespace i18n { std::string translate (std::string arg) { - return i2p::i18n::russian::GetString (arg); + switch (i2p::context.GetLanguage ()) + { + case eEnglish: return i2p::i18n::english::GetString (arg); + case eRussian: return i2p::i18n::russian::GetString (arg); + default: return arg; + } } template std::string translate (std::string arg, inttype&& n) { - return i2p::i18n::russian::GetPlural (arg, (int) n); + switch (i2p::context.GetLanguage ()) + { + case eEnglish: return i2p::i18n::english::GetPlural (arg, (int) n); + case eRussian: return i2p::i18n::russian::GetPlural (arg, (int) n); + default: return arg; + } } } // i18n diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 5b584e35..f5316860 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -93,6 +93,7 @@ namespace config { ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") ("http.hostname", value()->default_value("localhost"), "Expected hostname for WebUI") ("http.webroot", value()->default_value("/"), "WebUI root path (default: / )") + ("http.lang", value()->default_value("english"), "WebUI language (default: english )") ; options_description httpproxy("HTTP Proxy options"); diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 250b24ef..6ac302b0 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -12,6 +12,7 @@ #ifdef _WIN32 #include #include +#include #endif #include "Base.h" @@ -41,6 +42,18 @@ namespace fs { return dataDir; } + const std::string GetUTF8DataDir () { +#ifdef _WIN32 + boost::filesystem::wpath path (dataDir); + auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); // convert path to UTF-8 + auto dataDirUTF8 = path.string(); + boost::filesystem::path::imbue(loc); // Return locale settings back + return dataDirUTF8; +#else + return dataDir; // linux, osx, android uses UTF-8 by default +#endif + } + void DetectDataDir(const std::string & cmdline_param, bool isService) { if (cmdline_param != "") { dataDir = cmdline_param; diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 698e9b6b..f07ee35c 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -75,6 +75,9 @@ namespace fs { /** @brief Returns datadir path */ const std::string & GetDataDir(); + /** @brief Returns datadir path in UTF-8 encoding */ + const std::string GetUTF8DataDir(); + /** * @brief Set datadir either from cmdline option or using autodetection * @param cmdline_param Value of cmdline parameter --datadir= diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ad6576ed..0cfcb18a 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -29,7 +29,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), - m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) + m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID), m_Language (eEnglish) { } @@ -916,6 +916,11 @@ namespace i2p } } + void RouterContext::SetLanguage (Lang language) + { + m_Language = language; + } + i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () { if (!m_StaticKeys) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index a4d18f82..dad3fdca 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -24,7 +24,7 @@ namespace i2p namespace garlic { class RouterIncomingRatchetSession; -} +} const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; @@ -39,7 +39,7 @@ namespace garlic eRouterStatusError = 3, eRouterStatusUnknown = 4, eRouterStatusProxy = 5, - eRouterStatusMesh = 6 + eRouterStatusMesh = 6 }; enum RouterError @@ -49,7 +49,12 @@ namespace garlic eRouterErrorOffline = 2, eRouterErrorSymmetricNAT = 3 }; - + + enum Lang { + eEnglish = 0, + eRussian + }; + class RouterContext: public i2p::garlic::GarlicDestination { private: @@ -144,6 +149,10 @@ namespace garlic void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatusMessage (std::shared_ptr msg); + // i18n + Lang GetLanguage () const { return m_Language; }; + void SetLanguage (Lang language); + protected: // implements GarlicDestination @@ -178,6 +187,9 @@ namespace garlic std::unique_ptr m_StaticKeys; // for ECIESx25519 std::unique_ptr m_InitialNoiseState, m_CurrentNoiseState; + + // i18n + Lang m_Language; }; extern RouterContext context; From f321eb66c04fa6b7af9070bd139ad75f3f451937 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 May 2021 18:41:25 -0400 Subject: [PATCH 04/64] rename DatabaseLookupTageSet to SymmetricKeyTagset --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 12 ++++++------ libi2pd/ECIESX25519AEADRatchetSession.h | 4 ++-- libi2pd/Garlic.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index f9d5672f..45affde7 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -117,14 +117,14 @@ namespace garlic return session->HandleNextMessage (buf, len, shared_from_this (), index); } - DatabaseLookupTagSet::DatabaseLookupTagSet (GarlicDestination * destination, const uint8_t * key): + SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key): ReceiveRatchetTagSet (nullptr), m_Destination (destination) { memcpy (m_Key, key, 32); Expire (); } - bool DatabaseLookupTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) + bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) { if (len < 24) return false; uint8_t nonce[12]; @@ -133,18 +133,18 @@ namespace garlic len -= 16; // poly1305 if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt { - LogPrint (eLogWarning, "Garlic: Lookup reply AEAD decryption failed"); + LogPrint (eLogWarning, "Garlic: Symmetric key tagset AEAD decryption failed"); return false; } // we assume 1 I2NP block with delivery type local if (offset + 3 > len) { - LogPrint (eLogWarning, "Garlic: Lookup reply is too short ", len); + LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len); return false; } if (buf[offset] != eECIESx25519BlkGalicClove) { - LogPrint (eLogWarning, "Garlic: Lookup reply unexpected block ", (int)buf[offset]); + LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]); return false; } offset++; @@ -152,7 +152,7 @@ namespace garlic offset += 2; if (offset + size > len) { - LogPrint (eLogWarning, "Garlic: Lookup reply block is too long ", size); + LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size); return false; } if (m_Destination) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index bdbb7111..43e88ca6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -104,11 +104,11 @@ namespace garlic uint64_t m_ExpirationTimestamp = 0; }; - class DatabaseLookupTagSet: public ReceiveRatchetTagSet + class SymmetricKeyTagSet: public ReceiveRatchetTagSet { public: - DatabaseLookupTagSet (GarlicDestination * destination, const uint8_t * key); + SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key); bool IsIndexExpired (int index) const { return false; }; bool HandleNextMessage (uint8_t * buf, size_t len, int index); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 66a3b62f..2bf89556 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -471,7 +471,7 @@ namespace garlic { uint64_t t; memcpy (&t, tag, 8); - auto tagset = std::make_shared(this, key); + auto tagset = std::make_shared(this, key); m_ECIESx25519Tags.emplace (t, ECIESX25519AEADRatchetIndexTagset{0, tagset}); } From df66c2d2dcc55355c9812e6b8cf265a753cd4595 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 06:06:04 +0300 Subject: [PATCH 05/64] [i18n] translate HTTP proxy Signed-off-by: R4SAS --- i18n/I18N.h | 16 ++------ i18n/I18N_langs.h | 34 ++++++++++++++++ i18n/russian.cpp | 43 +++++++++++++++++++-- libi2pd/HTTP.cpp | 2 + libi2pd/RouterContext.h | 6 +-- libi2pd_client/HTTPProxy.cpp | 75 +++++++++++++++++++----------------- 6 files changed, 120 insertions(+), 56 deletions(-) create mode 100644 i18n/I18N_langs.h diff --git a/i18n/I18N.h b/i18n/I18N.h index eddec514..cb3e5c1c 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -11,20 +11,11 @@ #include "RouterContext.h" + namespace i2p { namespace i18n { - namespace english { - std::string GetString (std::string arg); - std::string GetPlural (std::string arg, int n); - } - - namespace russian { - std::string GetString (std::string arg); - std::string GetPlural (std::string arg, int n); - } - - std::string translate (std::string arg) + inline std::string translate (std::string arg) { switch (i2p::context.GetLanguage ()) { @@ -49,7 +40,8 @@ namespace i18n { } // i2p template -std::string tr (TArgs&&... args) { +std::string tr (TArgs&&... args) +{ return i2p::i18n::translate(std::forward(args)...); } diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h new file mode 100644 index 00000000..24c683b4 --- /dev/null +++ b/i18n/I18N_langs.h @@ -0,0 +1,34 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef __I18N_LANGS_H__ +#define __I18N_LANGS_H__ + +namespace i2p { + +enum Lang { + eEnglish = 0, + eRussian +}; + +namespace i18n { + + namespace english { + std::string GetString (std::string arg); + std::string GetPlural (std::string arg, int n); + } + + namespace russian { + std::string GetString (std::string arg); + std::string GetPlural (std::string arg, int n); + } + +} // i18n +} // i2p + +#endif // __I18N_LANGS_H__ diff --git a/i18n/russian.cpp b/i18n/russian.cpp index 892ee203..feb6fc63 100644 --- a/i18n/russian.cpp +++ b/i18n/russian.cpp @@ -16,8 +16,44 @@ namespace russian { // language static std::map strings { - {"Enabled", "Включено"}, - {"Disabled", "Выключено"} + // HTTP Proxy + {"Proxy error", "Ошибка прокси"}, + {"Proxy info", "Информация прокси"}, + {"Proxy error: Host not found", "Ошибка прокси: Адрес не найден"}, + {"Remote host not found in router's addressbook", "Запрошенный адрес не найден в адресной книге роутера"}, + {"You may try to find this host on jump services below", "Вы можете попробовать найти адрес на джамп сервисах ниже"}, + {"Invalid request", "Некорректный запрос"}, + {"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"}, + {"addresshelper is not supported", "addresshelper не поддерживается"}, + {"Host", "Адрес"}, + {"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"}, + {"already in router's addressbook", "уже а адресной книге роутера"}, + {"Click", "Нажмите"}, + {"here", "здесь"}, + {"to proceed", "чтобы продолжить"}, + {"to update record", "чтобы обновить запись"}, + {"Addresshelper found", "Найден addresshelper"}, + {"invalid request uri", "некорректный URI запроса"}, + {"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"}, + {"Outproxy failure", "Ошибка внешнего прокси"}, + {"bad outproxy settings", "некорректные настройки внешнего прокси"}, + {"not inside I2P network, but outproxy is not enabled", "не в I2P сети, но внешний прокси не включен"}, + {"unknown outproxy url", "неизвестный URL внешнего прокси"}, + {"cannot resolve upstream proxy", "не удается определить внешний прокси"}, + {"hostname too long", "имя хоста слишком длинное"}, + {"cannot connect to upstream socks proxy", "не удается подключиться к вышестоящему SOCKS прокси"}, + {"Cannot negotiate with socks proxy", "Не удается договориться с вышестоящим SOCKS прокси"}, + {"CONNECT error", "Ошибка CONNECT запроса"}, + {"Failed to Connect", "Не удалось подключиться"}, + {"socks proxy error", "ошибка SOCKS прокси"}, + {"failed to send request to upstream", "не удалось отправить запрос вышестоящему прокси"}, + {"No Reply From socks proxy", "Нет ответа от SOCKS прокси сервера"}, + {"cannot connect", "не удалось подключиться"}, + {"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"}, + {"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"}, + {"Host is down", "Адрес недоступен"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному адресу, возможно он не в сети. Попробуйте повторить запрос позже."}, + {"", ""}, }; static std::map> plurals @@ -25,7 +61,8 @@ namespace russian { // language {"days", {"день", "дня", "дней"}}, {"hours", {"час", "часа", "часов"}}, {"minutes", {"минута", "минуты", "минут"}}, - {"seconds", {"секунда", "секунды", "секунд"}} + {"seconds", {"секунда", "секунды", "секунд"}}, + {"", {"", ""}}, }; std::string GetString (std::string arg) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index da4299e9..6ad245f0 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -187,6 +187,8 @@ namespace http params.clear(); for (const auto& it : tokens) { + if (!it.length()) // empty + continue; std::size_t eq = it.find ('='); if (eq != std::string::npos) { auto e = std::pair(it.substr(0, eq), it.substr(eq + 1)); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index dad3fdca..1cb77a74 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -18,6 +18,7 @@ #include "Identity.h" #include "RouterInfo.h" #include "Garlic.h" +#include "I18N_langs.h" namespace i2p { @@ -50,11 +51,6 @@ namespace garlic eRouterErrorSymmetricNAT = 3 }; - enum Lang { - eEnglish = 0, - eRussian - }; - class RouterContext: public i2p::garlic::GarlicDestination { private: diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 6b2b8df7..aff165b0 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -28,6 +28,7 @@ #include "I2PTunnel.h" #include "Config.h" #include "HTTP.h" +#include "I18N.h" namespace i2p { namespace proxy { @@ -71,8 +72,8 @@ namespace proxy { void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); /* error helpers */ - void GenericProxyError(const char *title, const char *description); - void GenericProxyInfo(const char *title, const char *description); + void GenericProxyError(const std::string& title, const std::string& description); + void GenericProxyInfo(const std::string& title, const std::string& description); void HostNotFound(std::string & host); void SendProxyError(std::string & content); @@ -151,17 +152,17 @@ namespace proxy { Done(shared_from_this()); } - void HTTPReqHandler::GenericProxyError(const char *title, const char *description) { + void HTTPReqHandler::GenericProxyError(const std::string& title, const std::string& description) { std::stringstream ss; - ss << "

Proxy error: " << title << "

\r\n"; + ss << "

" << tr("Proxy error") << ": " << title << "

\r\n"; ss << "

" << description << "

\r\n"; std::string content = ss.str(); SendProxyError(content); } - void HTTPReqHandler::GenericProxyInfo(const char *title, const char *description) { + void HTTPReqHandler::GenericProxyInfo(const std::string& title, const std::string& description) { std::stringstream ss; - ss << "

Proxy info: " << title << "

\r\n"; + ss << "

" << tr("Proxy info") << ": " << title << "

\r\n"; ss << "

" << description << "

\r\n"; std::string content = ss.str(); SendProxyError(content); @@ -169,9 +170,9 @@ namespace proxy { void HTTPReqHandler::HostNotFound(std::string & host) { std::stringstream ss; - ss << "

Proxy error: Host not found

\r\n" - << "

Remote host not found in router's addressbook

\r\n" - << "

You may try to find this host on jump services below:

\r\n" + ss << "

" << tr("Proxy error: Host not found") << "

\r\n" + << "

" << tr("Remote host not found in router's addressbook") << "

\r\n" + << "

" << tr("You may try to find this host on jump services below") << ":

\r\n" << "
    \r\n"; for (const auto& js : jumpservices) { ss << "
  • " << js.first << "
  • \r\n"; @@ -216,7 +217,7 @@ namespace proxy { b64 = i2p::http::UrlDecode(value); // if we need update exists, request formed with update param if (params["update"] == "true") { len += std::strlen("&update=true"); confirm = true; } - url.query.replace(pos, len, ""); + url.query.replace(pos - 1, len + 1, ""); // +-1 for taking ? and & before parameter return true; } @@ -268,7 +269,7 @@ namespace proxy { if (m_req_len < 0) { LogPrint(eLogError, "HTTPProxy: unable to parse request"); - GenericProxyError("Invalid request", "Proxy unable to parse your request"); + GenericProxyError(tr("Invalid request"), tr("Proxy unable to parse your request")); return true; /* parse error */ } @@ -283,7 +284,7 @@ namespace proxy { if (!m_Addresshelper) { LogPrint(eLogWarning, "HTTPProxy: addresshelper request rejected"); - GenericProxyError("Invalid request", "addresshelper is not supported"); + GenericProxyError(tr("Invalid request"), tr("addresshelper is not supported")); return true; } if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm) @@ -292,17 +293,19 @@ namespace proxy { LogPrint (eLogInfo, "HTTPProxy: added address from addresshelper for ", m_RequestURL.host); std::string full_url = m_RequestURL.to_string(); std::stringstream ss; - ss << "Host " << m_RequestURL.host << " added to router's addressbook from helper. " - << "Click here to proceed."; - GenericProxyInfo("Addresshelper found", ss.str().c_str()); + ss << tr("Host") <<" " << m_RequestURL.host << " " << tr("added to router's addressbook from helper") << ". "; + ss << tr("Click") << " " << tr("here") << " " << tr("to proceed") << "."; + GenericProxyInfo(tr("Addresshelper found"), ss.str()); return true; /* request processed */ } else { + std::string full_url = m_RequestURL.to_string(); std::stringstream ss; - ss << "Host " << m_RequestURL.host << " already in router's addressbook. " - << "Click here to update record."; - GenericProxyInfo("Addresshelper found", ss.str().c_str()); + ss << tr("Host") << " " << m_RequestURL.host << " " << tr("already in router's addressbook") << ". "; + ss << tr("Click") << " " << tr("here") << " " << tr("to update record") << "."; + GenericProxyInfo(tr("Addresshelper found"), ss.str()); return true; /* request processed */ } } @@ -315,7 +318,7 @@ namespace proxy { auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) { - GenericProxyError("Invalid Request", "invalid request uri"); + GenericProxyError(tr("Invalid Request"), tr("invalid request uri")); return true; } else @@ -358,7 +361,7 @@ namespace proxy { else { /* relative url and missing 'Host' header */ - GenericProxyError("Invalid request", "Can't detect destination host from request"); + GenericProxyError(tr("Invalid request"), tr("Can't detect destination host from request")); return true; } } @@ -375,11 +378,11 @@ namespace proxy { if(m_ProxyURL.parse(m_OutproxyUrl)) ForwardToUpstreamProxy(); else - GenericProxyError("Outproxy failure", "bad outproxy settings"); + GenericProxyError(tr("Outproxy failure"), tr("bad outproxy settings")); } else { LogPrint (eLogWarning, "HTTPProxy: outproxy failure for ", dest_host, ": no outproxy enabled"); - std::string message = "Host " + dest_host + " not inside I2P network, but outproxy is not enabled"; - GenericProxyError("Outproxy failure", message.c_str()); + std::stringstream ss; ss << tr("Host") << " " << dest_host << " " << tr("not inside I2P network, but outproxy is not enabled"); + GenericProxyError(tr("Outproxy failure"), ss.str()); } return true; } @@ -467,13 +470,13 @@ namespace proxy { else { // unknown type, complain - GenericProxyError("unknown outproxy url", m_ProxyURL.to_string().c_str()); + GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string()); } } void HTTPReqHandler::HandleUpstreamProxyResolved(const boost::system::error_code & ec, boost::asio::ip::tcp::resolver::iterator it, ProxyResolvedHandler handler) { - if(ec) GenericProxyError("cannot resolve upstream proxy", ec.message().c_str()); + if(ec) GenericProxyError(tr("cannot resolve upstream proxy"), ec.message()); else handler(*it); } @@ -481,7 +484,7 @@ namespace proxy { { if(!ec) { if(m_RequestURL.host.size() > 255) { - GenericProxyError("hostname too long", m_RequestURL.host.c_str()); + GenericProxyError(tr("hostname too long"), m_RequestURL.host); return; } uint16_t port = m_RequestURL.port; @@ -508,13 +511,13 @@ namespace proxy { reqsize += host.size(); m_socks_buf[++reqsize] = 0; boost::asio::async_write(*m_proxysock, boost::asio::buffer(m_socks_buf, reqsize), boost::asio::transfer_all(), std::bind(&HTTPReqHandler::HandleSocksProxySendHandshake, this, std::placeholders::_1, std::placeholders::_2)); - } else GenericProxyError("cannot connect to upstream socks proxy", ec.message().c_str()); + } else GenericProxyError(tr("cannot connect to upstream socks proxy"), ec.message()); } void HTTPReqHandler::HandleSocksProxySendHandshake(const boost::system::error_code & ec, std::size_t bytes_transferred) { LogPrint(eLogDebug, "HTTPProxy: upstream socks handshake sent"); - if(ec) GenericProxyError("Cannot negotiate with socks proxy", ec.message().c_str()); + if(ec) GenericProxyError(tr("Cannot negotiate with socks proxy"), ec.message()); else m_proxysock->async_read_some(boost::asio::buffer(m_socks_buf, 8), std::bind(&HTTPReqHandler::HandleSocksProxyReply, this, std::placeholders::_1, std::placeholders::_2)); } @@ -556,7 +559,7 @@ namespace proxy { } else { - GenericProxyError("CONNECT error", "Failed to Connect"); + GenericProxyError(tr("CONNECT error"), tr("Failed to Connect")); } } @@ -567,7 +570,7 @@ namespace proxy { m_send_buf = m_ClientResponse.to_string(); boost::asio::async_write(*m_sock, boost::asio::buffer(m_send_buf), boost::asio::transfer_all(), [&] (const boost::system::error_code & ec, std::size_t transferred) { - if(ec) GenericProxyError("socks proxy error", ec.message().c_str()); + if(ec) GenericProxyError(tr("socks proxy error"), ec.message()); else HandoverToUpstreamProxy(); }); } else { @@ -575,7 +578,7 @@ namespace proxy { LogPrint(eLogDebug, "HTTPProxy: send ", m_send_buf.size(), " bytes"); boost::asio::async_write(*m_proxysock, boost::asio::buffer(m_send_buf), boost::asio::transfer_all(), [&](const boost::system::error_code & ec, std::size_t transferred) { - if(ec) GenericProxyError("failed to send request to upstream", ec.message().c_str()); + if(ec) GenericProxyError(tr("failed to send request to upstream"), ec.message()); else HandoverToUpstreamProxy(); }); } @@ -593,18 +596,18 @@ namespace proxy { ss << "error code: "; ss << (int) m_socks_buf[1]; std::string msg = ss.str(); - GenericProxyError("Socks Proxy error", msg.c_str()); + GenericProxyError(tr("socks proxy error"), msg); } } - else GenericProxyError("No Reply From socks proxy", ec.message().c_str()); + else GenericProxyError(tr("No Reply From socks proxy"), ec.message()); } void HTTPReqHandler::HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec) { if(!ec) { LogPrint(eLogDebug, "HTTPProxy: connected to http upstream"); - GenericProxyError("cannot connect", "http out proxy not implemented"); - } else GenericProxyError("cannot connect to upstream http proxy", ec.message().c_str()); + GenericProxyError(tr("cannot connect"), tr("http out proxy not implemented")); + } else GenericProxyError(tr("cannot connect to upstream http proxy"), ec.message()); } /* will be called after some data received from client */ @@ -637,7 +640,7 @@ namespace proxy { { if (!stream) { LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); - GenericProxyError("Host is down", "Can't create connection to requested host, it may be down. Please try again later."); + GenericProxyError(tr("Host is down"), tr("Can't create connection to requested host, it may be down. Please try again later.")); return; } if (Kill()) From e687773b412d62c16d332a39f703c3d0db3ef037 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 10:50:26 +0300 Subject: [PATCH 06/64] [18n] translate webconsole Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 434 ++++++++++++++++++++++-------------------- i18n/russian.cpp | 160 +++++++++++++++- 2 files changed, 381 insertions(+), 213 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 87744f37..22cefedd 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -41,7 +41,7 @@ namespace i2p { namespace http { - const char *itoopieFavicon = + const std::string itoopieFavicon = "data:image/png;base64," "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACx" "jwv8YQUAAAAJcEhZcwAALiIAAC4iAari3ZIAAAAHdElNRQfgCQsUNSZrkhi1AAAAGXRFWHRTb2Z0" @@ -59,49 +59,51 @@ namespace http { "JHYnlIsfzJjIp9xZKswL5YKBHL+coKJoRDaUSzoozxHVrygQU4JykQADAwAT5b1NHtwZugAAAABJ" "RU5ErkJggg=="; - const char *cssStyles = - "\r\n"; + static void GetStyles (std::stringstream& s) + { + s << "\r\n"; + } const char HTTP_PAGE_TUNNELS[] = "tunnels"; const char HTTP_PAGE_TRANSIT_TUNNELS[] = "transit_tunnels"; @@ -155,28 +157,35 @@ namespace http { s << std::fixed << std::setprecision(2); auto numKBytes = (double) bytes / 1024; if (numKBytes < 1024) - s << numKBytes << " KiB"; + s << numKBytes << " " << tr("KiB"); else if (numKBytes < 1024 * 1024) - s << numKBytes / 1024 << " MiB"; + s << numKBytes / 1024 << " " << tr("MiB"); else - s << numKBytes / 1024 / 1024 << " GiB"; + s << numKBytes / 1024 / 1024 << " " << tr("GiB"); } static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes) { - std::string state; + std::string state, stateText; switch (eState) { case i2p::tunnel::eTunnelStateBuildReplyReceived : - case i2p::tunnel::eTunnelStatePending : state = "building"; break; + case i2p::tunnel::eTunnelStatePending : state = "building"; break; case i2p::tunnel::eTunnelStateBuildFailed : case i2p::tunnel::eTunnelStateTestFailed : - case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; - case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; + case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; + case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; default: state = "unknown"; break; } - s << " " << state << ((explr) ? " (exploratory)" : "") << ", "; - s << " " << (int) (bytes / 1024) << " KiB\r\n"; + + if (state == "building") stateText = tr("building"); + else if (state == "failed") stateText = tr("failed"); + else if (state == "expiring") stateText = tr("expiring"); + else if (state == "established") stateText = tr("established"); + else stateText = tr("unknown"); + + s << " " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << ", "; + s << " " << (int) (bytes / 1024) << " " << tr("KiB") << "\r\n"; } static void SetLogLevel (const std::string& level) @@ -192,35 +201,40 @@ namespace http { static void ShowPageHead (std::stringstream& s) { - std::string webroot; - i2p::config::GetOption("http.webroot", webroot); + std::string webroot; i2p::config::GetOption("http.webroot", webroot); + + // Page language + std::string lang, langCode; i2p::config::GetOption("http.lang", lang); + if (lang == "russian") langCode = "ru"; + else langCode = "en"; + s << "\r\n" - "\r\n" /* TODO: Add support for locale */ + "\r\n" " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ " \r\n" " \r\n" " \r\n" - " Purple I2P " VERSION " Webconsole\r\n" - << cssStyles << - "\r\n"; + " Purple I2P " VERSION " Webconsole\r\n"; + GetStyles(s); s << + "\r\n" "\r\n" - "
    i2pd webconsole
    \r\n" + "
    " << tr("i2pd webconsole") << "
    \r\n" "
    \r\n" "
    \r\n" - " Main page
    \r\n" - " Router commands\r\n" - " Local destinations\r\n"; + " " << tr("Main page") << "
    \r\n" + " " << tr("Router commands") << "\r\n" + " " << tr("Local destinations") << "\r\n"; if (i2p::context.IsFloodfill ()) - s << " LeaseSets\r\n"; + s << " " << tr("LeaseSets") << "\r\n"; s << - " Tunnels\r\n" - " Transit tunnels\r\n" - " Transports\r\n" - " I2P tunnels\r\n"; + " " << tr("Tunnels") << "\r\n" + " " << tr("Transit tunnels") << "\r\n" + " " << tr ("Transports") << "\r\n" + " " << tr("I2P tunnels") << "\r\n"; if (i2p::client::context.GetSAMBridge ()) - s << " SAM sessions\r\n"; + s << " " << tr("SAM sessions") << "\r\n"; s << "
    \r\n" "
    "; @@ -236,94 +250,94 @@ namespace http { static void ShowError(std::stringstream& s, const std::string& string) { - s << "ERROR: " << string << "
    \r\n"; + s << "" << tr("ERROR") << ": " << string << "
    \r\n"; } static void ShowNetworkStatus (std::stringstream& s, RouterStatus status) { switch (status) { - case eRouterStatusOK: s << "OK"; break; - case eRouterStatusTesting: s << "Testing"; break; - case eRouterStatusFirewalled: s << "Firewalled"; break; - case eRouterStatusUnknown: s << "Unknown"; break; - case eRouterStatusProxy: s << "Proxy"; break; - case eRouterStatusMesh: s << "Mesh"; break; + case eRouterStatusOK: s << tr("OK"); break; + case eRouterStatusTesting: s << tr("Testing"); break; + case eRouterStatusFirewalled: s << tr("Firewalled"); break; + case eRouterStatusUnknown: s << tr("Unknown"); break; + case eRouterStatusProxy: s << tr("Proxy"); break; + case eRouterStatusMesh: s << tr("Mesh"); break; case eRouterStatusError: { - s << "Error"; + s << tr("Error"); switch (i2p::context.GetError ()) { case eRouterErrorClockSkew: - s << " - Clock skew"; + s << " - " << tr("Clock skew"); break; case eRouterErrorOffline: - s << " - Offline"; + s << " - " << tr("Offline"); break; case eRouterErrorSymmetricNAT: - s << " - Symmetric NAT"; + s << " - " << tr("Symmetric NAT"); break; default: ; } break; } - default: s << "Unknown"; + default: s << tr("Unknown"); } } void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) { - s << "Uptime: "; + s << "" << tr("Uptime") << ": "; ShowUptime(s, i2p::context.GetUptime ()); s << "
    \r\n"; - s << "Network status: "; + s << "" << tr("Network status") << ": "; ShowNetworkStatus (s, i2p::context.GetStatus ()); s << "
    \r\n"; if (i2p::context.SupportsV6 ()) { - s << "Network status 6: "; + s << "" << tr("Network status v6") << ": "; ShowNetworkStatus (s, i2p::context.GetStatusV6 ()); s << "
    \r\n"; } #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (auto remains = Daemon.gracefulShutdownInterval) { - s << "Stopping in: "; + s << "" << tr("Stopping in") << ": "; ShowUptime(s, remains); s << "
    \r\n"; } #elif defined(WIN32_APP) if (i2p::win32::g_GracefulShutdownEndtime != 0) { uint16_t remains = (i2p::win32::g_GracefulShutdownEndtime - GetTickCount()) / 1000; - s << "Stopping in: "; + s << "" << tr("Stopping in") << ": "; ShowUptime(s, remains); s << "
    \r\n"; } #endif auto family = i2p::context.GetFamily (); if (family.length () > 0) - s << "Family: " << family << "
    \r\n"; - s << "Tunnel creation success rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%
    \r\n"; - s << "Received: "; + s << ""<< tr("Family") << ": " << family << "
    \r\n"; + s << "" << tr("Tunnel creation success rate") << ": " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%
    \r\n"; + s << "" << tr("Received") << ": "; ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ()); - s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " KiB/s)
    \r\n"; - s << "Sent: "; + s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " " << tr("KiB/s") << ")
    \r\n"; + s << "" << tr("Sent") << ": "; ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ()); - s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)
    \r\n"; - s << "Transit: "; + s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " " << tr("KiB/s") << ")
    \r\n"; + s << "" << tr("Transit") << ": "; ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); - s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
    \r\n"; - s << "Data path: " << i2p::fs::GetUTF8DataDir() << "
    \r\n"; + s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr("KiB/s") << ")
    \r\n"; + s << "" << tr("Data path") << ": " << i2p::fs::GetUTF8DataDir() << "
    \r\n"; s << "
    "; - if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { - s << "\r\n\r\n
    \r\n"; + if((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) { + s << "\r\n\r\n
    \r\n"; } if(includeHiddenContent) { - s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
    \r\n"; + s << "" << tr("Router Ident") << ": " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
    \r\n"; if (!i2p::context.GetRouterInfo().GetProperty("family").empty()) - s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
    \r\n"; - s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
    \r\n"; - s << "Version: " VERSION "
    \r\n"; - s << "Our external address:" << "
    \r\n\r\n"; + s << "" << tr("Router Family") << ": " << i2p::context.GetRouterInfo().GetProperty("family") << "
    \r\n"; + s << "" << tr("Router Caps") << ": " << i2p::context.GetRouterInfo().GetProperty("caps") << "
    \r\n"; + s << "" << tr("Version") << ": " VERSION "
    \r\n"; + s << ""<< tr("Our external address") << ":" << "
    \r\n
    \r\n"; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { s << "\r\n"; @@ -331,7 +345,7 @@ namespace http { { s << "\r\n\r\n"; + s << "\r\n\r\n"; continue; } switch (address->transportStyle) @@ -353,32 +367,32 @@ namespace http { break; } default: - s << "\r\n"; + s << "\r\n"; } s << "\r\n\r\n"; } s << "
    NTCP2"; if (address->host.is_v6 ()) s << "v6"; - s << "supported
    " << tr("supported") << "
    Unknown" << tr("Unknown") << "" << address->host.to_string() << ":" << address->port << "
    \r\n"; } s << "
    \r\n
    \r\n"; - if(outputFormat==OutputFormatEnum::forQtUi) { + if(outputFormat == OutputFormatEnum::forQtUi) { s << "
    "; } - s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; - s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; - s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
    \r\n"; + s << "" << tr("Routers") << ": " << i2p::data::netdb.GetNumRouters () << " "; + s << "" << tr("Floodfills") << ": " << i2p::data::netdb.GetNumFloodfills () << " "; + s << "" << tr("LeaseSets") << ": " << i2p::data::netdb.GetNumLeaseSets () << "
    \r\n"; size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels(); clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels(); size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels(); - s << "Client Tunnels: " << std::to_string(clientTunnelCount) << " "; - s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
    \r\n
    \r\n"; + s << "" << tr("Client Tunnels") << ": " << std::to_string(clientTunnelCount) << " "; + s << "" << tr("Transit Tunnels") << ": " << std::to_string(transitTunnelCount) << "
    \r\n
    \r\n"; if(outputFormat==OutputFormatEnum::forWebConsole) { bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; + s << "
    Services
    " << "HTTP Proxy" << "
    " << "SOCKS Proxy" << "
    \r\n"; + s << "\r\n"; + s << "\r\n"; s << "\r\n"; s << "\r\n"; s << "\r\n"; @@ -390,7 +404,7 @@ namespace http { void ShowLocalDestinations (std::stringstream& s) { std::string webroot; i2p::config::GetOption("http.webroot", webroot); - s << "Local Destinations:
    \r\n
    \r\n"; + s << "" << tr("Local Destinations") << ":
    \r\n
    \r\n"; for (auto& it: i2p::client::context.GetDestinations ()) { auto ident = it.second->GetIdentHash (); @@ -402,7 +416,7 @@ namespace http { auto i2cpServer = i2p::client::context.GetI2CPServer (); if (i2cpServer && !(i2cpServer->GetSessions ().empty ())) { - s << "
    I2CP Local Destinations:
    \r\n
    \r\n"; + s << "
    I2CP "<< tr("Local Destinations") << ":
    \r\n
    \r\n"; for (auto& it: i2cpServer->GetSessions ()) { auto dest = it.second->GetDestination (); @@ -425,7 +439,7 @@ namespace http { if (dest->IsEncryptedLeaseSet ()) { i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ()); - s << "
    \r\n\r\n
    \r\n"; + s << "
    \r\n\r\n
    \r\n"; s << blinded.ToB33 () << ".b32.i2p
    \r\n"; s << "
    \r\n
    \r\n"; } @@ -434,67 +448,67 @@ namespace http { { std::string webroot; i2p::config::GetOption("http.webroot", webroot); auto base32 = dest->GetIdentHash ().ToBase32 (); - s << "
    \r\n\r\n
    \r\n" + s << "
    \r\n\r\n
    \r\n" "
    \r\n" " \r\n" " \r\n" " \r\n" - " Domain:\r\n\r\n" - " \r\n" + " " << tr("Domain") << ":\r\n\r\n" + " \r\n" "\r\nNote: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.\r\n
    \r\n
    \r\n
    \r\n"; } if(dest->GetNumRemoteLeaseSets()) { - s << "
    \r\n\r\n
    \r\n
    " << tr("Services") << "
    " << "HTTP " << tr("Proxy") << "
    " << "SOCKS " << tr("Proxy") << "
    " << "BOB" << "
    " << "SAM" << "
    " << "I2CP" << "
    "; + s << "
    \r\n\r\n
    \r\n
    AddressTypeEncType
    "; for(auto& it: dest->GetLeaseSets ()) s << "\r\n"; s << "
    "<< tr("Address") << "" << tr("Type") << "" << tr("EncType") << "
    " << it.first.ToBase32 () << "" << (int)it.second->GetStoreType () << "" << (int)it.second->GetEncryptionType () <<"
    \r\n
    \r\n
    \r\n
    \r\n"; } else - s << "LeaseSets: 0
    \r\n
    \r\n"; + s << "" << tr("LeaseSets") << ": 0
    \r\n
    \r\n"; auto pool = dest->GetTunnelPool (); if (pool) { - s << "Inbound tunnels:
    \r\n
    \r\n"; + s << "" << tr("Inbound tunnels") << ":
    \r\n
    \r\n"; for (auto & it : pool->GetInboundTunnels ()) { s << "
    "; it->Print(s); if(it->LatencyIsKnown()) - s << " ( " << it->GetMeanLatency() << "ms )"; + s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ()); s << "
    \r\n"; } s << "
    \r\n"; - s << "Outbound tunnels:
    \r\n
    \r\n"; + s << "" << tr("Outbound tunnels") << ":
    \r\n
    \r\n"; for (auto & it : pool->GetOutboundTunnels ()) { s << "
    "; it->Print(s); if(it->LatencyIsKnown()) - s << " ( " << it->GetMeanLatency() << "ms )"; + s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ()); s << "
    \r\n"; } } s << "
    \r\n"; - s << "Tags
    \r\nIncoming: " << dest->GetNumIncomingTags () << "
    \r\n"; + s << "" << tr("Tags") << "
    \r\n" << tr("Incoming") << ": " << dest->GetNumIncomingTags () << "
    \r\n"; if (!dest->GetSessions ().empty ()) { std::stringstream tmp_s; uint32_t out_tags = 0; for (const auto& it: dest->GetSessions ()) { tmp_s << "" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "" << it.second->GetNumOutgoingTags () << "\r\n"; out_tags += it.second->GetNumOutgoingTags (); } - s << "
    \r\n\r\n" - << "
    \r\n\r\n\r\n\r\n" << tmp_s.str () << "
    DestinationAmount
    \r\n
    \r\n
    \r\n"; + s << "
    \r\n\r\n" + << "
    \r\n\r\n\r\n\r\n" << tmp_s.str () << "
    " << tr("Destination") << "" << tr("Amount") << "
    \r\n
    \r\n
    \r\n"; } else - s << "Outgoing: 0
    \r\n"; + s << tr("Outgoing") << ": 0
    \r\n"; s << "
    \r\n"; auto numECIESx25519Tags = dest->GetNumIncomingECIESx25519Tags (); if (numECIESx25519Tags > 0) { - s << "ECIESx25519
    \r\nIncoming Tags: " << numECIESx25519Tags << "
    \r\n"; + s << "ECIESx25519
    \r\n" << tr("Incoming Tags") << ": " << numECIESx25519Tags << "
    \r\n"; if (!dest->GetECIESx25519Sessions ().empty ()) { std::stringstream tmp_s; uint32_t ecies_sessions = 0; @@ -502,17 +516,17 @@ namespace http { tmp_s << "" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetDestination ()) << "" << it.second->GetState () << "\r\n"; ecies_sessions++; } - s << "
    \r\n\r\n" - << "
    \r\n\r\n\r\n\r\n" << tmp_s.str () << "
    DestinationStatus
    \r\n
    \r\n
    \r\n"; + s << "
    \r\n\r\n" + << "
    \r\n\r\n\r\n\r\n" << tmp_s.str () << "
    " << tr("Destination") << "" << tr("Status") << "
    \r\n
    \r\n
    \r\n"; } else - s << "Tags sessions: 0
    \r\n"; + s << tr("Tags sessions") << ": 0
    \r\n"; s << "
    \r\n"; } } void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token) { - s << "Local Destination:
    \r\n
    \r\n"; + s << "" << tr("Local Destination") << ":
    \r\n
    \r\n"; i2p::data::IdentHash ident; ident.FromBase32 (b32); auto dest = i2p::client::context.FindLocalDestination (ident); @@ -521,7 +535,7 @@ namespace http { { ShowLeaseSetDestination (s, dest, token); // show streams - s << "\r\n\r\n\r\n"; + s << "
    Streams
    \r\n\r\n\r\n"; s << ""; s << ""; @@ -543,7 +557,7 @@ namespace http { s << ""; if (it->GetRecvStreamID ()) { s << ""; + << it->GetRecvStreamID () << "&token=" << token << "\" title=\"" << tr("Close stream") << "\"> ✘ "; } else { s << "
    " << tr("Streams") << "
    StreamID"; // Stream closing button column s << "Destination" << it->GetRecvStreamID () << ""; } @@ -567,22 +581,22 @@ namespace http { auto i2cpServer = i2p::client::context.GetI2CPServer (); if (i2cpServer) { - s << "I2CP Local Destination:
    \r\n
    \r\n"; + s << "I2CP " << tr("Local Destination") << ":
    \r\n
    \r\n"; auto it = i2cpServer->GetSessions ().find (std::stoi (id)); if (it != i2cpServer->GetSessions ().end ()) ShowLeaseSetDestination (s, it->second->GetDestination (), 0); else - ShowError(s, "I2CP session not found"); + ShowError(s, tr("I2CP session not found")); } else - ShowError(s, "I2CP is not enabled"); + ShowError(s, tr("I2CP is not enabled")); } void ShowLeasesSets(std::stringstream& s) { if (i2p::data::netdb.GetNumLeaseSets ()) { - s << "LeaseSets:
    \r\n
    \r\n"; + s << "" << tr("LeaseSets") << ":
    \r\n
    \r\n"; int counter = 1; // for each lease set i2p::data::netdb.VisitLeaseSets( @@ -601,21 +615,21 @@ namespace http { s << " expired"; // additional css class for expired s << "\">\r\n"; if (!ls->IsValid()) - s << "
    !! Invalid !!
    \r\n"; + s << "
    !! " << tr("Invalid") << " !!
    \r\n"; s << "
    \r\n"; s << "\r\n
    \r\n"; - s << "Store type: " << (int)storeType << "
    \r\n"; - s << "Expires: " << ConvertTime(ls->GetExpirationTime()) << "
    \r\n"; + s << "" << tr("Store type") << ": " << (int)storeType << "
    \r\n"; + s << "" << tr("Expires") << ": " << ConvertTime(ls->GetExpirationTime()) << "
    \r\n"; if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2) { // leases information is available auto leases = ls->GetNonExpiredLeases(); - s << "Non Expired Leases: " << leases.size() << "
    \r\n"; + s << "" << tr("Non Expired Leases") << ": " << leases.size() << "
    \r\n"; for ( auto & l : leases ) { - s << "Gateway: " << l->tunnelGateway.ToBase64() << "
    \r\n"; - s << "TunnelID: " << l->tunnelID << "
    \r\n"; - s << "EndDate: " << ConvertTime(l->endDate) << "
    \r\n"; + s << "" << tr("Gateway") << ": " << l->tunnelGateway.ToBase64() << "
    \r\n"; + s << "" << tr("TunnelID") << ": " << l->tunnelID << "
    \r\n"; + s << "" << tr("EndDate") << ": " << ConvertTime(l->endDate) << "
    \r\n"; } } s << "
    \r\n
    \r\n
    \r\n"; @@ -625,37 +639,37 @@ namespace http { } else if (!i2p::context.IsFloodfill ()) { - s << "LeaseSets: not floodfill.
    \r\n"; + s << "" << tr("LeaseSets") << ": " << tr("not floodfill") << ".
    \r\n"; } else { - s << "LeaseSets: 0
    \r\n"; + s << "" << tr("LeaseSets") << ": 0
    \r\n"; } } void ShowTunnels (std::stringstream& s) { - s << "Tunnels:
    \r\n"; - s << "Queue size: " << i2p::tunnel::tunnels.GetQueueSize () << "
    \r\n
    \r\n"; + s << "" << tr("Tunnels") << ":
    \r\n"; + s << "" << tr("Queue size") << ": " << i2p::tunnel::tunnels.GetQueueSize () << "
    \r\n
    \r\n"; auto ExplPool = i2p::tunnel::tunnels.GetExploratoryPool (); - s << "Inbound tunnels:
    \r\n
    \r\n"; + s << "" << tr("Inbound tunnels") << ":
    \r\n
    \r\n"; for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) { s << "
    "; it->Print(s); if(it->LatencyIsKnown()) - s << " ( " << it->GetMeanLatency() << "ms )"; + s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ()); s << "
    \r\n"; } s << "
    \r\n
    \r\n"; - s << "Outbound tunnels:
    \r\n
    \r\n"; + s << "" << tr("Outbound tunnels") << ":
    \r\n
    \r\n"; for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) { s << "
    "; it->Print(s); if(it->LatencyIsKnown()) - s << " ( " << it->GetMeanLatency() << "ms )"; + s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ()); s << "
    \r\n"; } @@ -666,30 +680,30 @@ namespace http { { std::string webroot; i2p::config::GetOption("http.webroot", webroot); /* commands */ - s << "Router Commands
    \r\n
    \r\n
    \r\n"; - s << " Run peer test\r\n"; + s << "" << tr("Router commands") << "
    \r\n
    \r\n
    \r\n"; + s << " " << tr("Run peer test") << "\r\n"; //s << " Reload config
    \r\n"; if (i2p::context.AcceptsTunnels ()) - s << " Decline transit tunnels\r\n"; + s << " " << tr("Decline transit tunnels") << "\r\n"; else - s << " Accept transit tunnels\r\n"; + s << " " << tr("Accept transit tunnels") << "\r\n"; #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (Daemon.gracefulShutdownInterval) - s << " Cancel graceful shutdown\r\n"; + s << " " << tr("Cancel graceful shutdown") << "\r\n"; else - s << " Start graceful shutdown
    \r\n"; + s << " " << tr("Start graceful shutdown") << "
    \r\n"; #elif defined(WIN32_APP) if (i2p::util::DaemonWin32::Instance().isGraceful) - s << " Cancel graceful shutdown\r\n"; + s << " " << tr("Cancel graceful shutdown") << "\r\n"; else - s << " Graceful shutdown\r\n"; + s << " " << tr("Start graceful shutdown") << "\r\n"; #endif - s << " Force shutdown\r\n"; + s << " " << tr("Force shutdown") << "\r\n"; s << "
    "; - s << "
    \r\nNote: any action done here are not persistent and not changes your config files.\r\n
    \r\n"; + s << "
    \r\n" << tr("Note: any action done here are not persistent and not changes your config files.") << "\r\n
    \r\n"; - s << "Logging level
    \r\n"; + s << "" << tr("Logging level") << "
    \r\n"; s << " none \r\n"; s << " error \r\n"; s << " warn \r\n"; @@ -697,12 +711,12 @@ namespace http { s << " debug
    \r\n
    \r\n"; uint16_t maxTunnels = GetMaxNumTransitTunnels (); - s << "Transit tunnels limit
    \r\n"; + s << "" << tr("Transit tunnels limit") << "
    \r\n"; s << "
    \r\n"; s << " \r\n"; s << " \r\n"; s << " \r\n"; - s << " \r\n"; + s << " \r\n"; s << "
    \r\n
    \r\n"; } @@ -710,7 +724,7 @@ namespace http { { if(i2p::tunnel::tunnels.CountTransitTunnels()) { - s << "Transit tunnels:
    \r\n
    \r\n"; + s << "" << tr("Transit tunnels") << ":
    \r\n
    \r\n"; for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) { s << "
    \r\n"; @@ -726,7 +740,7 @@ namespace http { } else { - s << "Transit tunnels: no transit tunnels currently built.
    \r\n"; + s << "" << tr("Transit tunnels") << ": " << tr("no transit tunnels currently built") << ".
    \r\n"; } } @@ -775,7 +789,7 @@ namespace http { void ShowTransports (std::stringstream& s) { - s << "Transports:
    \r\n"; + s << "" << tr("Transports") << ":
    \r\n"; auto ntcp2Server = i2p::transport::transports.GetNTCP2Server (); if (ntcp2Server) { @@ -831,13 +845,13 @@ namespace http { auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { - ShowError(s, "SAM disabled"); + ShowError(s, tr("SAM disabled")); return; } if(sam->GetSessions ().size ()) { - s << "SAM Sessions:
    \r\n
    \r\n"; + s << "" << tr("SAM sessions") << ":
    \r\n
    \r\n"; for (auto& it: sam->GetSessions ()) { auto& name = it.second->GetLocalDestination ()->GetNickname (); @@ -847,30 +861,30 @@ namespace http { s << "
    \r\n"; } else - s << "SAM Sessions: no sessions currently running.
    \r\n"; + s << "" << tr("SAM sessions") << ": " << tr("no sessions currently running") << ".
    \r\n"; } void ShowSAMSession (std::stringstream& s, const std::string& id) { auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { - ShowError(s, "SAM disabled"); + ShowError(s, tr("SAM disabled")); return; } auto session = sam->FindSession (id); if (!session) { - ShowError(s, "SAM session not found"); + ShowError(s, tr("SAM session not found")); return; } std::string webroot; i2p::config::GetOption("http.webroot", webroot); - s << "SAM Session:
    \r\n
    \r\n"; + s << "" << tr("SAM Session") << ":
    \r\n
    \r\n"; auto& ident = session->GetLocalDestination ()->GetIdentHash(); s << "\r\n"; s << "
    \r\n"; - s << "Streams:
    \r\n
    \r\n"; + s << "" << tr("Streams") << ":
    \r\n
    \r\n"; for (const auto& it: sam->ListSockets(id)) { s << "
    "; @@ -879,7 +893,7 @@ namespace http { case i2p::client::eSAMSocketTypeSession : s << "session"; break; case i2p::client::eSAMSocketTypeStream : s << "stream"; break; case i2p::client::eSAMSocketTypeAcceptor : s << "acceptor"; break; - case i2p::client::eSAMSocketTypeForward : s << "forward"; break; + case i2p::client::eSAMSocketTypeForward : s << "forward"; break; default: s << "unknown"; break; } s << " [" << it->GetSocket ().remote_endpoint() << "]"; @@ -891,7 +905,7 @@ namespace http { void ShowI2PTunnels (std::stringstream& s) { std::string webroot; i2p::config::GetOption("http.webroot", webroot); - s << "Client Tunnels:
    \r\n
    \r\n"; + s << "" << tr("Client Tunnels") << ":
    \r\n
    \r\n"; for (auto& it: i2p::client::context.GetClientTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); @@ -905,7 +919,7 @@ namespace http { { auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); s << "
    "; - s << "HTTP Proxy" << " ⇐ "; + s << "HTTP " << tr("Proxy") << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
    \r\n"<< std::endl; } @@ -914,7 +928,7 @@ namespace http { { auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); s << "
    "; - s << "SOCKS Proxy" << " ⇐ "; + s << "SOCKS " << tr("Proxy") << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
    \r\n"<< std::endl; } @@ -922,7 +936,7 @@ namespace http { auto& serverTunnels = i2p::client::context.GetServerTunnels (); if (!serverTunnels.empty ()) { - s << "
    \r\nServer Tunnels:
    \r\n
    \r\n"; + s << "
    \r\n" << tr("Server Tunnels") << ":
    \r\n
    \r\n"; for (auto& it: serverTunnels) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); @@ -938,7 +952,7 @@ namespace http { auto& clientForwards = i2p::client::context.GetClientForwards (); if (!clientForwards.empty ()) { - s << "
    \r\nClient Forwards:
    \r\n
    \r\n"; + s << "
    \r\n" << tr("Client Forwards") << ":
    \r\n
    \r\n"; for (auto& it: clientForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); @@ -952,7 +966,7 @@ namespace http { auto& serverForwards = i2p::client::context.GetServerForwards (); if (!serverForwards.empty ()) { - s << "
    \r\nServer Forwards:
    \r\n
    \r\n"; + s << "
    \r\n" << tr("Server Forwards") << ":
    \r\n
    \r\n"; for (auto& it: serverForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); @@ -1084,7 +1098,7 @@ namespace http { return; } } - // Html5 head start + // HTML head start ShowPageHead (s); if (req.uri.find("page=") != std::string::npos) { HandlePage (req, res, s); @@ -1158,7 +1172,7 @@ namespace http { ShowLeasesSets(s); else { res.code = 400; - ShowError(s, "Unknown page: " + page); + ShowError(s, tr("Unknown page") + ": " + page); return; } } @@ -1177,7 +1191,7 @@ namespace http { if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ()) { - ShowError(s, "Invalid token"); + ShowError(s, tr("Invalid token")); return; } @@ -1235,18 +1249,18 @@ namespace http { if (dest) { if(dest->DeleteStream (streamID)) - s << "SUCCESS: Stream closed
    \r\n
    \r\n"; + s << "" << tr("SUCCESS") << ": " << tr("Stream closed") << "
    \r\n
    \r\n"; else - s << "ERROR: Stream not found or already was closed
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("Stream not found or already was closed") << "
    \r\n
    \r\n"; } else - s << "ERROR: Destination not found
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("Destination not found") << "
    \r\n
    \r\n"; } else - s << "ERROR: StreamID can be null
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("StreamID can't be null") << "
    \r\n
    \r\n"; - s << "Return to destination page
    \r\n"; - s << "

    You will be redirected back in 5 seconds"; + s << "" << tr("Return to destination page") << "
    \r\n"; + s << "

    " << tr("You will be redirected back in 5 seconds") << ""; redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32; res.add_header("Refresh", redirect.c_str()); return; @@ -1257,9 +1271,9 @@ namespace http { if (limit > 0 && limit <= 65535) SetMaxNumTransitTunnels (limit); else { - s << "ERROR: Transit tunnels count must not exceed 65535\r\n
    \r\n
    \r\n"; - s << "Back to commands list\r\n
    \r\n"; - s << "

    You will be redirected back in 5 seconds"; + s << "" << tr("ERROR") << ": " << tr("Transit tunnels count must not exceed 65535") << "\r\n
    \r\n
    \r\n"; + s << "" << tr("Back to commands list") << "\r\n
    \r\n"; + s << "

    " << tr("You will be redirected back in 5 seconds") << ""; res.add_header("Refresh", redirect.c_str()); return; } @@ -1292,37 +1306,37 @@ namespace http { auto len = i2p::data::ByteStreamToBase64 (signature, signatureLen, sig, signatureLen*2); sig[len] = 0; out << "#!sig=" << sig; - s << "SUCCESS:
    \r\n

    \r\n" + s << "" << tr("SUCCESS") << ":
    \r\n\r\n" "\r\n
    \r\n
    \r\n" - "Register at reg.i2p:\r\n
    \r\n" - "Description:\r\n\r\n" - "\r\n" + "" << tr("Register at reg.i2p") << ":\r\n
    \r\n" + "" << tr("Description") << ":\r\n\r\n" + "\r\n" "
    \r\n
    \r\n"; delete[] signature; delete[] sig; } else - s << "ERROR: Domain can't end with .b32.i2p\r\n
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("Domain can't end with .b32.i2p") << "\r\n
    \r\n
    \r\n"; } else - s << "ERROR: Domain must end with .i2p\r\n
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("Domain must end with .i2p") << "\r\n
    \r\n
    \r\n"; } else - s << "ERROR: Such destination is not found\r\n
    \r\n
    \r\n"; + s << "" << tr("ERROR") << ": " << tr("Such destination is not found") << "\r\n
    \r\n
    \r\n"; - s << "Return to destination page\r\n"; + s << "" << tr("Return to destination page") << "\r\n"; return; } else { res.code = 400; - ShowError(s, "Unknown command: " + cmd); + ShowError(s, tr("Unknown command") + ": " + cmd); return; } - s << "SUCCESS: Command accepted

    \r\n"; - s << "Back to commands list
    \r\n"; - s << "

    You will be redirected in 5 seconds"; + s << "" << tr("SUCCESS") << ": " << tr("Command accepted") << "

    \r\n"; + s << "" << tr("Back to commands list") << "
    \r\n"; + s << "

    " << tr("You will be redirected in 5 seconds") << ""; res.add_header("Refresh", redirect.c_str()); } diff --git a/i18n/russian.cpp b/i18n/russian.cpp index feb6fc63..71f27613 100644 --- a/i18n/russian.cpp +++ b/i18n/russian.cpp @@ -52,16 +52,170 @@ namespace russian { // language {"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"}, {"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"}, {"Host is down", "Адрес недоступен"}, - {"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному адресу, возможно он не в сети. Попробуйте повторить запрос позже."}, + {"Can't create connection to requested host, it may be down. Please try again later.", + "Не удалось установить соединение к запрошенному адресу, возможно он не в сети. Попробуйте повторить запрос позже."}, + + // Webconsole // + // cssStyles + {"Disabled", "Выключено"}, + {"Enabled", "Включено"}, + // ShowTraffic + {"KiB", "КиБ"}, + {"MiB", "МиБ"}, + {"GiB", "ГиБ"}, + // ShowTunnelDetails + {"building", "строится"}, + {"failed", "неудачный"}, + {"expiring", "заканчивается"}, + {"established", "работает"}, + {"exploratory", "исследовательский"}, + {"unknown", "неизвестно"}, + {"i2pd webconsole", "Веб-консоль i2pd"}, + // ShowPageHead + {"Main page", "Главная"}, + {"Router commands", "Команды роутера"}, + {"Local destinations", "Локальные назнач."}, + {"LeaseSets", "Лизсеты"}, + {"Tunnels", "Туннели"}, + {"Transit tunnels", "Транзит. туннели"}, + {"Transports", "Транспорты"}, + {"I2P tunnels", "I2P туннели"}, + {"SAM sessions", "SAM сессии"}, + // Network Status + {"OK", "OK"}, + {"Testing", "Тестирование"}, + {"Firewalled", "Файрвол"}, + {"Unknown", "Неизвестно"}, + {"Proxy", "Прокси"}, + {"Mesh", "MESH-сеть"}, + {"Error", "Ошибка"}, + {"Clock skew", "Не точное время"}, + {"Offline", "Оффлайн"}, + {"Symmetric NAT", "Симметричный NAT"}, + // Status + {"Uptime", "В сети"}, + {"Network status", "Сетевой статус"}, + {"Network status v6", "Сетевой статус v6"}, + {"Stopping in", "Остановка через"}, + {"Family", "Семейство"}, + {"Tunnel creation success rate", "Успешно построенных туннелей"}, + {"Received", "Получено"}, + {"Sent", "Отправлено"}, + {"Transit", "Транзит"}, + {"KiB/s", "КиБ/с"}, + {"Data path", "Путь к данным"}, + {"Hidden content. Press on text to see.", "Скрытый контент. Нажмите на текст чтобы отобразить."}, + {"Router Ident", "Идентификатор роутера"}, + {"Router Family", "Семейство роутера"}, + {"Router Caps", "Флаги роутера"}, + {"Version", "Версия"}, + {"Our external address", "Наш внешний адрес"}, + {"supported", "поддерживается"}, + {"Routers", "Роутеры"}, + {"Floodfills", "Флудфилы"}, + {"LeaseSets", "Лизсеты"}, + {"Client Tunnels", "Клиентские туннели"}, + {"Transit Tunnels", "Транзитные туннели"}, + {"Services", "Сервисы"}, + // ShowLocalDestinations + {"Local Destinations", "Локальные назначения"}, + // ShowLeaseSetDestination + {"Encrypted B33 address", "Шифрованные B33 адреса"}, + {"Address registration line", "Строка регистрации адреса"}, + {"Domain", "Домен"}, + {"Generate", "Сгенерировать"}, + {"Address", "Адрес"}, + {"Type", "Тип"}, + {"EncType", "ТипШифр"}, + {"Inbound tunnels", "Входящие туннели"}, + {"Outbound tunnels", "Исходящие туннели"}, + {"ms", "мс"}, // milliseconds + {"Tags", "Теги"}, + {"Incoming", "Входящие"}, + {"Outgoing", "Исходящие"}, + {"Destination", "Назначение"}, + {"Amount", "Количество"}, + {"Incoming Tags", "Входящие Теги"}, + {"Tags sessions", "Сессии Тегов"}, + {"Status", "Статус"}, + // ShowLocalDestination + {"Local Destination", "Локальное назначение"}, + {"Streams", "Стримы"}, + {"Close stream", "Закрыть стрим"}, + // ShowI2CPLocalDestination + {"I2CP session not found", "I2CP сессия не найдена"}, + {"I2CP is not enabled", "I2CP не включен"}, + // ShowLeasesSets + {"Invalid", "Некорректный"}, + {"Store type", "Тип хранилища"}, + {"Expires", "Истекает"}, + {"Non Expired Leases", "Не истекшие Lease-ы"}, + {"Gateway", "Шлюз"}, + {"TunnelID", "ID туннеля"}, + {"EndDate", "Заканчивается"}, + {"not floodfill", "не флудфил"}, + // ShowTunnels + {"Queue size", "Размер очереди"}, + // ShowCommands + {"Run peer test", "Запустить тестирование"}, + {"Decline transit tunnels", "Отклонять транзитные туннели"}, + {"Accept transit tunnels", "Принимать транзитные туннели"}, + {"Cancel graceful shutdown", "Отменить плавную остановку"}, + {"Start graceful shutdown", "Запустить плавную остановку"}, + {"Force shutdown", "Принудительная остановка"}, + {"Note: any action done here are not persistent and not changes your config files.", + "Примечание: любое действие произведенное здесь не является постоянным и не изменяет ваши конфигурационные файлы."}, + {"Logging level", "Уровень логирования"}, + {"Transit tunnels limit", "Лимит транзитных туннелей"}, + {"Change", "Изменить"}, + // ShowTransitTunnels + {"no transit tunnels currently built", "нет построенных транзитных туннелей"}, + // ShowSAMSessions/ShowSAMSession + {"SAM disabled", "SAM выключен"}, + {"SAM session not found", "SAM сессия не найдена"}, + {"no sessions currently running", "нет запущенных сессий"}, + {"SAM Session", "SAM сессия"}, + // ShowI2PTunnels + {"Server Tunnels", "Серверные туннели"}, + {"Client Forwards", "Клиентские переадресации"}, + {"Server Forwards", "Серверные переадресации"}, + // HandlePage + {"Unknown page", "Неизвестная страница"}, + // HandleCommand, ShowError + {"Invalid token", "Неверный токен"}, + {"SUCCESS", "УСПЕШНО"}, + {"ERROR", "ОШИБКА"}, + {"Unknown command", "Неизвестная команда"}, + {"Command accepted", "Команда принята"}, + {"Back to commands list", "Вернуться к списку команд"}, + {"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"}, + // HTTP_COMMAND_KILLSTREAM + {"Stream closed", "Стрим закрыт"}, + {"Stream not found or already was closed", "Стрим не найден или уже закрыт"}, + {"Destination not found", "Точка назначения не найдена"}, + {"StreamID can't be null", "StreamID не может быть пустым"}, + {"Return to destination page", "Вернуться на страницу точки назначения"}, + {"You will be redirected back in 5 seconds", "Вы будете переадресованы назад через 5 секунд"}, + // HTTP_COMMAND_LIMITTRANSIT + {"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"}, + // HTTP_COMMAND_GET_REG_STRING + {"Register at reg.i2p", "Зарегистрировать на reg.i2p"}, + {"Description", "Описание"}, + {"A bit information about service on domain", "Немного информации о сервисе на домене"}, + {"Submit", "Отправить"}, + {"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"}, + {"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"}, + {"Such destination is not found", "Такая точка назначения не найдена"}, {"", ""}, }; static std::map> plurals { + // ShowUptime {"days", {"день", "дня", "дней"}}, {"hours", {"час", "часа", "часов"}}, - {"minutes", {"минута", "минуты", "минут"}}, - {"seconds", {"секунда", "секунды", "секунд"}}, + {"minutes", {"минуту", "минуты", "минут"}}, + {"seconds", {"секунду", "секунды", "секунд"}}, {"", {"", ""}}, }; From a4b84517dc66267354a962ca7f1487b8ded14cf2 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 10:56:20 +0300 Subject: [PATCH 07/64] [i18n] rename Russian translation, fix typo Signed-off-by: R4SAS --- i18n/{russian.cpp => Russian.cpp} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename i18n/{russian.cpp => Russian.cpp} (99%) diff --git a/i18n/russian.cpp b/i18n/Russian.cpp similarity index 99% rename from i18n/russian.cpp rename to i18n/Russian.cpp index 71f27613..d208e18f 100644 --- a/i18n/russian.cpp +++ b/i18n/Russian.cpp @@ -66,7 +66,7 @@ namespace russian { // language // ShowTunnelDetails {"building", "строится"}, {"failed", "неудачный"}, - {"expiring", "заканчивается"}, + {"expiring", "истекает"}, {"established", "работает"}, {"exploratory", "исследовательский"}, {"unknown", "неизвестно"}, From 2db035d23cff8ca17b6ec78d4e8e9a3295968fa7 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 13:16:52 +0300 Subject: [PATCH 08/64] [i18n] fix addresshelper Signed-off-by: R4SAS --- libi2pd_client/HTTPProxy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index aff165b0..d8b84e82 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -217,7 +217,8 @@ namespace proxy { b64 = i2p::http::UrlDecode(value); // if we need update exists, request formed with update param if (params["update"] == "true") { len += std::strlen("&update=true"); confirm = true; } - url.query.replace(pos - 1, len + 1, ""); // +-1 for taking ? and & before parameter + if (pos != 0 && url.query[pos-1] == '&') { pos--; len++; } // if helper is not only one query option + url.query.replace(pos, len, ""); return true; } From 919bf4e144a838a73e4561119fe0b5bc7723e571 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 15:39:29 +0300 Subject: [PATCH 09/64] [i18n] add cmake build Signed-off-by: R4SAS --- build/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 6f9fbae6..f6d69b04 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -33,10 +33,12 @@ target_architecture(ARCHITECTURE) set(LIBI2PD_SRC_DIR ../libi2pd) set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client) +set(LANG_SRC_DIR ../i18n) set(DAEMON_SRC_DIR ../daemon) include_directories(${LIBI2PD_SRC_DIR}) include_directories(${LIBI2PD_CLIENT_SRC_DIR}) +include_directories(${LANG_SRC_DIR}) include_directories(${DAEMON_SRC_DIR}) set(LIBI2PD_SRC @@ -126,6 +128,11 @@ if(WITH_LIBRARY) COMPONENT Libraries) endif() +set(LANG_SRC + "${LANG_SRC_DIR}/English.cpp" + "${LANG_SRC_DIR}/Russian.cpp" +) + set(DAEMON_SRC "${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/HTTPServer.cpp" @@ -321,7 +328,7 @@ message(STATUS "---------------------------------------") include(GNUInstallDirs) if(WITH_BINARY) - add_executable("${PROJECT_NAME}" ${DAEMON_SRC}) + add_executable("${PROJECT_NAME}" ${LANG_SRC} ${DAEMON_SRC}) if(WITH_STATIC) set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static") From 5207dd4c9eb9178cd0e0867693a359cc91712e3d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 15:43:04 +0300 Subject: [PATCH 10/64] [gha] update freebsd action --- .github/workflows/build-freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-freebsd.yml b/.github/workflows/build-freebsd.yml index 4e31bed7..c6e0addf 100644 --- a/.github/workflows/build-freebsd.yml +++ b/.github/workflows/build-freebsd.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - name: Test in FreeBSD id: test - uses: vmactions/freebsd-vm@v0.1.2 + uses: vmactions/freebsd-vm@v0.1.4 with: usesh: true prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc From 69a0fe3040325cbe8c554609d9ec0a2fd617bf82 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 May 2021 08:52:27 -0400 Subject: [PATCH 11/64] pass arg as reference --- i18n/I18N.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/i18n/I18N.h b/i18n/I18N.h index cb3e5c1c..8ce2aa84 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -15,24 +15,30 @@ namespace i2p { namespace i18n { - inline std::string translate (std::string arg) + inline std::string translate (const std::string& arg) { switch (i2p::context.GetLanguage ()) { - case eEnglish: return i2p::i18n::english::GetString (arg); - case eRussian: return i2p::i18n::russian::GetString (arg); - default: return arg; + case eEnglish: + return i2p::i18n::english::GetString (arg); + case eRussian: + return i2p::i18n::russian::GetString (arg); + default: + return arg; } } template - std::string translate (std::string arg, inttype&& n) + std::string translate (const std::string& arg, inttype&& n) { switch (i2p::context.GetLanguage ()) { - case eEnglish: return i2p::i18n::english::GetPlural (arg, (int) n); - case eRussian: return i2p::i18n::russian::GetPlural (arg, (int) n); - default: return arg; + case eEnglish: + return i2p::i18n::english::GetPlural (arg, (int) n); + case eRussian: + return i2p::i18n::russian::GetPlural (arg, (int) n); + default: + return arg; } } From b676d7034f2e784c06c7ffa45f2527545b5bf971 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 23 May 2021 16:30:42 +0300 Subject: [PATCH 12/64] [i18n] update translation Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 2 +- i18n/Russian.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 22cefedd..e184dd06 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -455,7 +455,7 @@ namespace http { " \r\n" " " << tr("Domain") << ":\r\n\r\n" " \r\n" - "\r\nNote: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.\r\n

    \r\n
    \r\n
    \r\n"; + "\r\n" << tr("Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "\r\n
    \r\n
    \r\n
    \r\n"; } if(dest->GetNumRemoteLeaseSets()) diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index d208e18f..033ee33d 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -124,6 +124,8 @@ namespace russian { // language {"Address registration line", "Строка регистрации адреса"}, {"Domain", "Домен"}, {"Generate", "Сгенерировать"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", + "Примечание: полученная строка может быть использована только для регистрации доменов второго уровня. Для регистрации поддоменов используйте i2pd-tools."}, {"Address", "Адрес"}, {"Type", "Тип"}, {"EncType", "ТипШифр"}, From 585116a51f9557038f49630ea4b41d25b47e010c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 May 2021 14:20:23 -0400 Subject: [PATCH 13/64] XMR added --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d21df6e7..1aa96fb0 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG +XMR: 497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH License ------- From d06924b33940170bc6209f5c51b8b38f35e35e2a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 May 2021 14:28:10 -0400 Subject: [PATCH 14/64] LeaseSet type 3 by default --- libi2pd/Destination.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 6e149cf5..40c9e9ab 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -62,7 +62,7 @@ namespace client const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname"; const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname"; const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType"; - const int DEFAULT_LEASESET_TYPE = 1; + const int DEFAULT_LEASESET_TYPE = 3; const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType"; const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; From 08fafe267add1de917b2cca1dba1de3efb7e2c0c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 May 2021 17:27:14 -0400 Subject: [PATCH 15/64] rekey all routers to ECIES --- libi2pd/RouterContext.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 0cfcb18a..78f63137 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -736,14 +736,8 @@ namespace i2p } } std::shared_ptr oldIdentity; - bool rekey = m_Keys.GetPublic ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; - if (!rekey && m_Keys.GetPublic ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) - { - // rekey routers with bandwidth = L (or default) this time - bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); - if (!isFloodfill) rekey = true; - } - if (rekey) + if (m_Keys.GetPublic ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1 || + m_Keys.GetPublic ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) { // update keys LogPrint (eLogInfo, "Router: router keys are obsolete. Creating new"); From 1a4250d8cc60afb55e06b5244ca1335c5ef4d20b Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 25 May 2021 00:22:28 +0300 Subject: [PATCH 16/64] [i18n] update russian translation Signed-off-by: R4SAS --- i18n/Russian.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 033ee33d..489bee7b 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -179,8 +179,8 @@ namespace russian { // language {"SAM Session", "SAM сессия"}, // ShowI2PTunnels {"Server Tunnels", "Серверные туннели"}, - {"Client Forwards", "Клиентские переадресации"}, - {"Server Forwards", "Серверные переадресации"}, + {"Client Forwards", "Клиентские перенаправления"}, + {"Server Forwards", "Серверные перенаправления"}, // HandlePage {"Unknown page", "Неизвестная страница"}, // HandleCommand, ShowError From 779f2fa451ac759d9de88820898025ce7c71ec30 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 25 May 2021 22:03:29 +0300 Subject: [PATCH 17/64] [i18n] rework localization system Signed-off-by: R4SAS --- daemon/Daemon.cpp | 6 ++-- i18n/English.cpp | 52 +++++++++++++++------------------- i18n/I18N.h | 38 ++++++++++--------------- i18n/I18N_langs.h | 59 +++++++++++++++++++++++++++++---------- i18n/Russian.cpp | 46 +++++++++++++----------------- libi2pd/RouterContext.cpp | 7 +---- libi2pd/RouterContext.h | 12 ++++---- 7 files changed, 111 insertions(+), 109 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index ec62f5d6..f7f2ef2f 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -32,6 +32,7 @@ #include "UPnP.h" #include "Timestamp.h" #include "util.h" +#include "I18N.h" namespace i2p { @@ -345,10 +346,7 @@ namespace util } std::string httpLang; i2p::config::GetOption("http.lang", httpLang); - if (!httpLang.compare("russian")) - i2p::context.SetLanguage (eRussian); - else - i2p::context.SetLanguage (eEnglish); + i2p::i18n::SetLanguage(httpLang); return true; } diff --git a/i18n/English.cpp b/i18n/English.cpp index 8664a0f0..8b13279a 100644 --- a/i18n/English.cpp +++ b/i18n/English.cpp @@ -1,23 +1,34 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + #include #include #include +#include +#include "I18N.h" -// Russian localization file - -namespace i2p { -namespace i18n { -namespace english { // language +// English localization file +namespace i2p +{ +namespace i18n +{ +namespace english // language +{ // See for language plural forms here: // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html - int plural (int n) { + static int plural (int n) { return n != 1 ? 1 : 0; } static std::map strings { - {"Enabled", "Enabled"}, - {"Disabled", "Disabled"} + {"", ""}, }; static std::map> plurals @@ -25,30 +36,13 @@ namespace english { // language {"days", {"day", "days"}}, {"hours", {"hour", "hours"}}, {"minutes", {"minute", "minutes"}}, - {"seconds", {"second", "seconds"}} + {"seconds", {"second", "seconds"}}, + {"", {"", ""}}, }; - std::string GetString (std::string arg) + std::shared_ptr GetLocale() { - auto it = strings.find(arg); - if (it == strings.end()) - { - return arg; - } else { - return it->second; - } - } - - std::string GetPlural (std::string arg, int n) - { - auto it = plurals.find(arg); - if (it == plurals.end()) - { - return arg; - } else { - int form = plural(n); - return it->second[form]; - } + return std::make_shared(strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/I18N.h b/i18n/I18N.h index 8ce2aa84..ccb8f413 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -11,37 +11,27 @@ #include "RouterContext.h" - -namespace i2p { -namespace i18n { +namespace i2p +{ +namespace i18n +{ + inline void SetLanguage(const std::string &lang) + { + if (!lang.compare("russian")) + i2p::context.SetLanguage (i2p::i18n::russian::GetLocale()); + else + i2p::context.SetLanguage (i2p::i18n::english::GetLocale()); + } inline std::string translate (const std::string& arg) { - switch (i2p::context.GetLanguage ()) - { - case eEnglish: - return i2p::i18n::english::GetString (arg); - case eRussian: - return i2p::i18n::russian::GetString (arg); - default: - return arg; - } + return i2p::context.GetLanguage ()->GetString (arg); } - template - std::string translate (const std::string& arg, inttype&& n) + inline std::string translate (const std::string& arg, const int& n) { - switch (i2p::context.GetLanguage ()) - { - case eEnglish: - return i2p::i18n::english::GetPlural (arg, (int) n); - case eRussian: - return i2p::i18n::russian::GetPlural (arg, (int) n); - default: - return arg; - } + return i2p::context.GetLanguage ()->GetPlural (arg, n); } - } // i18n } // i2p diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 24c683b4..07bdc087 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -9,24 +9,55 @@ #ifndef __I18N_LANGS_H__ #define __I18N_LANGS_H__ -namespace i2p { +namespace i2p +{ +namespace i18n +{ + class Locale + { + public: + Locale ( + const std::map& strings, + const std::map>& plurals, + std::function formula + ): m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; -enum Lang { - eEnglish = 0, - eRussian -}; + std::string GetString (const std::string& arg) const + { + const auto it = m_Strings.find(arg); + if (it == m_Strings.end()) + { + return arg; + } + else + { + return it->second; + } + } -namespace i18n { + std::string GetPlural (const std::string& arg, const int& n) const + { + const auto it = m_Plurals.find(arg); + if (it == m_Plurals.end()) + { + return arg; + } + else + { + int form = m_Formula(n); + return it->second[form]; + } + } - namespace english { - std::string GetString (std::string arg); - std::string GetPlural (std::string arg, int n); - } + private: + const std::map m_Strings; + const std::map> m_Plurals; + std::function m_Formula; + }; - namespace russian { - std::string GetString (std::string arg); - std::string GetPlural (std::string arg, int n); - } + // Add localization here with language name as namespace + namespace english { std::shared_ptr GetLocale (); } + namespace russian { std::shared_ptr GetLocale (); } } // i18n } // i2p diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 489bee7b..1f2c25da 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -1,16 +1,28 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + #include #include #include +#include +#include "I18N.h" // Russian localization file -namespace i2p { -namespace i18n { -namespace russian { // language - +namespace i2p +{ +namespace i18n +{ +namespace russian // language +{ // See for language plural forms here: // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html - int plural (int n) { + static int plural (int n) { return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; } @@ -218,30 +230,12 @@ namespace russian { // language {"hours", {"час", "часа", "часов"}}, {"minutes", {"минуту", "минуты", "минут"}}, {"seconds", {"секунду", "секунды", "секунд"}}, - {"", {"", ""}}, + {"", {"", "", ""}}, }; - std::string GetString (std::string arg) + std::shared_ptr GetLocale() { - auto it = strings.find(arg); - if (it == strings.end()) - { - return arg; - } else { - return it->second; - } - } - - std::string GetPlural (std::string arg, int n) - { - auto it = plurals.find(arg); - if (it == plurals.end()) - { - return arg; - } else { - int form = plural(n); - return it->second[form]; - } + return std::make_shared(strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 78f63137..664b457c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -29,7 +29,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), - m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID), m_Language (eEnglish) + m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -910,11 +910,6 @@ namespace i2p } } - void RouterContext::SetLanguage (Lang language) - { - m_Language = language; - } - i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () { if (!m_StaticKeys) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 1cb77a74..ee34c2d8 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -99,7 +99,7 @@ namespace garlic bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); void UpdatePort (int port); // called from Daemon - void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon + void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); void UpdateNTCP2Address (bool enable); void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later @@ -125,11 +125,11 @@ namespace garlic void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; std::unique_ptr& GetCurrentNoiseState () { return m_CurrentNoiseState; }; - + void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateStats (); void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing - void CleanupDestination (); // garlic destination + void CleanupDestination (); // garlic destination // implements LocalDestination std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; @@ -146,8 +146,8 @@ namespace garlic void ProcessDeliveryStatusMessage (std::shared_ptr msg); // i18n - Lang GetLanguage () const { return m_Language; }; - void SetLanguage (Lang language); + std::shared_ptr GetLanguage () { return m_Language; }; + void SetLanguage (const std::shared_ptr language) { m_Language = language; }; protected: @@ -185,7 +185,7 @@ namespace garlic std::unique_ptr m_InitialNoiseState, m_CurrentNoiseState; // i18n - Lang m_Language; + std::shared_ptr m_Language; }; extern RouterContext context; From 0275f7f574b03e2ac8b2f7d1797d7437336bc8e1 Mon Sep 17 00:00:00 2001 From: Artem M Date: Wed, 26 May 2021 10:05:10 +0300 Subject: [PATCH 18/64] [i18n] fix two typos in the russian translation (#1659) --- i18n/Russian.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 1f2c25da..28e07cc1 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -39,7 +39,7 @@ namespace russian // language {"addresshelper is not supported", "addresshelper не поддерживается"}, {"Host", "Адрес"}, {"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"}, - {"already in router's addressbook", "уже а адресной книге роутера"}, + {"already in router's addressbook", "уже в адресной книге роутера"}, {"Click", "Нажмите"}, {"here", "здесь"}, {"to proceed", "чтобы продолжить"}, @@ -51,7 +51,7 @@ namespace russian // language {"bad outproxy settings", "некорректные настройки внешнего прокси"}, {"not inside I2P network, but outproxy is not enabled", "не в I2P сети, но внешний прокси не включен"}, {"unknown outproxy url", "неизвестный URL внешнего прокси"}, - {"cannot resolve upstream proxy", "не удается определить внешний прокси"}, + {"cannot resolve upstream proxy", "не удается определить вышестоящий прокси"}, {"hostname too long", "имя хоста слишком длинное"}, {"cannot connect to upstream socks proxy", "не удается подключиться к вышестоящему SOCKS прокси"}, {"Cannot negotiate with socks proxy", "Не удается договориться с вышестоящим SOCKS прокси"}, From bdf63cf82ca38a97e08f7c1cf278664844bd12a0 Mon Sep 17 00:00:00 2001 From: Artem M Date: Wed, 26 May 2021 10:38:58 +0300 Subject: [PATCH 19/64] [i18n] add Ukrainian (#1658) --- i18n/Ukrainian.cpp | 243 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 i18n/Ukrainian.cpp diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp new file mode 100644 index 00000000..94c61d80 --- /dev/null +++ b/i18n/Ukrainian.cpp @@ -0,0 +1,243 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Russian localization file + +namespace i2p +{ +namespace i18n +{ +namespace ukrainian // language +{ + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + } + + static std::map strings + { + // HTTP Proxy + {"Proxy error", "Помилка проксі"}, + {"Proxy info", "Інформація проксі"}, + {"Proxy error: Host not found", "Помилка проксі: Адреса не знайдена"}, + {"Remote host not found in router's addressbook", "Віддалена адреса не знайдена в адресній книзі роутера"}, + {"You may try to find this host on jump services below", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"}, + {"Invalid request", "Некоректний запит"}, + {"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"}, + {"addresshelper is not supported", "addresshelper не підтримується"}, + {"Host", "Адреса"}, + {"added to router's addressbook from helper", "доданий в адресну книгу роутера через хелпер"}, + {"already in router's addressbook", "вже в адресній книзі роутера"}, + {"Click", "Натисніть"}, + {"here", "тут"}, + {"to proceed", "щоб продовжити"}, + {"to update record", "щоб оновити запис"}, + {"Addresshelper found", "Знайдено addresshelper"}, + {"invalid request uri", "некоректний URI запиту"}, + {"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"}, + {"Outproxy failure", "Помилка зовнішнього проксі"}, + {"bad outproxy settings", "некоректні налаштування зовнішнього проксі"}, + {"not inside I2P network, but outproxy is not enabled", "не в I2P мережі, але зовнішній проксі не включений"}, + {"unknown outproxy url", "невідомий URL зовнішнього проксі"}, + {"cannot resolve upstream proxy", "не вдається визначити висхідний проксі"}, + {"hostname too long", "ім'я вузла надто довге"}, + {"cannot connect to upstream socks proxy", "не вдається підключитися до висхідного SOCKS проксі"}, + {"Cannot negotiate with socks proxy", "Не вдається домовитися з висхідним SOCKS проксі"}, + {"CONNECT error", "Помилка CONNECT запиту"}, + {"Failed to Connect", "Не вдалося підключитися"}, + {"socks proxy error", "помилка SOCKS проксі"}, + {"failed to send request to upstream", "не вдалося відправити запит висхідному проксі"}, + {"No Reply From socks proxy", "Немає відповіді від SOCKS проксі сервера"}, + {"cannot connect", "не вдалося підключитися"}, + {"http out proxy not implemented", "підтримка зовнішнього HTTP проксі сервера не реалізована"}, + {"cannot connect to upstream http proxy", "не вдалося підключитися до висхідного HTTP проксі сервера"}, + {"Host is down", "Вузол недоступний"}, + {"Can't create connection to requested host, it may be down. Please try again later.", + "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."}, + + // Webconsole // + // cssStyles + {"Disabled", "Вимкнуто"}, + {"Enabled", "Увімкнуто"}, + // ShowTraffic + {"KiB", "КіБ"}, + {"MiB", "МіБ"}, + {"GiB", "ГіБ"}, + // ShowTunnelDetails + {"building", "будується"}, + {"failed", "невдалий"}, + {"expiring", "завершується"}, + {"established", "працює"}, + {"exploratory", "дослідницький"}, + {"unknown", "невідомо"}, + {"i2pd webconsole", "Веб-консоль i2pd"}, + // ShowPageHead + {"Main page", "Головна"}, + {"Router commands", "Команди роутера"}, + {"Local destinations", "Локальні признач."}, + {"LeaseSets", "Лізсети"}, + {"Tunnels", "Тунелі"}, + {"Transit tunnels", "Транзит. тунелі"}, + {"Transports", "Транспорти"}, + {"I2P tunnels", "I2P тунелі"}, + {"SAM sessions", "SAM сесії"}, + // Network Status + {"OK", "OK"}, + {"Testing", "Тестування"}, + {"Firewalled", "Файрвол"}, + {"Unknown", "Невідомо"}, + {"Proxy", "Проксі"}, + {"Mesh", "MESH-мережа"}, + {"Error", "Помилка"}, + {"Clock skew", "Неточний час"}, + {"Offline", "Офлайн"}, + {"Symmetric NAT", "Симетричний NAT"}, + // Status + {"Uptime", "В мережі"}, + {"Network status", "Мережевий статус"}, + {"Network status v6", "Мережевий статус v6"}, + {"Stopping in", "Зупинка через"}, + {"Family", "Сімейство"}, + {"Tunnel creation success rate", "Успішно побудованих тунелів"}, + {"Received", "Отримано"}, + {"Sent", "Відправлено"}, + {"Transit", "Транзит"}, + {"KiB/s", "КіБ/с"}, + {"Data path", "Шлях до даних"}, + {"Hidden content. Press on text to see.", "Прихований вміст. Натисніть на текст щоб відобразити."}, + {"Router Ident", "Ідентифікатор Роутера"}, + {"Router Family", "Сімейство Роутера"}, + {"Router Caps", "Прапорці Роутера"}, + {"Version", "Версія"}, + {"Our external address", "Наша зовнішня адреса"}, + {"supported", "підтримується"}, + {"Routers", "Роутери"}, + {"Floodfills", "Флудфіли"}, + {"LeaseSets", "Лізсети"}, + {"Client Tunnels", "Клієнтські Тунелі"}, + {"Transit Tunnels", "Транзитні Тунелі"}, + {"Services", "Сервіси"}, + // ShowLocalDestinations + {"Local Destinations", "Локальні Призначення"}, + // ShowLeaseSetDestination + {"Encrypted B33 address", "Шифровані B33 адреси"}, + {"Address registration line", "Рядок реєстрації адреси"}, + {"Domain", "Домен"}, + {"Generate", "Згенерувати"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", + "Примітка: отриманий рядок може бути використаний тільки для реєстрації доменів другого рівня. Для реєстрації піддоменів використовуйте i2pd-tools."}, + {"Address", "Адреса"}, + {"Type", "Тип"}, + {"EncType", "ТипШифр"}, + {"Inbound tunnels", "Вхідні тунелі"}, + {"Outbound tunnels", "Вихідні тунелі"}, + {"ms", "мс"}, // milliseconds + {"Tags", "Теги"}, + {"Incoming", "Вхідні"}, + {"Outgoing", "Вихідні"}, + {"Destination", "Призначення"}, + {"Amount", "Кількість"}, + {"Incoming Tags", "Вхідні Теги"}, + {"Tags sessions", "Сесії тегів"}, + {"Status", "Статус"}, + // ShowLocalDestination + {"Local Destination", "Локальне Призначення"}, + {"Streams", "Потоки"}, + {"Close stream", "Закрити потік"}, + // ShowI2CPLocalDestination + {"I2CP session not found", "I2CP сесія не знайдена"}, + {"I2CP is not enabled", "I2CP не увікнуто"}, + // ShowLeasesSets + {"Invalid", "Некоректний"}, + {"Store type", "Тип сховища"}, + {"Expires", "Завершується"}, + {"Non Expired Leases", "Не завершені Lease-и"}, + {"Gateway", "Шлюз"}, + {"TunnelID", "ID тунеля"}, + {"EndDate", "Закінчується"}, + {"not floodfill", "не флудфіл"}, + // ShowTunnels + {"Queue size", "Розмір черги"}, + // ShowCommands + {"Run peer test", "Запустити тестування"}, + {"Decline transit tunnels", "Відхиляти транзитні тунелі"}, + {"Accept transit tunnels", "Ухвалювати транзитні тунелі"}, + {"Cancel graceful shutdown", "Скасувати плавну зупинку"}, + {"Start graceful shutdown", "Запустити плавну зупинку"}, + {"Force shutdown", "Примусова зупинка"}, + {"Note: any action done here are not persistent and not changes your config files.", + "Примітка: будь-яка зроблена тут дія не є постійною та не змінює ваші конфігураційні файли."}, + {"Logging level", "Рівень логування"}, + {"Transit tunnels limit", "Обмеження транзитних тунелів"}, + {"Change", "Змінити"}, + // ShowTransitTunnels + {"no transit tunnels currently built", "немає побудованих транзитних тунелів"}, + // ShowSAMSessions/ShowSAMSession + {"SAM disabled", "SAM вимкнуто"}, + {"SAM session not found", "SAM сесія не знайдена"}, + {"no sessions currently running", "немає запущених сесій"}, + {"SAM Session", "SAM сесія"}, + // ShowI2PTunnels + {"Server Tunnels", "Серверні Тунелі"}, + {"Client Forwards", "Клієнтські Переспрямування"}, + {"Server Forwards", "Серверні Переспрямування"}, + // HandlePage + {"Unknown page", "Невідома сторінка"}, + // HandleCommand, ShowError + {"Invalid token", "Невірний токен"}, + {"SUCCESS", "ВДАЛО"}, + {"ERROR", "ПОМИЛКА"}, + {"Unknown command", "Невідома команда"}, + {"Command accepted", "Команда прийнята"}, + {"Back to commands list", "Повернутися до списку команд"}, + {"You will be redirected in 5 seconds", "Ви будете переадресовані через 5 секунд"}, + // HTTP_COMMAND_KILLSTREAM + {"Stream closed", "Потік зачинений"}, + {"Stream not found or already was closed", "Потік не знайдений або вже зачинений"}, + {"Destination not found", "Точка призначення не знайдена"}, + {"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"}, + {"Return to destination page", "Повернутися на сторінку точки призначення"}, + {"You will be redirected back in 5 seconds", "Ви будете переадресовані назад через 5 секунд"}, + // HTTP_COMMAND_LIMITTRANSIT + {"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"}, + // HTTP_COMMAND_GET_REG_STRING + {"Register at reg.i2p", "Зареєструвати на reg.i2p"}, + {"Description", "Опис"}, + {"A bit information about service on domain", "Трохи інформації про сервіс на домені"}, + {"Submit", "Надіслати"}, + {"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"}, + {"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"}, + {"Such destination is not found", "Така точка призначення не знайдена"}, + {"", ""}, + }; + + static std::map> plurals + { + // ShowUptime + {"days", {"день", "дня", "днів"}}, + {"hours", {"годину", "години", "годин"}}, + {"minutes", {"хвилину", "хвилини", "хвилин"}}, + {"seconds", {"секунду", "секунди", "секунд"}}, + {"", {"", "", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p From cc1244126cd6e526aa40e637d6e032ba102a1558 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 10:50:02 +0300 Subject: [PATCH 20/64] [i18n] enable Ukrainian in source Signed-off-by: R4SAS --- contrib/i2pd.conf | 2 +- i18n/I18N.h | 4 +++- i18n/I18N_langs.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 3c9c71ff..3b20a809 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -104,7 +104,7 @@ port = 7070 # user = i2pd # pass = changeme ## Select webconsole language -## Currently supported only english (default) and russian languages +## Currently supported english (default), russian and ukrainian languages # lang = english [httpproxy] diff --git a/i18n/I18N.h b/i18n/I18N.h index ccb8f413..a1a78b77 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -19,7 +19,9 @@ namespace i18n { if (!lang.compare("russian")) i2p::context.SetLanguage (i2p::i18n::russian::GetLocale()); - else + if (!lang.compare("ukrainian")) + i2p::context.SetLanguage (i2p::i18n::ukrainian::GetLocale()); + else // fallback i2p::context.SetLanguage (i2p::i18n::english::GetLocale()); } diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 07bdc087..c094cb79 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -58,6 +58,7 @@ namespace i18n // Add localization here with language name as namespace namespace english { std::shared_ptr GetLocale (); } namespace russian { std::shared_ptr GetLocale (); } + namespace ukrainian { std::shared_ptr GetLocale (); } } // i18n } // i2p From ebce1e34d8ff325e32f6871a66e8300ac5d10f55 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 12:56:47 +0300 Subject: [PATCH 21/64] [i18n] enable Ukrainian in source Signed-off-by: R4SAS --- build/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index f6d69b04..b96cfb6a 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -131,6 +131,7 @@ endif() set(LANG_SRC "${LANG_SRC_DIR}/English.cpp" "${LANG_SRC_DIR}/Russian.cpp" + "${LANG_SRC_DIR}/Ukrainian.cpp" ) set(DAEMON_SRC From 0292227a6b1c5330b04224ae6d4930ba8cb65854 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 13:15:17 +0300 Subject: [PATCH 22/64] [cmake] switch to glob instead filling sources list Signed-off-by: R4SAS --- build/CMakeLists.txt | 70 ++------------------------------------------ 1 file changed, 3 insertions(+), 67 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index b96cfb6a..d1b51f23 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -41,55 +41,7 @@ include_directories(${LIBI2PD_CLIENT_SRC_DIR}) include_directories(${LANG_SRC_DIR}) include_directories(${DAEMON_SRC_DIR}) -set(LIBI2PD_SRC - "${LIBI2PD_SRC_DIR}/api.cpp" - "${LIBI2PD_SRC_DIR}/Base.cpp" - "${LIBI2PD_SRC_DIR}/Blinding.cpp" - "${LIBI2PD_SRC_DIR}/BloomFilter.cpp" - "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" - "${LIBI2PD_SRC_DIR}/Config.cpp" - "${LIBI2PD_SRC_DIR}/CPU.cpp" - "${LIBI2PD_SRC_DIR}/Crypto.cpp" - "${LIBI2PD_SRC_DIR}/CryptoKey.cpp" - "${LIBI2PD_SRC_DIR}/Datagram.cpp" - "${LIBI2PD_SRC_DIR}/Destination.cpp" - "${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp" - "${LIBI2PD_SRC_DIR}/Ed25519.cpp" - "${LIBI2PD_SRC_DIR}/Elligator.cpp" - "${LIBI2PD_SRC_DIR}/Family.cpp" - "${LIBI2PD_SRC_DIR}/FS.cpp" - "${LIBI2PD_SRC_DIR}/Garlic.cpp" - "${LIBI2PD_SRC_DIR}/Gost.cpp" - "${LIBI2PD_SRC_DIR}/Gzip.cpp" - "${LIBI2PD_SRC_DIR}/HTTP.cpp" - "${LIBI2PD_SRC_DIR}/I2NPProtocol.cpp" - "${LIBI2PD_SRC_DIR}/Identity.cpp" - "${LIBI2PD_SRC_DIR}/LeaseSet.cpp" - "${LIBI2PD_SRC_DIR}/Log.cpp" - "${LIBI2PD_SRC_DIR}/NetDb.cpp" - "${LIBI2PD_SRC_DIR}/NetDbRequests.cpp" - "${LIBI2PD_SRC_DIR}/NTCP2.cpp" - "${LIBI2PD_SRC_DIR}/Poly1305.cpp" - "${LIBI2PD_SRC_DIR}/Profiling.cpp" - "${LIBI2PD_SRC_DIR}/Reseed.cpp" - "${LIBI2PD_SRC_DIR}/RouterContext.cpp" - "${LIBI2PD_SRC_DIR}/RouterInfo.cpp" - "${LIBI2PD_SRC_DIR}/Signature.cpp" - "${LIBI2PD_SRC_DIR}/SSU.cpp" - "${LIBI2PD_SRC_DIR}/SSUData.cpp" - "${LIBI2PD_SRC_DIR}/SSUSession.cpp" - "${LIBI2PD_SRC_DIR}/Streaming.cpp" - "${LIBI2PD_SRC_DIR}/Timestamp.cpp" - "${LIBI2PD_SRC_DIR}/TransitTunnel.cpp" - "${LIBI2PD_SRC_DIR}/Transports.cpp" - "${LIBI2PD_SRC_DIR}/Tunnel.cpp" - "${LIBI2PD_SRC_DIR}/TunnelEndpoint.cpp" - "${LIBI2PD_SRC_DIR}/TunnelGateway.cpp" - "${LIBI2PD_SRC_DIR}/TunnelPool.cpp" - "${LIBI2PD_SRC_DIR}/TunnelConfig.cpp" - "${LIBI2PD_SRC_DIR}/util.cpp" -) - +FILE(GLOB LIBI2PD_SRC ${LIBI2PD_SRC_DIR}/*.cpp) add_library(libi2pd ${LIBI2PD_SRC}) set_target_properties(libi2pd PROPERTIES PREFIX "") @@ -104,19 +56,7 @@ if(WITH_LIBRARY) # install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() -set(CLIENT_SRC - "${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/BOB.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/ClientContext.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/MatchedDestination.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/I2PTunnel.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/I2PService.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/SAM.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/SOCKS.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/HTTPProxy.cpp" - "${LIBI2PD_CLIENT_SRC_DIR}/I2CP.cpp" -) - +FILE(GLOB CLIENT_SRC ${LIBI2PD_CLIENT_SRC_DIR}/*.cpp) add_library(libi2pdclient ${CLIENT_SRC}) set_target_properties(libi2pdclient PROPERTIES PREFIX "") @@ -128,11 +68,7 @@ if(WITH_LIBRARY) COMPONENT Libraries) endif() -set(LANG_SRC - "${LANG_SRC_DIR}/English.cpp" - "${LANG_SRC_DIR}/Russian.cpp" - "${LANG_SRC_DIR}/Ukrainian.cpp" -) +FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp) set(DAEMON_SRC "${DAEMON_SRC_DIR}/Daemon.cpp" From 35b1842a7204dd30b72b407d3ccd90a3bcd1afef Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 13:21:15 +0300 Subject: [PATCH 23/64] [gha] add cmake build on ubuntu Signed-off-by: R4SAS --- .github/workflows/build.yml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a776df92..c7b5a667 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,8 +3,8 @@ name: Build on Ubuntu on: [push, pull_request] jobs: - build: - name: With USE_UPNP=${{ matrix.with_upnp }} + build-make: + name: Make with USE_UPNP=${{ matrix.with_upnp }} runs-on: ubuntu-16.04 strategy: fail-fast: true @@ -19,3 +19,22 @@ jobs: sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - name: build application run: make USE_UPNP=${{ matrix.with_upnp }} -j3 + build-cmake: + name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }} + runs-on: ubuntu-16.04 + strategy: + fail-fast: true + matrix: + with_upnp: ['ON', 'OFF'] + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + sudo add-apt-repository ppa:mhier/libboost-latest + sudo apt-get update + sudo apt-get install build-essential cmake libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev + - name: build application + run: | + cd build + cmake -DWITH_UPNP=${{ matrix.with_upnp }} . + make -j3 From 5011ecaaa65427e83badde130c1185de27f2dae5 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 13:27:13 +0300 Subject: [PATCH 24/64] [i18n] fix language selection Signed-off-by: R4SAS --- i18n/I18N.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/I18N.h b/i18n/I18N.h index a1a78b77..366e9269 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -19,7 +19,7 @@ namespace i18n { if (!lang.compare("russian")) i2p::context.SetLanguage (i2p::i18n::russian::GetLocale()); - if (!lang.compare("ukrainian")) + else if (!lang.compare("ukrainian")) i2p::context.SetLanguage (i2p::i18n::ukrainian::GetLocale()); else // fallback i2p::context.SetLanguage (i2p::i18n::english::GetLocale()); From 3a53e049bd4fbb085af75810e13970e4471c8a64 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 May 2021 13:43:24 +0300 Subject: [PATCH 25/64] [gha] switch ubuntu to 18.04 Signed-off-by: R4SAS --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c7b5a667..d8828f61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: build-make: name: Make with USE_UPNP=${{ matrix.with_upnp }} - runs-on: ubuntu-16.04 + runs-on: ubuntu-18.04 strategy: fail-fast: true matrix: @@ -21,7 +21,7 @@ jobs: run: make USE_UPNP=${{ matrix.with_upnp }} -j3 build-cmake: name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }} - runs-on: ubuntu-16.04 + runs-on: ubuntu-18.04 strategy: fail-fast: true matrix: From 8ce5ceef5970478ff39eb59544278f9c633579d7 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 May 2021 17:47:59 -0400 Subject: [PATCH 26/64] Correct transaltion for "Firewalled" --- i18n/Russian.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 28e07cc1..7df82d54 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -96,7 +96,7 @@ namespace russian // language // Network Status {"OK", "OK"}, {"Testing", "Тестирование"}, - {"Firewalled", "Файрвол"}, + {"Firewalled", "Заблокировано извне"}, {"Unknown", "Неизвестно"}, {"Proxy", "Прокси"}, {"Mesh", "MESH-сеть"}, From e77e383efa8021fdcb21557a8073df91b26214c9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 28 May 2021 18:59:59 +0300 Subject: [PATCH 27/64] [docker] add UPnP at compile time (closes #1649) --- contrib/docker/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index adb7ba75..dc9f5501 100644 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -25,24 +25,24 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \ # 1. install deps, clone and build. # 2. strip binaries. # 3. Purge all dependencies and other unrelated packages, including build directory. -RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl git \ +RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl miniupnpc-dev git \ && mkdir -p /tmp/build \ && cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \ && cd i2pd \ && if [ -n "${GIT_TAG}" ]; then git checkout tags/${GIT_TAG}; fi \ - && make \ + && make USE_UPNP=yes \ && cp -R contrib/certificates /i2pd_certificates \ && mkdir -p /usr/local/bin \ && mv i2pd /usr/local/bin \ && cd /usr/local/bin \ && strip i2pd \ && rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \ - boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \ + miniupnpc-dev boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \ boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre2 \ libtool g++ gcc # 2. Adding required libraries to run i2pd to ensure it will run. -RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl musl-utils libstdc++ +RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl miniupnpc musl-utils libstdc++ COPY entrypoint.sh /entrypoint.sh RUN chmod a+x /entrypoint.sh From a0e545a6f1ed29b9f077371857a587349059416a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 May 2021 12:11:24 -0400 Subject: [PATCH 28/64] always create new tunnel from exploratory pool --- libi2pd/TunnelPool.cpp | 18 ++++++++++++++++-- libi2pd/TunnelPool.h | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index ed9a1a82..f2f0b4c8 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -393,10 +393,14 @@ namespace tunnel } } + bool TunnelPool::IsExploratory () const + { + return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this (); + } + std::shared_ptr TunnelPool::SelectNextHop (std::shared_ptr prevHop, bool reverse) const { - bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ()); - auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop, reverse): + auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse): i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse); if (!hop || hop->GetProfile ()->IsBad ()) @@ -521,6 +525,11 @@ namespace tunnel void TunnelPool::RecreateInboundTunnel (std::shared_ptr tunnel) { + if (IsExploratory ()) // always create new exploratory tunnel + { + CreateInboundTunnel (); + return; + } auto outboundTunnel = GetNextOutboundTunnel (); if (!outboundTunnel) outboundTunnel = tunnels.GetNextOutboundTunnel (); @@ -567,6 +576,11 @@ namespace tunnel void TunnelPool::RecreateOutboundTunnel (std::shared_ptr tunnel) { + if (IsExploratory ()) // always create new exploratory tunnel + { + CreateOutboundTunnel (); + return; + } auto inboundTunnel = GetNextInboundTunnel (); if (!inboundTunnel) inboundTunnel = tunnels.GetNextInboundTunnel (); diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 5fd1d83c..164ca7a1 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -77,6 +77,7 @@ namespace tunnel void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatus (std::shared_ptr msg); + bool IsExploratory () const; bool IsActive () const { return m_IsActive; }; void SetActive (bool isActive) { m_IsActive = isActive; }; void DetachTunnels (); From ed42948051afb308cd7585d4284d286f49829a08 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 30 May 2021 03:23:00 +0300 Subject: [PATCH 29/64] prefer public ipv6 instead rfc4941 (closes #1251) Wokrs only on linux-based systems. Not tested on other *nix systems, and not works on windows. Signed-off-by: R4SAS --- libi2pd/NTCP2.cpp | 9 +++++++++ libi2pd/SSU.cpp | 9 +++++++++ libi2pd/util.h | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index d5a03d1c..54d6483c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -23,6 +23,10 @@ #include "HTTP.h" #include "util.h" +#ifdef __linux__ + #include +#endif + namespace i2p { namespace transport @@ -1198,6 +1202,11 @@ namespace transport ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port); else if (m_YggdrasilAddress && !context.SupportsV6 ()) ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port); +#ifdef __linux__ + // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others + typedef boost::asio::detail::socket_option::boolean ipv6PreferPubAddr; + m_NTCP2V6Acceptor->set_option (ipv6PreferPubAddr (true)); +#endif m_NTCP2V6Acceptor->bind (ep); m_NTCP2V6Acceptor->listen (); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index f7801bb0..0836f84e 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -14,6 +14,10 @@ #include "SSU.h" #include "util.h" +#ifdef __linux__ + #include +#endif + #ifdef _WIN32 #include #endif @@ -62,6 +66,11 @@ namespace transport m_SocketV6.set_option (boost::asio::ip::v6_only (true)); m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); +#ifdef __linux__ + // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others + typedef boost::asio::detail::socket_option::boolean ipv6PreferPubAddr; + m_SocketV6.set_option (ipv6PreferPubAddr(true)); +#endif m_SocketV6.bind (m_EndpointV6); LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port()); } diff --git a/libi2pd/util.h b/libi2pd/util.h index 0cab4121..000cb74e 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -177,13 +177,13 @@ namespace util 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); From 39319853ab79c3cadd74cfe69e525a4e247d4bab Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 30 May 2021 21:38:14 +0300 Subject: [PATCH 30/64] [i18n] add Turkmen translation Signed-off-by: R4SAS --- contrib/i2pd.conf | 2 +- i18n/I18N.h | 2 + i18n/I18N_langs.h | 1 + i18n/Turkmen.cpp | 243 +++++++++++++++++++++++++++++++++++++++++++++ i18n/Ukrainian.cpp | 2 +- 5 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 i18n/Turkmen.cpp diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 3b20a809..f3cea2b5 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -104,7 +104,7 @@ port = 7070 # user = i2pd # pass = changeme ## Select webconsole language -## Currently supported english (default), russian and ukrainian languages +## Currently supported english (default), russian, turkmen and ukrainian languages # lang = english [httpproxy] diff --git a/i18n/I18N.h b/i18n/I18N.h index 366e9269..7d0baf1a 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -19,6 +19,8 @@ namespace i18n { if (!lang.compare("russian")) i2p::context.SetLanguage (i2p::i18n::russian::GetLocale()); + else if (!lang.compare("turkmen")) + i2p::context.SetLanguage (i2p::i18n::turkmen::GetLocale()); else if (!lang.compare("ukrainian")) i2p::context.SetLanguage (i2p::i18n::ukrainian::GetLocale()); else // fallback diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index c094cb79..435141bf 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -58,6 +58,7 @@ namespace i18n // Add localization here with language name as namespace namespace english { std::shared_ptr GetLocale (); } namespace russian { std::shared_ptr GetLocale (); } + namespace turkmen { std::shared_ptr GetLocale (); } namespace ukrainian { std::shared_ptr GetLocale (); } } // i18n diff --git a/i18n/Turkmen.cpp b/i18n/Turkmen.cpp new file mode 100644 index 00000000..93bd92fe --- /dev/null +++ b/i18n/Turkmen.cpp @@ -0,0 +1,243 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Turkmen localization file + +namespace i2p +{ +namespace i18n +{ +namespace turkmen // language +{ + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + static std::map strings + { + // HTTP Proxy + {"Proxy error", "Proksi ýalňyşlygy"}, + {"Proxy info", "Proksi maglumat"}, + {"Proxy error: Host not found", "Proksi ýalňyşlygy: Host tapylmady"}, + {"Remote host not found in router's addressbook", "Uzakdaky öý eýesi marşruteriň salgy kitabynda tapylmady"}, + {"You may try to find this host on jump services below", "Aşakdaky böküş hyzmatlarynda bu öý eýesini tapmaga synanyşyp bilersiňiz"}, + {"Invalid request", "Nädogry haýyş"}, + {"Proxy unable to parse your request", "Proksi haýyşyňyzy derňäp bilmeýär"}, + {"addresshelper is not supported", "Salgylandyryjy goldanok"}, + {"Host", "Adres"}, + {"added to router's addressbook from helper", "marşruteriň adresini kömekçiden goşdy"}, + {"already in router's addressbook", "marşruteriň adres kitaby"}, + {"Click", "Basyň"}, + {"here", "bu ýerde"}, + {"to proceed", "dowam etmek"}, + {"to update record", "recordazgyny täzelemek üçin"}, + {"Addresshelper found", "Forgelper tapyldy"}, + {"invalid request uri", "nädogry haýyş URI"}, + {"Can't detect destination host from request", "Haýyşdan barmaly ýerini tapyp bilemok"}, + {"Outproxy failure", "Daşarky proksi ýalňyşlyk"}, + {"bad outproxy settings", "daşarky daşarky proksi sazlamalary nädogry"}, + {"not inside I2P network, but outproxy is not enabled", "I2P torunda däl, ýöne daşarky proksi goşulmaýar"}, + {"unknown outproxy url", "näbelli daşarky proksi URL"}, + {"cannot resolve upstream proxy", "has ýokary proksi kesgitläp bilmeýär"}, + {"hostname too long", "hoster eýesi ady gaty uzyn"}, + {"cannot connect to upstream socks proxy", "ýokary jorap SOCKS proksi bilen birigip bolmaýar"}, + {"Cannot negotiate with socks proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"}, + {"CONNECT error", "Bagyr haýyşy säwligi"}, + {"Failed to Connect", "Birikdirip bilmedi"}, + {"socks proxy error", "socks proksi ýalňyşlygy"}, + {"failed to send request to upstream", "öý eýesi proksi üçin haýyş iberip bilmedi"}, + {"No Reply From socks proxy", "Jorap proksi serwerinden hiç hili jogap ýok"}, + {"cannot connect", "birikdirip bilmedi"}, + {"http out proxy not implemented", "daşarky http proksi serwerini goldamak amala aşyrylmaýar"}, + {"cannot connect to upstream http proxy", "ýokary akym HTTP proksi serwerine birigip bilmedi"}, + {"Host is down", "Salgy elýeterli däl"}, + {"Can't create connection to requested host, it may be down. Please try again later.", + "Talap edilýän salgyda birikmäni gurup bilmedim, onlaýn bolup bilmez. Soňra haýyşy soň gaýtalamaga synanyşyň."}, + + // Webconsole // + // cssStyles + {"Disabled", "Öçürildi"}, + {"Enabled", "Goşuldy"}, + // ShowTraffic + {"KiB", "KiB"}, + {"MiB", "MiB"}, + {"GiB", "GiB"}, + // ShowTunnelDetails + {"building", "bina"}, + {"failed", "şowsuz"}, + {"expiring", "möhleti gutarýar"}, + {"established", "işleýär"}, + {"exploratory", "gözleg"}, + {"unknown", "näbelli"}, + {"i2pd webconsole", "Web konsoly i2pd"}, + // ShowPageHead + {"Main page", "Esasy sahypa"}, + {"Router commands", "Marşrutizator buýruklary"}, + {"Local destinations", "Ýerli ýerler"}, + {"LeaseSets", "Lizset"}, + {"Tunnels", "Tuneller"}, + {"Transit tunnels", "Tranzit Tunels"}, + {"Transports", "Daşamak"}, + {"I2P tunnels", "I2P tuneller"}, + {"SAM sessions", "SAM Sessiýasy"}, + // Network Status + {"OK", "OK"}, + {"Testing", "Synag etmek"}, + {"Firewalled", "Daşynda petiklendi"}, + {"Unknown", "Näbelli"}, + {"Proxy", "Proksi"}, + {"Mesh", "MESH-tor"}, + {"Error", "Ýalňyşlyk"}, + {"Clock skew", "Takyk wagt däl"}, + {"Offline", "Awtonom"}, + {"Symmetric NAT", "Simmetriklik NAT"}, + // Status + {"Uptime", "Onlaýn onlaýn sözlügi"}, + {"Network status", "Tor ýagdaýy"}, + {"Network status v6", "Tor ýagdaýy v6"}, + {"Stopping in", "soň duruň"}, + {"Family", "Maşgala"}, + {"Tunnel creation success rate", "Gurlan teneller üstünlikli gurlan teneller"}, + {"Received", "Alnan"}, + {"Sent", "Ýerleşdirildi"}, + {"Transit", "Tranzit"}, + {"KiB/s", "KiB/s"}, + {"Data path", "Maglumat ýoly"}, + {"Hidden content. Press on text to see.", "Gizlin mazmun. Görkezmek üçin tekste basyň."}, + {"Router Ident", "Marşrutly kesgitleýji"}, + {"Router Family", "Marşrutler maşgalasy"}, + {"Router Caps", "Baýdaklar marşruteri"}, + {"Version", "Wersiýasy"}, + {"Our external address", "Daşarky salgymyz"}, + {"supported", "Goldanýar"}, + {"Routers", "Marşrutizatorlar"}, + {"Floodfills", "Fludfillar"}, + {"LeaseSets", "Lizsetllar"}, + {"Client Tunnels", "Müşderi tunelleri"}, + {"Transit Tunnels", "Tranzit Tunelleri"}, + {"Services", "Hyzmatlar"}, + // ShowLocalDestinations + {"Local Destinations", "Ýerli ýerler"}, + // ShowLeaseSetDestination + {"Encrypted B33 address", "Şifrlenen B33 salgylar"}, + {"Address registration line", "Hasaba alyş salgysy"}, + {"Domain", "Domen"}, + {"Generate", "Öndürmek"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", + "Bellik: Alnan setir diňe ikinji derejeli domenleri bellige almak üçin ulanylyp bilner. Subýutmalary hasaba almak üçin i2pd ulanyň-tools."}, + {"Address", "Salgysy"}, + {"Type", "Görnüş"}, + {"EncType", "Şifrlemek görnüşi"}, + {"Inbound tunnels", "Gelýän tuneller"}, + {"Outbound tunnels", "Çykýan tuneller"}, + {"ms", "ms"}, // milliseconds + {"Tags", "Bellikler"}, + {"Incoming", "Gelýän"}, + {"Outgoing", "Çykýan"}, + {"Destination", "Maksat"}, + {"Amount", "Sany"}, + {"Incoming Tags", "Gelýän bellikler"}, + {"Tags sessions", "Sapaklar Tag."}, + {"Status", "Ýagdaýy"}, + // ShowLocalDestination + {"Local Destination", "Ýerli maksat"}, + {"Streams", "Strimlary"}, + {"Close stream", "Yap strim"}, + // ShowI2CPLocalDestination + {"I2CP session not found", "I2CP Sessiýa tapylmady"}, + {"I2CP is not enabled", "I2CP goşulmaýar"}, + // ShowLeasesSets + {"Invalid", "Nädogry"}, + {"Store type", "Ammar görnüşi"}, + {"Expires", "Möhleti gutarýar"}, + {"Non Expired Leases", "Möhleti gutarmady Lizsetlary"}, + {"Gateway", "Derweze"}, + {"TunnelID", "Tuneliň ID"}, + {"EndDate", "Gutarýar"}, + {"not floodfill", "fludfil däl"}, + // ShowTunnels + {"Queue size", "Nobatyň ululygy"}, + // ShowCommands + {"Run peer test", "Synag başlaň"}, + {"Decline transit tunnels", "Tranzit tunellerini ret ediň"}, + {"Accept transit tunnels", "Tranzit tunellerini alyň"}, + {"Cancel graceful shutdown", "Tekiz durmagy ýatyryň"}, + {"Start graceful shutdown", "Tekiz durmak"}, + {"Force shutdown", "Mejbury duralga"}, + {"Note: any action done here are not persistent and not changes your config files.", + "Bellik: Bu ýerde öndürilen islendik çäre hemişelik däl we konfigurasiýa faýllaryňyzy üýtgetmeýär.."}, + {"Logging level", "Giriş derejesi"}, + {"Transit tunnels limit", "Tranzit tunelleriniň çägi"}, + {"Change", "Üýtgetmek"}, + // ShowTransitTunnels + {"no transit tunnels currently built", "gurlan tranzit tunelleri ýok"}, + // ShowSAMSessions/ShowSAMSession + {"SAM disabled", "SAM öçürilen"}, + {"SAM session not found", "SAM Sessiýa tapylmady"}, + {"no sessions currently running", "başlamagyň sessiýalary ýok"}, + {"SAM Session", "SAM Sessiýa"}, + // ShowI2PTunnels + {"Server Tunnels", "Serwer tunelleri"}, + {"Client Forwards", "Müşderi gönükdirýär"}, + {"Server Forwards", "Serweriň täzeden düzlüleri"}, + // HandlePage + {"Unknown page", "Näbelli sahypa"}, + // HandleCommand, ShowError + {"Invalid token", "Nädogry token"}, + {"SUCCESS", "Üstünlikli"}, + {"ERROR", "Ýalňyşlyk"}, + {"Unknown command", "Näbelli topar"}, + {"Command accepted", "Topar kabul edilýär"}, + {"Back to commands list", "Topar sanawyna dolan"}, + {"You will be redirected in 5 seconds", "5 sekuntdan soň täzeden ugrukdyrylarsyňyz"}, + // HTTP_COMMAND_KILLSTREAM + {"Stream closed", "Strim ýapyk"}, + {"Stream not found or already was closed", "Strim tapylmady ýa-da eýýäm ýapyldy"}, + {"Destination not found", "Niýetlenen ýeri tapylmady"}, + {"StreamID can't be null", "StreamID boş bolup bilmez"}, + {"Return to destination page", "Barmaly nokadynyň nokadyna gaýdyp geliň"}, + {"You will be redirected back in 5 seconds", "5 sekuntda yzyna iberiler"}, + // HTTP_COMMAND_LIMITTRANSIT + {"Transit tunnels count must not exceed 65535", "Tranzit tagtalaryň sany 65535-den geçmeli däldir"}, + // HTTP_COMMAND_GET_REG_STRING + {"Register at reg.i2p", "Reg.i2P-de hasaba duruň"}, + {"Description", "Beýany"}, + {"A bit information about service on domain", "Domendäki hyzmat barada käbir maglumatlar"}, + {"Submit", "Iber"}, + {"Domain can't end with .b32.i2p", "Domain .b32.i2p bilen gutaryp bilmez."}, + {"Domain must end with .i2p", "Domeni .i2p bilen gutarmaly"}, + {"Such destination is not found", "Bu barmaly ýer tapylmady"}, + {"", ""}, + }; + + static std::map> plurals + { + // ShowUptime + {"days", {"gün", "gün"}}, + {"hours", {"sagat", "sagat"}}, + {"minutes", {"minut", "minut"}}, + {"seconds", {"sekunt", "sekunt"}}, + {"", {"", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp index 94c61d80..05e7c786 100644 --- a/i18n/Ukrainian.cpp +++ b/i18n/Ukrainian.cpp @@ -12,7 +12,7 @@ #include #include "I18N.h" -// Russian localization file +// Ukrainian localization file namespace i2p { From be31640010ab6fe6777435302fc231ae3279f73e Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 31 May 2021 00:23:50 +0300 Subject: [PATCH 31/64] fix ipv6 preference on linux Signed-off-by: R4SAS --- libi2pd/NTCP2.cpp | 13 ++++++++----- libi2pd/SSU.cpp | 9 ++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 54d6483c..72e822cd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1197,16 +1197,19 @@ namespace transport m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true)); +#ifdef __linux__ + if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address + { + // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others + typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; + m_NTCP2V6Acceptor->set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA)); + } +#endif auto ep = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port); if (m_Address6 && !context.SupportsMesh ()) ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port); else if (m_YggdrasilAddress && !context.SupportsV6 ()) ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port); -#ifdef __linux__ - // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others - typedef boost::asio::detail::socket_option::boolean ipv6PreferPubAddr; - m_NTCP2V6Acceptor->set_option (ipv6PreferPubAddr (true)); -#endif m_NTCP2V6Acceptor->bind (ep); m_NTCP2V6Acceptor->listen (); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 0836f84e..f625c89b 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -67,9 +67,12 @@ namespace transport m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); #ifdef __linux__ - // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others - typedef boost::asio::detail::socket_option::boolean ipv6PreferPubAddr; - m_SocketV6.set_option (ipv6PreferPubAddr(true)); + if (m_EndpointV6.address() != boost::asio::ip::address().from_string("::")) // only if not binded to address + { + // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others + typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; + m_SocketV6.set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA)); + } #endif m_SocketV6.bind (m_EndpointV6); LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port()); From 0547d590e1f1cefc1f93204cae17e2795487b61a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 31 May 2021 00:24:54 +0300 Subject: [PATCH 32/64] fix typo Signed-off-by: R4SAS --- libi2pd/SSU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index f625c89b..e4901f7c 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -67,7 +67,7 @@ namespace transport m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); #ifdef __linux__ - if (m_EndpointV6.address() != boost::asio::ip::address().from_string("::")) // only if not binded to address + if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address { // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; From ef8c4389e104cf217dae6c3e15d9bff83d6abfd9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Jun 2021 12:55:08 -0400 Subject: [PATCH 33/64] reachable transports added --- libi2pd/RouterInfo.cpp | 45 ++++++++++++++++++++++++++++++++++++++---- libi2pd/RouterInfo.h | 7 ++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 87a987fe..3035bd31 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -36,7 +36,7 @@ namespace data RouterInfo::RouterInfo (const std::string& fullPath): m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false), - m_SupportedTransports (0), m_Caps (0), m_Version (0) + m_SupportedTransports (0), m_ReachableTransports (0), m_Caps (0), m_Version (0) { m_Addresses = boost::make_shared(); // create empty list m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; @@ -45,7 +45,7 @@ namespace data RouterInfo::RouterInfo (const uint8_t * buf, int len): m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), - m_Caps (0), m_Version (0) + m_ReachableTransports (0), m_Caps (0), m_Version (0) { m_Addresses = boost::make_shared(); // create empty list if (len <= MAX_RI_BUFFER_SIZE) @@ -84,6 +84,7 @@ namespace data m_IsUpdated = true; m_IsUnreachable = false; m_SupportedTransports = 0; + m_ReachableTransports = 0; m_Caps = 0; // don't clean up m_Addresses, it will be replaced in ReadFromStream m_Properties.clear (); @@ -305,9 +306,10 @@ namespace data if (isHost) { if (address->host.is_v6 ()) - supportedTransports |= i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6; + supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6); else supportedTransports |= eNTCP2V4; + m_ReachableTransports |= supportedTransports; } else if (!address->published) { @@ -347,10 +349,16 @@ namespace data else it.iPort = 0; } - if (!numValid) address->ssu->introducers.resize (0); + if (numValid) + m_ReachableTransports |= supportedTransports; + else + address->ssu->introducers.resize (0); } else if (isHost && address->port) + { address->published = true; + m_ReachableTransports |= supportedTransports; + } } } if (supportedTransports) @@ -860,6 +868,7 @@ namespace data for (auto& intro: addr->ssu->introducers) if (intro.iTag == introducer.iTag) return false; // already presented addr->ssu->introducers.push_back (introducer); + m_ReachableTransports |= (addr->IsV4 () ? eSSUV4 : eSSUV6); return true; } } @@ -877,6 +886,8 @@ namespace data if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { addr->ssu->introducers.erase (it); + if (addr->ssu->introducers.empty ()) + m_ReachableTransports &= ~(addr->IsV4 () ? eSSUV4 : eSSUV6); return true; } } @@ -1184,5 +1195,31 @@ namespace data } } } + + void RouterInfo::UpdateSupportedTransports () + { + m_SupportedTransports = 0; + m_ReachableTransports = 0; + for (const auto& addr: *m_Addresses) + { + uint8_t transports = 0; + if (addr->transportStyle == eTransportNTCP) + { + if (addr->IsV4 ()) transports |= eNTCP2V4; + if (addr->IsV6 ()) + transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6); + if (addr->IsPublishedNTCP2 ()) + m_ReachableTransports |= transports; + } + else if (addr->transportStyle == eTransportSSU) + { + if (addr->IsV4 ()) transports |= eSSUV4; + if (addr->IsV6 ()) transports |= eSSUV6; + if (addr->IsReachableSSU ()) + m_ReachableTransports |= transports; + } + m_SupportedTransports |= transports; + } + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index dd3e7e13..bea83fda 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -59,7 +59,7 @@ namespace data { public: - enum SupportedTranports + enum SupportedTransports { eNTCP2V4 = 0x01, eNTCP2V6 = 0x02, @@ -147,7 +147,7 @@ namespace data bool IsNTCP2 () const { return (bool)ntcp2; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; }; - bool IsReachableSSU () const { return (bool)ssu && (!host.is_unspecified () || !ssu->introducers.empty ()); }; + bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); }; bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); }; bool IsIntroducer () const { return caps & eSSUIntroducer; }; @@ -187,6 +187,7 @@ namespace data std::string GetProperty (const std::string& key) const; // called from RouterContext only void ClearProperties () { m_Properties.clear (); }; void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps + void UpdateSupportedTransports (); bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; bool IsReachable () const { return m_Caps & Caps::eReachable; }; bool IsSSU (bool v4only = true) const; @@ -269,7 +270,7 @@ namespace data boost::shared_ptr m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9 std::map m_Properties; bool m_IsUpdated, m_IsUnreachable; - uint8_t m_SupportedTransports, m_Caps; + uint8_t m_SupportedTransports, m_ReachableTransports, m_Caps; int m_Version; mutable std::shared_ptr m_Profile; }; From 5ce9c0f1e20079505a2549c708f6d3ac8049c88a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Jun 2021 14:45:21 -0400 Subject: [PATCH 34/64] build new tunnels instead slow --- libi2pd/Tunnel.h | 3 +++ libi2pd/TunnelPool.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 7e8edca7..f30eab14 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -38,6 +38,7 @@ namespace tunnel const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message const int MAX_NUM_RECORDS = 8; + const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds enum TunnelState { @@ -98,6 +99,8 @@ namespace tunnel bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; bool LatencyIsKnown() const { return m_Latency > 0; } + bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); } + protected: void PrintHops (std::stringstream& s) const; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index f2f0b4c8..b025219f 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -525,7 +525,7 @@ namespace tunnel void TunnelPool::RecreateInboundTunnel (std::shared_ptr tunnel) { - if (IsExploratory ()) // always create new exploratory tunnel + if (IsExploratory () || tunnel->IsSlow ()) // always create new exploratory tunnel or if slow { CreateInboundTunnel (); return; @@ -576,7 +576,7 @@ namespace tunnel void TunnelPool::RecreateOutboundTunnel (std::shared_ptr tunnel) { - if (IsExploratory ()) // always create new exploratory tunnel + if (IsExploratory () || tunnel->IsSlow ()) // always create new exploratory tunnel or if slow { CreateOutboundTunnel (); return; From 8e3e35a36d2f4db0929a88f08bf37dc04e2b81c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Jun 2021 19:50:29 -0400 Subject: [PATCH 35/64] decrypt short request record --- libi2pd/I2NPProtocol.h | 3 ++ libi2pd/RouterContext.cpp | 64 ++++++++++++++++++++++++--------------- libi2pd/RouterContext.h | 5 ++- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index c9b0fc04..56afeb0e 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -100,6 +100,9 @@ namespace i2p // ECIES BuildResponseRecord const size_t ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET = 0; const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511; + + // ShortRequestRecordClearText + const size_t SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE = 172; enum I2NPMessageType { diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 664b457c..d1f503bb 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -875,34 +875,11 @@ namespace i2p bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data) { - if (!m_TunnelDecryptor) return false; if (IsECIES ()) - { - if (!m_InitialNoiseState) return false; - // m_InitialNoiseState is h = SHA256(h || hepk) - m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); - m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) - uint8_t sharedSecret[32]; - if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false)) - { - LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); - return false; - } - m_CurrentNoiseState->MixKey (sharedSecret); - encrypted += 32; - uint8_t nonce[12]; - memset (nonce, 0, 12); - if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, - m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, false)) // decrypt - { - LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); - return false; - } - m_CurrentNoiseState->MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) - return true; - } + return DecryptECIESTunnelBuildRecord (encrypted, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE); else { + if (!m_TunnelDecryptor) return false; BN_CTX * ctx = BN_CTX_new (); bool success = m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false); BN_CTX_free (ctx); @@ -910,6 +887,43 @@ namespace i2p } } + bool RouterContext::DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize) + { + if (!m_InitialNoiseState || !m_TunnelDecryptor) return false; + // m_InitialNoiseState is h = SHA256(h || hepk) + m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); + m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) + uint8_t sharedSecret[32]; + if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false)) + { + LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); + return false; + } + m_CurrentNoiseState->MixKey (sharedSecret); + encrypted += 32; + uint8_t nonce[12]; + memset (nonce, 0, 12); + if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState->m_H, 32, + m_CurrentNoiseState->m_CK + 32, nonce, data, clearTextSize, false)) // decrypt + { + LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); + return false; + } + m_CurrentNoiseState->MixHash (encrypted, clearTextSize + 16); // h = SHA256(h || ciphertext) + return true; + } + + bool RouterContext::DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data) + { + if (IsECIES ()) + return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE); + else + { + LogPrint (eLogWarning, "Router: Can't decrypt short request record on non-ECIES router"); + return false; + } + } + i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () { if (!m_StaticKeys) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ee34c2d8..10498b3b 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -97,7 +97,8 @@ namespace garlic int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); - + bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data); + void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); @@ -164,6 +165,8 @@ namespace garlic bool Load (); void SaveKeys (); + bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); + private: i2p::data::RouterInfo m_RouterInfo; From e740d5fc4fd2c56960fc3e635195a282f302459b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Jun 2021 12:16:50 -0400 Subject: [PATCH 36/64] try to pick non-slow tunnel --- libi2pd/TunnelPool.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index b025219f..f5af249a 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -172,13 +172,16 @@ namespace tunnel { if (tunnels.empty ()) return nullptr; uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0; + bool skipped = false; typename TTunnels::value_type tunnel = nullptr; for (const auto& it: tunnels) { if (it->IsEstablished () && it != excluded) { - if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) { - i ++; + if (it->IsSlow () || (HasLatencyRequirement() && it->LatencyIsKnown() && + !it->LatencyFitsRange(m_MinLatency, m_MaxLatency))) + { + i++; skipped = true; continue; } tunnel = it; @@ -186,7 +189,8 @@ namespace tunnel } if (i > ind && tunnel) break; } - if(HasLatencyRequirement() && !tunnel) { + if (!tunnel && skipped) + { ind = rand () % (tunnels.size ()/2 + 1), i = 0; for (const auto& it: tunnels) { From d752a83eb568c34d529e3437205393e29a7a7cfd Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Jun 2021 18:28:30 -0400 Subject: [PATCH 37/64] handle i2cp.dontPublishLeaseSet for all destinations --- libi2pd/Destination.cpp | 13 +++++++++++-- libi2pd/Destination.h | 5 +++-- libi2pd_client/I2CP.cpp | 6 ++---- libi2pd_client/I2CP.h | 1 - 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 9962599b..7bcfe111 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -82,6 +82,14 @@ namespace client if (it != params->end ()) m_Nickname = it->second; // otherwise we set default nickname in Start when we know local address } + it = params->find (I2CP_PARAM_DONT_PUBLISH_LEASESET); + if (it != params->end ()) + { + // oveeride isPublic + bool dontpublish = false; + i2p::config::GetOption (it->second, dontpublish); + m_IsPublic = !dontpublish; + } it = params->find (I2CP_PARAM_LEASESET_TYPE); if (it != params->end ()) m_LeaseSetType = std::stoi(it->second); @@ -509,7 +517,7 @@ namespace client // schedule verification m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); } else i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID); @@ -592,7 +600,8 @@ namespace client // assume it successive and try to verify m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); + } } } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 40c9e9ab..6695796d 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -61,14 +61,15 @@ namespace client const char I2CP_PARAM_RATCHET_OUTBOUND_TAGS[] = "crypto.ratchet.outboundTags"; // not used yet const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname"; const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname"; + const char I2CP_PARAM_DONT_PUBLISH_LEASESET[] = "i2cp.dontPublishLeaseSet"; const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType"; const int DEFAULT_LEASESET_TYPE = 3; const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType"; const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn - const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn - + const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn + // latency const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const int DEFAULT_MIN_TUNNEL_LATENCY = 0; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index d07c6248..25a5504a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -544,13 +544,11 @@ namespace client offset += 8; // date if (identity->Verify (buf, offset, buf + offset)) // signature { - bool isPublic = true; - if (params[I2CP_PARAM_DONT_PUBLISH_LEASESET] == "true") isPublic = false; if (!m_Destination) { m_Destination = m_Owner.IsSingleThread () ? - std::make_shared(m_Owner.GetService (), shared_from_this (), identity, isPublic, params): - std::make_shared(shared_from_this (), identity, isPublic, params); + std::make_shared(m_Owner.GetService (), shared_from_this (), identity, true, params): + std::make_shared(shared_from_this (), identity, true, params); SendSessionStatusMessage (1); // created LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " created"); m_Destination->Start (); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 085bf30a..9a8bda4e 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -62,7 +62,6 @@ namespace client }; // params - const char I2CP_PARAM_DONT_PUBLISH_LEASESET[] = "i2cp.dontPublishLeaseSet"; const char I2CP_PARAM_MESSAGE_RELIABILITY[] = "i2cp.messageReliability"; class I2CPSession; From 5fb426b33612d983d3cb78f2e503e1c12d226512 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Jun 2021 13:55:38 -0400 Subject: [PATCH 38/64] decrypt and encrypt reply for short tunnel build message --- libi2pd/I2NPProtocol.cpp | 73 +++++++++++++++++++++++++++++++++++++--- libi2pd/I2NPProtocol.h | 8 +++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 7f059d72..e47c9add 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -458,7 +458,7 @@ namespace i2p LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) { - LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len); + LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len); return; } @@ -526,12 +526,12 @@ namespace i2p { if (i2p::context.IsECIES ()) { - LogPrint (eLogWarning, "TunnelBuild is too old for ECIES router"); + LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router"); return; } if (len < NUM_TUNNEL_BUILD_RECORDS*TUNNEL_BUILD_RECORD_SIZE) { - LogPrint (eLogError, "TunnelBuild message is too short ", len); + LogPrint (eLogError, "I2NP: TunnelBuild message is too short ", len); return; } uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; @@ -558,7 +558,7 @@ namespace i2p LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID); if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1) { - LogPrint (eLogError, "VaribleTunnelBuildReply message of ", num, " records is too short ", len); + LogPrint (eLogError, "I2NP: VaribleTunnelBuildReply message of ", num, " records is too short ", len); return; } @@ -582,7 +582,66 @@ namespace i2p LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found"); } - + void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) + { + if (!i2p::context.IsECIES ()) + { + LogPrint (eLogWarning, "I2NP: ShortTunnelBuild can be handled by ECIES router only"); + return; + } + int num = buf[0]; + LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records"); + if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) + { + LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len); + return; + } + // TODO: check replyMsgID + const uint8_t * record = buf + 1; + for (int i = 0; i < num; i++) + { + if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) + { + LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours"); + uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; + if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) + { + LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i); + return; + } + // TODO: fill reply + // encrypt reply + auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); + if (!noiseState) + { + LogPrint (eLogWarning, "I2NP: Invalid Noise state for short reply encryption"); + return; + } + uint8_t nonce[12]; + memset (nonce, 0, 12); + uint8_t * reply = buf + 1; + for (int j = 0; j < num; j++) + { + if (j == i) + { + if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState->m_H, 32, noiseState->m_CK, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); + return; + } + } + else + i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState->m_CK, nonce, reply); + reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + // TODO: send + return; + } + record += SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + } + std::shared_ptr CreateTunnelDataMsg (const uint8_t * buf) { auto msg = NewI2NPTunnelMessage (); @@ -700,6 +759,9 @@ namespace i2p case eI2NPVariableTunnelBuildReply: HandleVariableTunnelBuildReplyMsg (msgID, buf, size); break; + case eI2NPShortTunnelBuild: + HandleShortTunnelBuildMsg (msgID, buf, size); + break; case eI2NPTunnelBuild: HandleTunnelBuildMsg (buf, size); break; @@ -756,6 +818,7 @@ namespace i2p case eI2NPVariableTunnelBuildReply: case eI2NPTunnelBuild: case eI2NPTunnelBuildReply: + case eI2NPShortTunnelBuild: // forward to tunnel thread i2p::tunnel::tunnels.PostTunnelData (msg); break; diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 56afeb0e..5db93978 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -55,7 +55,8 @@ namespace i2p // TunnelBuild const size_t TUNNEL_BUILD_RECORD_SIZE = 528; - + const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 236; + //BuildRequestRecordClearText const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0; const size_t BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET = BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4; @@ -102,6 +103,7 @@ namespace i2p const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511; // ShortRequestRecordClearText + const size_t SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET = 16; const size_t SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE = 172; enum I2NPMessageType @@ -118,7 +120,8 @@ namespace i2p eI2NPTunnelBuild = 21, eI2NPTunnelBuildReply = 22, eI2NPVariableTunnelBuild = 23, - eI2NPVariableTunnelBuildReply = 24 + eI2NPVariableTunnelBuildReply = 24, + eI2NPShortTunnelBuild = 25 }; const int NUM_TUNNEL_BUILD_RECORDS = 8; @@ -287,6 +290,7 @@ namespace tunnel bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); + void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleTunnelBuildMsg (uint8_t * buf, size_t len); std::shared_ptr CreateTunnelDataMsg (const uint8_t * buf); From 857183048513220dc6c29751b094eeb7a193758f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Jun 2021 18:28:36 -0400 Subject: [PATCH 39/64] create transit tunnel and reply for short tunnel build --- libi2pd/I2NPProtocol.cpp | 20 +++++++++++++++++--- libi2pd/I2NPProtocol.h | 9 +++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index e47c9add..760bdf59 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -424,7 +424,7 @@ namespace i2p { uint8_t nonce[12]; memset (nonce, 0, 12); - auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); + auto& noiseState = i2p::context.GetCurrentNoiseState (); if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt { @@ -609,9 +609,19 @@ namespace i2p LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i); return; } + auto& noiseState = i2p::context.GetCurrentNoiseState (); + uint8_t layerKeys[64]; // (layer key, iv key) + i2p::crypto::HKDF (noiseState->m_CK + 32, nullptr, 0, "LayerAndIVKeys", layerKeys); // TODO: correct domain + auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( + bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + layerKeys, layerKeys + 32, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & 0x80, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & 0x40); + i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); // TODO: fill reply // encrypt reply - auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); if (!noiseState) { LogPrint (eLogWarning, "I2NP: Invalid Noise state for short reply encryption"); @@ -622,6 +632,7 @@ namespace i2p uint8_t * reply = buf + 1; for (int j = 0; j < num; j++) { + nonce[4] = j; // nonce is record # if (j == i) { if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, @@ -635,7 +646,10 @@ namespace i2p i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState->m_CK, nonce, reply); reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; } - // TODO: send + // TODO: send reply + transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, + CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); return; } record += SHORT_TUNNEL_BUILD_RECORD_SIZE; diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 5db93978..76030e91 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -104,6 +104,15 @@ namespace i2p // ShortRequestRecordClearText const size_t SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET = 16; + const size_t SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0; + const size_t SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4; + const size_t SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET = SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET + 4; + const size_t SHORT_REQUEST_RECORD_FLAG_OFFSET = SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET + 32; + const size_t SHORT_REQUEST_RECORD_MORE_FLAGS_OFFSET = SHORT_REQUEST_RECORD_FLAG_OFFSET + 1; + const size_t SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE = SHORT_REQUEST_RECORD_MORE_FLAGS_OFFSET + 2; + const size_t SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET = SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE + 1; + const size_t SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET = SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4; + const size_t SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET = SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4; const size_t SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE = 172; enum I2NPMessageType From 8e4781b0f7d82f2e048d0334a5069e2d8b3ff3f0 Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Tue, 8 Jun 2021 09:39:28 -0400 Subject: [PATCH 40/64] tbytes in WinApp (#1660) --- Win32/Win32App.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index db5a1f3d..7104ec7f 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -131,7 +131,7 @@ namespace win32 transfer >>= 10; auto mbytes = transfer & 0x03ff; transfer >>= 10; - auto gbytes = transfer & 0x03ff; + auto gbytes = transfer; if (gbytes) s << gbytes << " GB, "; From 3b051dbba34bcfd3c985ef93e194c1cfc586a270 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Jun 2021 15:36:27 -0400 Subject: [PATCH 41/64] send OutboundTunnelBuildReply --- libi2pd/I2NPProtocol.cpp | 114 ++++++++++++++++++++++++++------------- libi2pd/I2NPProtocol.h | 7 ++- libi2pd/TunnelConfig.cpp | 6 +-- 3 files changed, 84 insertions(+), 43 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 760bdf59..5ed875c5 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -18,6 +18,7 @@ #include "Tunnel.h" #include "Transports.h" #include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" #include "I2NPProtocol.h" #include "version.h" @@ -387,16 +388,16 @@ namespace i2p bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) : + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) : i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, - clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, - clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40); + clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); } else @@ -486,7 +487,7 @@ namespace i2p uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (num, buf + 1, clearText)) { - if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel + if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel { // so we send it to reply tunnel transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, @@ -505,7 +506,7 @@ namespace i2p uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (num, buf + 1, clearText)) { - if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel + if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, @@ -537,7 +538,7 @@ namespace i2p uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText)) { - if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel + if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outbound tunnel { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, @@ -610,6 +611,11 @@ namespace i2p return; } auto& noiseState = i2p::context.GetCurrentNoiseState (); + if (!noiseState) + { + LogPrint (eLogWarning, "I2NP: Invalid Noise state for short reply encryption"); + return; + } uint8_t layerKeys[64]; // (layer key, iv key) i2p::crypto::HKDF (noiseState->m_CK + 32, nullptr, 0, "LayerAndIVKeys", layerKeys); // TODO: correct domain auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( @@ -617,39 +623,71 @@ namespace i2p clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), layerKeys, layerKeys + 32, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & 0x80, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & 0x40); + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); - // TODO: fill reply - // encrypt reply - if (!noiseState) - { - LogPrint (eLogWarning, "I2NP: Invalid Noise state for short reply encryption"); - return; - } - uint8_t nonce[12]; - memset (nonce, 0, 12); - uint8_t * reply = buf + 1; - for (int j = 0; j < num; j++) - { - nonce[4] = j; // nonce is record # - if (j == i) + if (clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) + { + // we are endpoint, create OutboundTunnelBuildReply + auto otbrm = NewI2NPShortMessage (); + auto payload = otbrm->GetPayload (); + payload[0] = num; // num + payload[1] = i; // slot + payload +=2; + // reply + htobe16buf (payload, 3); payload += 2; // length, TODO + memset (payload, 0, 3); payload += 3; // ClearText: no options, and zero ret code. TODO + // ShortBuildReplyRecords. Exclude ours + uint8_t * records = buf + 1; + if (i > 0) + { + memcpy (payload, records, i*SHORT_TUNNEL_BUILD_RECORD_SIZE); + payload += i*SHORT_TUNNEL_BUILD_RECORD_SIZE; + records += i*SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + if (i < num-1) { - if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState->m_H, 32, noiseState->m_CK, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt - { - LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); - return; - } - } - else - i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState->m_CK, nonce, reply); - reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; + memcpy (payload, records, (num-1-i)*SHORT_TUNNEL_BUILD_RECORD_SIZE); + payload += (num-1-i)*SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + otbrm->len += (payload - otbrm->GetPayload ()); + otbrm->FillI2NPMessageHeader (eI2NPOutboundTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); + uint8_t replyKeys[64]; // (reply key, tag) + i2p::crypto::HKDF (noiseState->m_CK, nullptr, 0, "ReplyKeyAndTag", replyKeys); // TODO: correct domain + uint64_t tag; + memcpy (&tag, replyKeys + 32, 8); + // send garlic to reply tunnel + transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + i2p::garlic::WrapECIESX25519AEADRatchetMessage (otbrm, replyKeys, tag))); } - // TODO: send reply - transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, - CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + else + { + // we are participant, encrypt reply + uint8_t nonce[12]; + memset (nonce, 0, 12); + uint8_t * reply = buf + 1; + for (int j = 0; j < num; j++) + { + nonce[4] = j; // nonce is record # + if (j == i) + { + // TODO: fill reply + if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState->m_H, 32, noiseState->m_CK, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); + return; + } + } + else + i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState->m_CK, nonce, reply); + reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, + CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } return; } record += SHORT_TUNNEL_BUILD_RECORD_SIZE; diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 76030e91..ee143734 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -130,9 +130,12 @@ namespace i2p eI2NPTunnelBuildReply = 22, eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuildReply = 24, - eI2NPShortTunnelBuild = 25 + eI2NPShortTunnelBuild = 25, + eI2NPOutboundTunnelBuildReply = 26 }; + const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80; + const uint8_t TUNNEL_BUILD_RECORD_ENDPOINT_FLAG = 0x40; const int NUM_TUNNEL_BUILD_RECORDS = 8; // DatabaseLookup flags diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index d43483c0..8f515c5d 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -81,8 +81,8 @@ namespace tunnel void TunnelHopConfig::CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) { uint8_t flag = 0; - if (isGateway) flag |= 0x80; - if (isEndpoint) flag |= 0x40; + if (isGateway) flag |= TUNNEL_BUILD_RECORD_GATEWAY_FLAG; + if (isEndpoint) flag |= TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; auto encryptor = ident->CreateEncryptor (nullptr); if (IsECIES ()) { From 83fd289e4651b4e23c2ebc7b7a58222b5fbcf9b6 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Jun 2021 12:49:50 -0400 Subject: [PATCH 42/64] don't re-create noise state for every message --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 9 +++++---- libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++++ libi2pd/I2NPProtocol.cpp | 17 ++++++----------- libi2pd/RouterContext.cpp | 19 ++++++++----------- libi2pd/RouterContext.h | 4 ++-- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 45affde7..55e962d8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -1109,21 +1109,22 @@ namespace garlic bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len) { if (!GetOwner ()) return false; - i2p::crypto::NoiseSymmetricState state (GetNoiseState ()); + m_CurrentNoiseState = GetNoiseState (); // we are Bob - state.MixHash (buf, 32); + m_CurrentNoiseState.MixHash (buf, 32); uint8_t sharedSecret[32]; if (!GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) { LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); return false; } - state.MixKey (sharedSecret); + m_CurrentNoiseState.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, state.m_H, 32, state.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32, + m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Payload for router AEAD verification failed"); return false; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 43e88ca6..cd7b9b40 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -249,6 +249,11 @@ namespace garlic RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState); bool HandleNextMessage (const uint8_t * buf, size_t len); + i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; + + private: + + i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; }; std::shared_ptr WrapECIESX25519AEADRatchetMessage (std::shared_ptr msg, const uint8_t * key, uint64_t tag); diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 5ed875c5..7c4d84c3 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -426,8 +426,8 @@ namespace i2p uint8_t nonce[12]; memset (nonce, 0, 12); auto& noiseState = i2p::context.GetCurrentNoiseState (); - if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt { LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); return false; @@ -611,13 +611,8 @@ namespace i2p return; } auto& noiseState = i2p::context.GetCurrentNoiseState (); - if (!noiseState) - { - LogPrint (eLogWarning, "I2NP: Invalid Noise state for short reply encryption"); - return; - } uint8_t layerKeys[64]; // (layer key, iv key) - i2p::crypto::HKDF (noiseState->m_CK + 32, nullptr, 0, "LayerAndIVKeys", layerKeys); // TODO: correct domain + i2p::crypto::HKDF (noiseState.m_CK + 32, nullptr, 0, "LayerAndIVKeys", layerKeys); // TODO: correct domain auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, @@ -653,7 +648,7 @@ namespace i2p otbrm->len += (payload - otbrm->GetPayload ()); otbrm->FillI2NPMessageHeader (eI2NPOutboundTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); uint8_t replyKeys[64]; // (reply key, tag) - i2p::crypto::HKDF (noiseState->m_CK, nullptr, 0, "ReplyKeyAndTag", replyKeys); // TODO: correct domain + i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "ReplyKeyAndTag", replyKeys); // TODO: correct domain uint64_t tag; memcpy (&tag, replyKeys + 32, 8); // send garlic to reply tunnel @@ -674,14 +669,14 @@ namespace i2p { // TODO: fill reply if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState->m_H, 32, noiseState->m_CK, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + noiseState.m_H, 32, noiseState.m_CK, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt { LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); return; } } else - i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState->m_CK, nonce, reply); + i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState.m_CK, nonce, reply); reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; } transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d1f503bb..78be6305 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -45,10 +45,8 @@ namespace i2p UpdateRouterInfo (); if (IsECIES ()) { - auto initState = new i2p::crypto::NoiseSymmetricState (); - i2p::crypto::InitNoiseNState (*initState, GetIdentity ()->GetEncryptionPublicKey ()); - m_InitialNoiseState.reset (initState); - m_ECIESSession = std::make_shared(*initState); + i2p::crypto::InitNoiseNState (m_InitialNoiseState, GetIdentity ()->GetEncryptionPublicKey ()); + m_ECIESSession = std::make_shared(m_InitialNoiseState); } } @@ -889,27 +887,26 @@ namespace i2p bool RouterContext::DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize) { - if (!m_InitialNoiseState || !m_TunnelDecryptor) return false; // m_InitialNoiseState is h = SHA256(h || hepk) - m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); - m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) + m_CurrentNoiseState = m_InitialNoiseState; + m_CurrentNoiseState.MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false)) { LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); return false; } - m_CurrentNoiseState->MixKey (sharedSecret); + m_CurrentNoiseState.MixKey (sharedSecret); encrypted += 32; uint8_t nonce[12]; memset (nonce, 0, 12); - if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState->m_H, 32, - m_CurrentNoiseState->m_CK + 32, nonce, data, clearTextSize, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState.m_H, 32, + m_CurrentNoiseState.m_CK + 32, nonce, data, clearTextSize, false)) // decrypt { LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); return false; } - m_CurrentNoiseState->MixHash (encrypted, clearTextSize + 16); // h = SHA256(h || ciphertext) + m_CurrentNoiseState.MixHash (encrypted, clearTextSize + 16); // h = SHA256(h || ciphertext) return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 10498b3b..acb33795 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -125,7 +125,7 @@ namespace garlic void SetSupportsV4 (bool supportsV4); void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; - std::unique_ptr& GetCurrentNoiseState () { return m_CurrentNoiseState; }; + i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateStats (); @@ -185,7 +185,7 @@ namespace garlic std::unique_ptr m_NTCP2Keys; std::unique_ptr m_StaticKeys; // for ECIESx25519 - std::unique_ptr m_InitialNoiseState, m_CurrentNoiseState; + i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState; // i18n std::shared_ptr m_Language; From 8708a0076f34c25cd9ffd03eb341d055f8e1b45e Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 9 Jun 2021 22:22:57 +0300 Subject: [PATCH 43/64] fix build with boost < 1.55.0 (closes #1661) Signed-off-by: R4SAS --- libi2pd/NTCP2.cpp | 4 ++++ libi2pd/SSU.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 72e822cd..c231863d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1201,7 +1201,11 @@ namespace transport if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address { // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others +#if (BOOST_VERSION >= 105500) typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; +#else + typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; +#endif m_NTCP2V6Acceptor->set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA)); } #endif diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index e4901f7c..f3da611c 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -70,7 +70,11 @@ namespace transport if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address { // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others +#if (BOOST_VERSION >= 105500) typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; +#else + typedef boost::asio::detail::socket_option::integer ipv6PreferAddr; +#endif m_SocketV6.set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA)); } #endif From a92b93192d843c63f19618c5ad39bd71bba89e31 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Jun 2021 13:24:04 -0400 Subject: [PATCH 44/64] reg.i2p for subscriptions --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index f5316860..a80778a1 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -221,7 +221,7 @@ namespace config { ("addressbook.defaulturl", value()->default_value( "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt" ), "AddressBook subscription URL for initial setup") - ("addressbook.subscriptions", value()->default_value(""), "AddressBook subscriptions URLs, separated by comma") + ("addressbook.subscriptions", value()->default_value("http://reg.i2p/hosts.txt"), "AddressBook subscriptions URLs, separated by comma") ("addressbook.hostsfile", value()->default_value(""), "File to dump addresses in hosts.txt format"); options_description trust("Trust options"); From e412b17f709af249ffa20a08cb111090631e8d0e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 11 Jun 2021 08:34:56 -0400 Subject: [PATCH 45/64] don't publish slow tunnel in LeaseSet if possible --- libi2pd/TunnelPool.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index f5af249a..e45c6090 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -142,16 +142,24 @@ namespace tunnel { std::vector > v; int i = 0; + std::shared_ptr slowTunnel; std::unique_lock l(m_InboundTunnelsMutex); for (const auto& it : m_InboundTunnels) { if (i >= num) break; if (it->IsEstablished ()) { - v.push_back (it); - i++; + if (it->IsSlow () && !slowTunnel) + slowTunnel = it; + else + { + v.push_back (it); + i++; + } } } + if (slowTunnel && (int)v.size () < (num/2+1)) + v.push_back (slowTunnel); return v; } From bce6685d0cda5127ff072aeb6a701b666fcd5d49 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Jun 2021 12:36:54 -0400 Subject: [PATCH 46/64] correct check of ipv4/ipv6 address --- libi2pd/RouterContext.cpp | 4 ++-- libi2pd/RouterInfo.cpp | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 78be6305..50dd6c59 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -484,7 +484,7 @@ namespace i2p addr->ssu->introducers.clear (); port = addr->port; } - // unpiblish NTCP2 addreeses + // unpublish NTCP2 addreeses bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) PublishNTCP2Address (port, false, v4, v6, false); @@ -677,7 +677,7 @@ namespace i2p if (addr->IsPublishedNTCP2 ()) { bool isYgg1 = i2p::util::net::IsYggdrasilAddress (addr->host); - if (addr->host.is_v6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1))) + if (addr->IsV6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1))) { if (addr->host != host) { diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 3035bd31..dcef9463 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -554,7 +554,7 @@ namespace data if (address.IsNTCP2 ()) { WriteString ("NTCP2", s); - if (address.IsPublishedNTCP2 () && !address.host.is_unspecified ()) + if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port) isPublished = true; else { @@ -998,9 +998,16 @@ namespace data for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; - addr->caps &= ~AddressCaps::eV6; - if (addr->host.is_v6 ()) - it = m_Addresses->erase (it); + if (addr->IsV6 ()) + { + if (addr->IsV4 ()) + { + addr->caps &= ~AddressCaps::eV6; + ++it; + } + else + it = m_Addresses->erase (it); + } else ++it; } @@ -1015,9 +1022,16 @@ namespace data for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; - addr->caps &= ~AddressCaps::eV4; - if (addr->host.is_v4 ()) - it = m_Addresses->erase (it); + if (addr->IsV4 ()) + { + if (addr->IsV6 ()) + { + addr->caps &= ~AddressCaps::eV4; + ++it; + } + else + it = m_Addresses->erase (it); + } else ++it; } @@ -1188,7 +1202,7 @@ namespace data for (auto& addr: *m_Addresses) { // TODO: implement SSU - if (addr->transportStyle == eTransportNTCP && (!addr->IsPublishedNTCP2 () || addr->port)) + if (addr->transportStyle == eTransportNTCP && !addr->IsPublishedNTCP2 ()) { addr->caps &= ~(eV4 | eV6); addr->caps |= transports; From 631c8c9870bf48b9a4ff7f57daf82ae28c783251 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Jun 2021 21:19:44 -0400 Subject: [PATCH 47/64] use correct address type for NTCP2 acceptors --- libi2pd/NTCP2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index c231863d..cb200b42 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1170,7 +1170,7 @@ namespace transport if (!address) continue; if (address->IsPublishedNTCP2 () && address->port) { - if (address->host.is_v4()) + if (address->IsV4()) { try { @@ -1189,7 +1189,7 @@ namespace transport auto conn = std::make_shared(*this); m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); } - else if (address->host.is_v6() && (context.SupportsV6 () || context.SupportsMesh ())) + else if (address->IsV6() && (context.SupportsV6 () || context.SupportsMesh ())) { m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ())); try From 1d973bc3aca52e2aab02876fa6d851911c522d15 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 15 Jun 2021 17:55:09 +0300 Subject: [PATCH 48/64] [webconsole] remove extra line break Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index e184dd06..dadb2f8f 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -691,7 +691,7 @@ namespace http { if (Daemon.gracefulShutdownInterval) s << " " << tr("Cancel graceful shutdown") << "\r\n"; else - s << " " << tr("Start graceful shutdown") << "
    \r\n"; + s << " " << tr("Start graceful shutdown") << "\r\n"; #elif defined(WIN32_APP) if (i2p::util::DaemonWin32::Instance().isGraceful) s << " " << tr("Cancel graceful shutdown") << "\r\n"; From 29c1173e148da874755052a0d4d9606465dc5e25 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 15 Jun 2021 23:22:11 +0300 Subject: [PATCH 49/64] [i18n] fixes in translations Signed-off-by: R4SAS --- i18n/Turkmen.cpp | 15 +++++++-------- i18n/Ukrainian.cpp | 11 +++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/i18n/Turkmen.cpp b/i18n/Turkmen.cpp index 93bd92fe..0edc9a6e 100644 --- a/i18n/Turkmen.cpp +++ b/i18n/Turkmen.cpp @@ -61,7 +61,7 @@ namespace turkmen // language {"failed to send request to upstream", "öý eýesi proksi üçin haýyş iberip bilmedi"}, {"No Reply From socks proxy", "Jorap proksi serwerinden hiç hili jogap ýok"}, {"cannot connect", "birikdirip bilmedi"}, - {"http out proxy not implemented", "daşarky http proksi serwerini goldamak amala aşyrylmaýar"}, + {"http out proxy not implemented", "daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"}, {"cannot connect to upstream http proxy", "ýokary akym HTTP proksi serwerine birigip bilmedi"}, {"Host is down", "Salgy elýeterli däl"}, {"Can't create connection to requested host, it may be down. Please try again later.", @@ -89,7 +89,7 @@ namespace turkmen // language {"Local destinations", "Ýerli ýerler"}, {"LeaseSets", "Lizset"}, {"Tunnels", "Tuneller"}, - {"Transit tunnels", "Tranzit Tunels"}, + {"Transit tunnels", "Tranzit tunels"}, {"Transports", "Daşamak"}, {"I2P tunnels", "I2P tuneller"}, {"SAM sessions", "SAM Sessiýasy"}, @@ -108,7 +108,7 @@ namespace turkmen // language {"Uptime", "Onlaýn onlaýn sözlügi"}, {"Network status", "Tor ýagdaýy"}, {"Network status v6", "Tor ýagdaýy v6"}, - {"Stopping in", "soň duruň"}, + {"Stopping in", "Soň duruň"}, {"Family", "Maşgala"}, {"Tunnel creation success rate", "Gurlan teneller üstünlikli gurlan teneller"}, {"Received", "Alnan"}, @@ -122,10 +122,9 @@ namespace turkmen // language {"Router Caps", "Baýdaklar marşruteri"}, {"Version", "Wersiýasy"}, {"Our external address", "Daşarky salgymyz"}, - {"supported", "Goldanýar"}, + {"supported", "goldanýar"}, {"Routers", "Marşrutizatorlar"}, {"Floodfills", "Fludfillar"}, - {"LeaseSets", "Lizsetllar"}, {"Client Tunnels", "Müşderi tunelleri"}, {"Transit Tunnels", "Tranzit Tunelleri"}, {"Services", "Hyzmatlar"}, @@ -150,7 +149,7 @@ namespace turkmen // language {"Destination", "Maksat"}, {"Amount", "Sany"}, {"Incoming Tags", "Gelýän bellikler"}, - {"Tags sessions", "Sapaklar Tag."}, + {"Tags sessions", "Sapaklar bellikler"}, {"Status", "Ýagdaýy"}, // ShowLocalDestination {"Local Destination", "Ýerli maksat"}, @@ -178,7 +177,7 @@ namespace turkmen // language {"Start graceful shutdown", "Tekiz durmak"}, {"Force shutdown", "Mejbury duralga"}, {"Note: any action done here are not persistent and not changes your config files.", - "Bellik: Bu ýerde öndürilen islendik çäre hemişelik däl we konfigurasiýa faýllaryňyzy üýtgetmeýär.."}, + "Bellik: Bu ýerde öndürilen islendik çäre hemişelik däl we konfigurasiýa faýllaryňyzy üýtgetmeýär."}, {"Logging level", "Giriş derejesi"}, {"Transit tunnels limit", "Tranzit tunelleriniň çägi"}, {"Change", "Üýtgetmek"}, @@ -217,7 +216,7 @@ namespace turkmen // language {"Description", "Beýany"}, {"A bit information about service on domain", "Domendäki hyzmat barada käbir maglumatlar"}, {"Submit", "Iber"}, - {"Domain can't end with .b32.i2p", "Domain .b32.i2p bilen gutaryp bilmez."}, + {"Domain can't end with .b32.i2p", "Domain .b32.i2p bilen gutaryp bilmez"}, {"Domain must end with .i2p", "Domeni .i2p bilen gutarmaly"}, {"Such destination is not found", "Bu barmaly ýer tapylmady"}, {"", ""}, diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp index 05e7c786..11878cde 100644 --- a/i18n/Ukrainian.cpp +++ b/i18n/Ukrainian.cpp @@ -86,17 +86,17 @@ namespace ukrainian // language // ShowPageHead {"Main page", "Головна"}, {"Router commands", "Команди роутера"}, - {"Local destinations", "Локальні признач."}, + {"Local destinations", "Локальні призначення"}, {"LeaseSets", "Лізсети"}, {"Tunnels", "Тунелі"}, - {"Transit tunnels", "Транзит. тунелі"}, + {"Transit tunnels", "Транзитні тунелі"}, {"Transports", "Транспорти"}, {"I2P tunnels", "I2P тунелі"}, {"SAM sessions", "SAM сесії"}, // Network Status {"OK", "OK"}, {"Testing", "Тестування"}, - {"Firewalled", "Файрвол"}, + {"Firewalled", "Заблоковано ззовні"}, {"Unknown", "Невідомо"}, {"Proxy", "Проксі"}, {"Mesh", "MESH-мережа"}, @@ -125,7 +125,6 @@ namespace ukrainian // language {"supported", "підтримується"}, {"Routers", "Роутери"}, {"Floodfills", "Флудфіли"}, - {"LeaseSets", "Лізсети"}, {"Client Tunnels", "Клієнтські Тунелі"}, {"Transit Tunnels", "Транзитні Тунелі"}, {"Services", "Сервіси"}, @@ -153,7 +152,7 @@ namespace ukrainian // language {"Tags sessions", "Сесії тегів"}, {"Status", "Статус"}, // ShowLocalDestination - {"Local Destination", "Локальне Призначення"}, + {"Local Destination", "Локальні Призначення"}, {"Streams", "Потоки"}, {"Close stream", "Закрити потік"}, // ShowI2CPLocalDestination @@ -197,7 +196,7 @@ namespace ukrainian // language {"Unknown page", "Невідома сторінка"}, // HandleCommand, ShowError {"Invalid token", "Невірний токен"}, - {"SUCCESS", "ВДАЛО"}, + {"SUCCESS", "УСПІШНО"}, {"ERROR", "ПОМИЛКА"}, {"Unknown command", "Невідома команда"}, {"Command accepted", "Команда прийнята"}, From eebea7b342e607f312b5d832e16c0ab08eeb38eb Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 15 Jun 2021 23:22:59 +0300 Subject: [PATCH 50/64] [i18n] Add translation source in gettext format Signed-off-by: R4SAS --- i18n/English.po | 741 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 741 insertions(+) create mode 100644 i18n/English.po diff --git a/i18n/English.po b/i18n/English.po new file mode 100644 index 00000000..e9317528 --- /dev/null +++ b/i18n/English.po @@ -0,0 +1,741 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: i2pd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-06-15 20:41+0300\n" +"PO-Revision-Date: 2021-06-15 20:42+0300\n" +"Last-Translator: \n" +"Language-Team: PurpleI2P\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 3.0\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-Basepath: .\n" +"X-Poedit-KeywordsList: ;tr\n" +"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n" +"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n" + +#: daemon/HTTPServer.cpp:85 +msgid "Disabled" +msgstr "" + +#: daemon/HTTPServer.cpp:86 +msgid "Enabled" +msgstr "" + +#: daemon/HTTPServer.cpp:141 +msgid "days" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: daemon/HTTPServer.cpp:145 +msgid "hours" +msgid_plural "hours" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: daemon/HTTPServer.cpp:149 +msgid "minutes" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: daemon/HTTPServer.cpp:152 +msgid "seconds" +msgid_plural "seconds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: daemon/HTTPServer.cpp:160 daemon/HTTPServer.cpp:188 +msgid "KiB" +msgstr "" + +#: daemon/HTTPServer.cpp:162 +msgid "MiB" +msgstr "" + +#: daemon/HTTPServer.cpp:164 +msgid "GiB" +msgstr "" + +#: daemon/HTTPServer.cpp:181 +msgid "building" +msgstr "" + +#: daemon/HTTPServer.cpp:182 +msgid "failed" +msgstr "" + +#: daemon/HTTPServer.cpp:183 +msgid "expiring" +msgstr "" + +#: daemon/HTTPServer.cpp:184 +msgid "established" +msgstr "" + +#: daemon/HTTPServer.cpp:185 +msgid "unknown" +msgstr "" + +#: daemon/HTTPServer.cpp:187 +msgid "exploratory" +msgstr "" + +#: daemon/HTTPServer.cpp:223 +msgid "i2pd webconsole" +msgstr "" + +#: daemon/HTTPServer.cpp:226 +msgid "Main page" +msgstr "" + +#: daemon/HTTPServer.cpp:227 daemon/HTTPServer.cpp:683 +msgid "Router commands" +msgstr "" + +#: daemon/HTTPServer.cpp:228 +msgid "Local destinations" +msgstr "" + +#: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:382 +#: daemon/HTTPServer.cpp:463 daemon/HTTPServer.cpp:469 +#: daemon/HTTPServer.cpp:599 daemon/HTTPServer.cpp:642 +#: daemon/HTTPServer.cpp:646 +msgid "LeaseSets" +msgstr "" + +#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:652 +msgid "Tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:727 +#: daemon/HTTPServer.cpp:743 +msgid "Transit tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:234 daemon/HTTPServer.cpp:792 +msgid "Transports" +msgstr "" + +#: daemon/HTTPServer.cpp:235 +msgid "I2P tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:237 daemon/HTTPServer.cpp:854 +#: daemon/HTTPServer.cpp:864 +msgid "SAM sessions" +msgstr "" + +#: daemon/HTTPServer.cpp:253 daemon/HTTPServer.cpp:1254 +#: daemon/HTTPServer.cpp:1257 daemon/HTTPServer.cpp:1260 +#: daemon/HTTPServer.cpp:1274 daemon/HTTPServer.cpp:1319 +#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1325 +msgid "ERROR" +msgstr "" + +#: daemon/HTTPServer.cpp:260 +msgid "OK" +msgstr "" + +#: daemon/HTTPServer.cpp:261 +msgid "Testing" +msgstr "" + +#: daemon/HTTPServer.cpp:262 +msgid "Firewalled" +msgstr "" + +#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:284 +#: daemon/HTTPServer.cpp:370 +msgid "Unknown" +msgstr "" + +#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:394 +#: daemon/HTTPServer.cpp:395 daemon/HTTPServer.cpp:922 +#: daemon/HTTPServer.cpp:931 +msgid "Proxy" +msgstr "" + +#: daemon/HTTPServer.cpp:265 +msgid "Mesh" +msgstr "" + +#: daemon/HTTPServer.cpp:268 +msgid "Error" +msgstr "" + +#: daemon/HTTPServer.cpp:272 +msgid "Clock skew" +msgstr "" + +#: daemon/HTTPServer.cpp:275 +msgid "Offline" +msgstr "" + +#: daemon/HTTPServer.cpp:278 +msgid "Symmetric NAT" +msgstr "" + +#: daemon/HTTPServer.cpp:290 +msgid "Uptime" +msgstr "" + +#: daemon/HTTPServer.cpp:293 +msgid "Network status" +msgstr "" + +#: daemon/HTTPServer.cpp:298 +msgid "Network status v6" +msgstr "" + +#: daemon/HTTPServer.cpp:304 daemon/HTTPServer.cpp:311 +msgid "Stopping in" +msgstr "" + +#: daemon/HTTPServer.cpp:318 +msgid "Family" +msgstr "" + +#: daemon/HTTPServer.cpp:319 +msgid "Tunnel creation success rate" +msgstr "" + +#: daemon/HTTPServer.cpp:320 +msgid "Received" +msgstr "" + +#: daemon/HTTPServer.cpp:322 daemon/HTTPServer.cpp:325 +#: daemon/HTTPServer.cpp:328 +msgid "KiB/s" +msgstr "" + +#: daemon/HTTPServer.cpp:323 +msgid "Sent" +msgstr "" + +#: daemon/HTTPServer.cpp:326 +msgid "Transit" +msgstr "" + +#: daemon/HTTPServer.cpp:329 +msgid "Data path" +msgstr "" + +#: daemon/HTTPServer.cpp:332 +msgid "Hidden content. Press on text to see." +msgstr "" + +#: daemon/HTTPServer.cpp:335 +msgid "Router Ident" +msgstr "" + +#: daemon/HTTPServer.cpp:337 +msgid "Router Family" +msgstr "" + +#: daemon/HTTPServer.cpp:338 +msgid "Router Caps" +msgstr "" + +#: daemon/HTTPServer.cpp:339 +msgid "Version" +msgstr "" + +#: daemon/HTTPServer.cpp:340 +msgid "Our external address" +msgstr "" + +#: daemon/HTTPServer.cpp:348 +msgid "supported" +msgstr "" + +#: daemon/HTTPServer.cpp:380 +msgid "Routers" +msgstr "" + +#: daemon/HTTPServer.cpp:381 +msgid "Floodfills" +msgstr "" + +#: daemon/HTTPServer.cpp:388 daemon/HTTPServer.cpp:908 +msgid "Client Tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:389 +msgid "Transit Tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:393 +msgid "Services" +msgstr "" + +#: daemon/HTTPServer.cpp:407 daemon/HTTPServer.cpp:419 +msgid "Local Destinations" +msgstr "" + +#: daemon/HTTPServer.cpp:442 +msgid "Encrypted B33 address" +msgstr "" + +#: daemon/HTTPServer.cpp:451 +msgid "Address registration line" +msgstr "" + +#: daemon/HTTPServer.cpp:456 +msgid "Domain" +msgstr "" + +#: daemon/HTTPServer.cpp:457 +msgid "Generate" +msgstr "" + +#: daemon/HTTPServer.cpp:458 +msgid "" +"Note: result string can be used only for registering 2LD domains " +"(example.i2p). For registering subdomains please use i2pd-tools." +msgstr "" + +#: daemon/HTTPServer.cpp:464 +msgid "Address" +msgstr "" + +#: daemon/HTTPServer.cpp:464 +msgid "Type" +msgstr "" + +#: daemon/HTTPServer.cpp:464 +msgid "EncType" +msgstr "" + +#: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:657 +msgid "Inbound tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:489 +#: daemon/HTTPServer.cpp:662 daemon/HTTPServer.cpp:672 +msgid "ms" +msgstr "" + +#: daemon/HTTPServer.cpp:484 daemon/HTTPServer.cpp:667 +msgid "Outbound tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:496 +msgid "Tags" +msgstr "" + +#: daemon/HTTPServer.cpp:496 +msgid "Incoming" +msgstr "" + +#: daemon/HTTPServer.cpp:503 daemon/HTTPServer.cpp:506 +msgid "Outgoing" +msgstr "" + +#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:520 +msgid "Destination" +msgstr "" + +#: daemon/HTTPServer.cpp:504 +msgid "Amount" +msgstr "" + +#: daemon/HTTPServer.cpp:511 +msgid "Incoming Tags" +msgstr "" + +#: daemon/HTTPServer.cpp:519 daemon/HTTPServer.cpp:522 +msgid "Tags sessions" +msgstr "" + +#: daemon/HTTPServer.cpp:520 +msgid "Status" +msgstr "" + +#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:584 +msgid "Local Destination" +msgstr "" + +#: daemon/HTTPServer.cpp:538 daemon/HTTPServer.cpp:887 +msgid "Streams" +msgstr "" + +#: daemon/HTTPServer.cpp:560 +msgid "Close stream" +msgstr "" + +#: daemon/HTTPServer.cpp:589 +msgid "I2CP session not found" +msgstr "" + +#: daemon/HTTPServer.cpp:592 +msgid "I2CP is not enabled" +msgstr "" + +#: daemon/HTTPServer.cpp:618 +msgid "Invalid" +msgstr "" + +#: daemon/HTTPServer.cpp:621 +msgid "Store type" +msgstr "" + +#: daemon/HTTPServer.cpp:622 +msgid "Expires" +msgstr "" + +#: daemon/HTTPServer.cpp:627 +msgid "Non Expired Leases" +msgstr "" + +#: daemon/HTTPServer.cpp:630 +msgid "Gateway" +msgstr "" + +#: daemon/HTTPServer.cpp:631 +msgid "TunnelID" +msgstr "" + +#: daemon/HTTPServer.cpp:632 +msgid "EndDate" +msgstr "" + +#: daemon/HTTPServer.cpp:642 +msgid "not floodfill" +msgstr "" + +#: daemon/HTTPServer.cpp:653 +msgid "Queue size" +msgstr "" + +#: daemon/HTTPServer.cpp:684 +msgid "Run peer test" +msgstr "" + +#: daemon/HTTPServer.cpp:687 +msgid "Decline transit tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:689 +msgid "Accept transit tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:692 daemon/HTTPServer.cpp:697 +msgid "Cancel graceful shutdown" +msgstr "" + +#: daemon/HTTPServer.cpp:694 daemon/HTTPServer.cpp:699 +msgid "Start graceful shutdown" +msgstr "" + +#: daemon/HTTPServer.cpp:701 +msgid "Force shutdown" +msgstr "" + +#: daemon/HTTPServer.cpp:704 +msgid "" +"Note: any action done here are not persistent and not changes your " +"config files." +msgstr "" + +#: daemon/HTTPServer.cpp:706 +msgid "Logging level" +msgstr "" + +#: daemon/HTTPServer.cpp:714 +msgid "Transit tunnels limit" +msgstr "" + +#: daemon/HTTPServer.cpp:719 +msgid "Change" +msgstr "" + +#: daemon/HTTPServer.cpp:743 +msgid "no transit tunnels currently built" +msgstr "" + +#: daemon/HTTPServer.cpp:848 daemon/HTTPServer.cpp:871 +msgid "SAM disabled" +msgstr "" + +#: daemon/HTTPServer.cpp:864 +msgid "no sessions currently running" +msgstr "" + +#: daemon/HTTPServer.cpp:877 +msgid "SAM session not found" +msgstr "" + +#: daemon/HTTPServer.cpp:882 +msgid "SAM Session" +msgstr "" + +#: daemon/HTTPServer.cpp:939 +msgid "Server Tunnels" +msgstr "" + +#: daemon/HTTPServer.cpp:955 +msgid "Client Forwards" +msgstr "" + +#: daemon/HTTPServer.cpp:969 +msgid "Server Forwards" +msgstr "" + +#: daemon/HTTPServer.cpp:1175 +msgid "Unknown page" +msgstr "" + +#: daemon/HTTPServer.cpp:1194 +msgid "Invalid token" +msgstr "" + +#: daemon/HTTPServer.cpp:1252 daemon/HTTPServer.cpp:1309 +#: daemon/HTTPServer.cpp:1337 +msgid "SUCCESS" +msgstr "" + +#: daemon/HTTPServer.cpp:1252 +msgid "Stream closed" +msgstr "" + +#: daemon/HTTPServer.cpp:1254 +msgid "Stream not found or already was closed" +msgstr "" + +#: daemon/HTTPServer.cpp:1257 +msgid "Destination not found" +msgstr "" + +#: daemon/HTTPServer.cpp:1260 +msgid "StreamID can't be null" +msgstr "" + +#: daemon/HTTPServer.cpp:1262 daemon/HTTPServer.cpp:1327 +msgid "Return to destination page" +msgstr "" + +#: daemon/HTTPServer.cpp:1263 daemon/HTTPServer.cpp:1276 +msgid "You will be redirected back in 5 seconds" +msgstr "" + +#: daemon/HTTPServer.cpp:1274 +msgid "Transit tunnels count must not exceed 65535" +msgstr "" + +#: daemon/HTTPServer.cpp:1275 daemon/HTTPServer.cpp:1338 +msgid "Back to commands list" +msgstr "" + +#: daemon/HTTPServer.cpp:1311 +msgid "Register at reg.i2p" +msgstr "" + +#: daemon/HTTPServer.cpp:1312 +msgid "Description" +msgstr "" + +#: daemon/HTTPServer.cpp:1312 +msgid "A bit information about service on domain" +msgstr "" + +#: daemon/HTTPServer.cpp:1313 +msgid "Submit" +msgstr "" + +#: daemon/HTTPServer.cpp:1319 +msgid "Domain can't end with .b32.i2p" +msgstr "" + +#: daemon/HTTPServer.cpp:1322 +msgid "Domain must end with .i2p" +msgstr "" + +#: daemon/HTTPServer.cpp:1325 +msgid "Such destination is not found" +msgstr "" + +#: daemon/HTTPServer.cpp:1333 +msgid "Unknown command" +msgstr "" + +#: daemon/HTTPServer.cpp:1337 +msgid "Command accepted" +msgstr "" + +#: daemon/HTTPServer.cpp:1339 +msgid "You will be redirected in 5 seconds" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:157 +msgid "Proxy error" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:165 +msgid "Proxy info" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:173 +msgid "Proxy error: Host not found" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:174 +msgid "Remote host not found in router's addressbook" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:175 +msgid "You may try to find this host on jump services below" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288 +#: libi2pd_client/HTTPProxy.cpp:365 +msgid "Invalid request" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:273 +msgid "Proxy unable to parse your request" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:288 +msgid "addresshelper is not supported" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:297 libi2pd_client/HTTPProxy.cpp:306 +#: libi2pd_client/HTTPProxy.cpp:385 +msgid "Host" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:297 +msgid "added to router's addressbook from helper" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:298 libi2pd_client/HTTPProxy.cpp:307 +msgid "Click" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:298 libi2pd_client/HTTPProxy.cpp:308 +msgid "here" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:298 +msgid "to proceed" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:299 libi2pd_client/HTTPProxy.cpp:309 +msgid "Addresshelper found" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:306 +msgid "already in router's addressbook" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:308 +msgid "to update record" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:322 +msgid "Invalid Request" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:322 +msgid "invalid request uri" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:365 +msgid "Can't detect destination host from request" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:382 libi2pd_client/HTTPProxy.cpp:386 +msgid "Outproxy failure" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:382 +msgid "bad outproxy settings" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:385 +msgid "not inside I2P network, but outproxy is not enabled" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:474 +msgid "unknown outproxy url" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:480 +msgid "cannot resolve upstream proxy" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:488 +msgid "hostname too long" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:515 +msgid "cannot connect to upstream socks proxy" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:521 +msgid "Cannot negotiate with socks proxy" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:563 +msgid "CONNECT error" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:563 +msgid "Failed to Connect" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:574 libi2pd_client/HTTPProxy.cpp:600 +msgid "socks proxy error" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:582 +msgid "failed to send request to upstream" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:603 +msgid "No Reply From socks proxy" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:610 +msgid "cannot connect" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:610 +msgid "http out proxy not implemented" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:611 +msgid "cannot connect to upstream http proxy" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:644 +msgid "Host is down" +msgstr "" + +#: libi2pd_client/HTTPProxy.cpp:644 +msgid "" +"Can't create connection to requested host, it may be down. Please try again " +"later." +msgstr "" + +#~ msgid "day" +#~ msgid_plural "days" +#~ msgstr[0] "день" +#~ msgstr[1] "дня" +#~ msgstr[2] "дней" From b91eaf548798a64f54f4be900e0e2289d9f440ba Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 15 Jun 2021 23:30:28 +0300 Subject: [PATCH 51/64] [i18n] update gettext description Signed-off-by: R4SAS --- i18n/English.po | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/i18n/English.po b/i18n/English.po index e9317528..37acdb65 100644 --- a/i18n/English.po +++ b/i18n/English.po @@ -1,15 +1,15 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# i2pd +# Copyright (C) 2021 PurpleI2P team +# This file is distributed under the same license as the i2pd package. +# R4SAS , 2021. # msgid "" msgstr "" "Project-Id-Version: i2pd\n" -"Report-Msgid-Bugs-To: \n" +"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n" "POT-Creation-Date: 2021-06-15 20:41+0300\n" "PO-Revision-Date: 2021-06-15 20:42+0300\n" -"Last-Translator: \n" +"Last-Translator: R4SAS\n" "Language-Team: PurpleI2P\n" "Language: ru\n" "MIME-Version: 1.0\n" @@ -733,9 +733,3 @@ msgid "" "Can't create connection to requested host, it may be down. Please try again " "later." msgstr "" - -#~ msgid "day" -#~ msgid_plural "days" -#~ msgstr[0] "день" -#~ msgstr[1] "дня" -#~ msgstr[2] "дней" From 0bacd4df5fcaace1750fe84853b63fef125f8d8b Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 15 Jun 2021 23:43:33 +0300 Subject: [PATCH 52/64] [i18n] update gettext description Signed-off-by: R4SAS --- i18n/English.po | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/i18n/English.po b/i18n/English.po index 37acdb65..10b5b01e 100644 --- a/i18n/English.po +++ b/i18n/English.po @@ -7,16 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: i2pd\n" "Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n" -"POT-Creation-Date: 2021-06-15 20:41+0300\n" -"PO-Revision-Date: 2021-06-15 20:42+0300\n" -"Last-Translator: R4SAS\n" -"Language-Team: PurpleI2P\n" -"Language: ru\n" +"POT-Creation-Date: 2021-06-15 17:40\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Generator: Poedit 3.0\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Basepath: .\n" @@ -37,28 +31,22 @@ msgid "days" msgid_plural "days" msgstr[0] "" msgstr[1] "" -msgstr[2] "" - #: daemon/HTTPServer.cpp:145 msgid "hours" msgid_plural "hours" msgstr[0] "" msgstr[1] "" -msgstr[2] "" - #: daemon/HTTPServer.cpp:149 msgid "minutes" msgid_plural "minutes" msgstr[0] "" msgstr[1] "" -msgstr[2] "" #: daemon/HTTPServer.cpp:152 msgid "seconds" msgid_plural "seconds" msgstr[0] "" msgstr[1] "" -msgstr[2] "" #: daemon/HTTPServer.cpp:160 daemon/HTTPServer.cpp:188 msgid "KiB" @@ -328,6 +316,7 @@ msgstr "" #: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:489 #: daemon/HTTPServer.cpp:662 daemon/HTTPServer.cpp:672 +#: Means milliseconds msgid "ms" msgstr "" From c06a5609464c88a6edf4e38a8cc3daa34eb6b65e Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 00:13:26 +0300 Subject: [PATCH 53/64] [i18n] use xgettext compatible function format for plural Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 8 ++++---- i18n/English.cpp | 5 +---- i18n/I18N.h | 4 ++-- i18n/I18N_langs.h | 8 ++++---- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index dadb2f8f..7eb296c4 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -138,18 +138,18 @@ namespace http { int num; if ((num = seconds / 86400) > 0) { - s << num << " " << tr("days", num) << ", "; + s << num << " " << tr("day", "days", num) << ", "; seconds -= num * 86400; } if ((num = seconds / 3600) > 0) { - s << num << " " << tr("hours", num) << ", "; + s << num << " " << tr("hour", "hours", num) << ", "; seconds -= num * 3600; } if ((num = seconds / 60) > 0) { - s << num << " " << tr("minutes", num) << ", "; + s << num << " " << tr("minute", "minutes", num) << ", "; seconds -= num * 60; } - s << seconds << " " << tr("seconds", seconds); + s << seconds << " " << tr("second", "seconds", seconds); } static void ShowTraffic (std::stringstream& s, uint64_t bytes) diff --git a/i18n/English.cpp b/i18n/English.cpp index 8b13279a..6015f8e1 100644 --- a/i18n/English.cpp +++ b/i18n/English.cpp @@ -13,6 +13,7 @@ #include "I18N.h" // English localization file +// This is an example translation file without strings in it. namespace i2p { @@ -33,10 +34,6 @@ namespace english // language static std::map> plurals { - {"days", {"day", "days"}}, - {"hours", {"hour", "hours"}}, - {"minutes", {"minute", "minutes"}}, - {"seconds", {"second", "seconds"}}, {"", {"", ""}}, }; diff --git a/i18n/I18N.h b/i18n/I18N.h index 7d0baf1a..4857df15 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -32,9 +32,9 @@ namespace i18n return i2p::context.GetLanguage ()->GetString (arg); } - inline std::string translate (const std::string& arg, const int& n) + inline std::string translate (const std::string& arg, const std::string& arg2, const int& n) { - return i2p::context.GetLanguage ()->GetPlural (arg, n); + return i2p::context.GetLanguage ()->GetPlural (arg, arg2, n); } } // i18n } // i2p diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 435141bf..3c560a2f 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -35,12 +35,12 @@ namespace i18n } } - std::string GetPlural (const std::string& arg, const int& n) const + std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const { - const auto it = m_Plurals.find(arg); - if (it == m_Plurals.end()) + const auto it = m_Plurals.find(arg2); + if (it == m_Plurals.end()) // not found, fallback to english { - return arg; + return n == 1 ? arg : arg2; } else { From dc75868bd392fe86e9546a924d7d184d288ef939 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Jun 2021 19:09:36 -0400 Subject: [PATCH 54/64] check Alice's IP address in PeerTest --- libi2pd/SSUSession.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 339ac8df..59ee578b 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -383,7 +383,7 @@ namespace transport { // tell out peer to now assign relay tag flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; - *payload = 2; payload++; // 1 byte length + *payload = 2; payload++; // 1 byte length uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG htobe16buf (payload, flags); payload += 2; @@ -1073,7 +1073,10 @@ namespace transport LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob"); auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest if (session && session->m_State == eSessionStateEstablished) - session->Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Alice + { + const auto& ep = session->GetRemoteEndpoint (); // Alice's endpoint as known to Bob + session->SendPeerTest (nonce, ep.address (), ep.port (), introKey, false, true); // send back to Alice + } m_Server.RemovePeerTest (nonce); // nonce has been used break; } @@ -1093,9 +1096,12 @@ namespace transport if (port) { LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie"); - m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob - SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob + if (!addr.is_unspecified () && !i2p::util::net::IsInReservedRange(addr)) + { + m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); + SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob + } } else { From 2ba3f4758a33769d6f50c12beda0a7b0944c5021 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 17:56:08 +0300 Subject: [PATCH 55/64] [i18n] move gettext translation template to contrib Signed-off-by: R4SAS --- {i18n => contrib/i18n}/English.po | 8 ++++---- contrib/i18n/regex.txt | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) rename {i18n => contrib/i18n}/English.po (99%) create mode 100644 contrib/i18n/regex.txt diff --git a/i18n/English.po b/contrib/i18n/English.po similarity index 99% rename from i18n/English.po rename to contrib/i18n/English.po index 10b5b01e..1de2ddaa 100644 --- a/i18n/English.po +++ b/contrib/i18n/English.po @@ -27,23 +27,23 @@ msgid "Enabled" msgstr "" #: daemon/HTTPServer.cpp:141 -msgid "days" +msgid "day" msgid_plural "days" msgstr[0] "" msgstr[1] "" #: daemon/HTTPServer.cpp:145 -msgid "hours" +msgid "hour" msgid_plural "hours" msgstr[0] "" msgstr[1] "" #: daemon/HTTPServer.cpp:149 -msgid "minutes" +msgid "minute" msgid_plural "minutes" msgstr[0] "" msgstr[1] "" #: daemon/HTTPServer.cpp:152 -msgid "seconds" +msgid "second" msgid_plural "seconds" msgstr[0] "" msgstr[1] "" diff --git a/contrib/i18n/regex.txt b/contrib/i18n/regex.txt new file mode 100644 index 00000000..768a4b01 --- /dev/null +++ b/contrib/i18n/regex.txt @@ -0,0 +1,7 @@ +Regex for transforming gettext translations to our format + +msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\nmsgstr\[1\]\ \"(.*)\"\n(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)? +#{"$2", {"$3", "$4", "$6", "$8", "$10"}},\n + +msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n +{"$1", "$2"},\n From 954711e98069da66c06f91c5c5ea38a81c8c0126 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 17:57:02 +0300 Subject: [PATCH 56/64] [i18n] pull afrikaans translation from crowdin Signed-off-by: R4SAS --- i18n/Afrikaans.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++++ i18n/I18N.h | 4 ++- i18n/I18N_langs.h | 7 +++-- 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 i18n/Afrikaans.cpp diff --git a/i18n/Afrikaans.cpp b/i18n/Afrikaans.cpp new file mode 100644 index 00000000..098c1105 --- /dev/null +++ b/i18n/Afrikaans.cpp @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2021, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Afrikaans localization file +// This is an example translation file without strings in it. + +namespace i2p +{ +namespace i18n +{ +namespace afrikaans // language +{ + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + static std::map strings + { + {"Disabled", "Gedeaktiveer"}, + {"Enabled", "Geaktiveer"}, + {"failed", "Het misluk"}, + {"unknown", "onbekend"}, + {"Tunnels", "Tonnels"}, + {"Transit tunnels", "Deurgang tonnels"}, + {"I2P tunnels", "I2P tonnels"}, + {"SAM sessions", "SAM sessies"}, + {"OK", "LEKKER"}, + {"Testing", "Besig om te toets"}, + {"Firewalled", "Vuurmuur'd"}, + {"Unknown", "Onbekend"}, + {"Error", "Fout"}, + {"Offline", "Aflyn"}, + {"Uptime", "Optyd"}, + {"Network status", "Netwerk status"}, + {"Network status v6", "Netwerk status v6"}, + {"Family", "Familie"}, + {"Received", "Ontvang"}, + {"Sent", "Gestuur"}, + {"Hidden content. Press on text to see.", "Hidden content. Druk om te sien."}, + {"Router Ident", "Router Ident"}, + {"Router Family", "Router Familie"}, + {"", ""}, + }; + + static std::map> plurals + { + {"days", {"dag", "dae"}}, + {"hours", {"uur", "ure"}}, + {"minutes", {"minuut", "minute"}}, + {"seconds", {"seconde", "sekondes"}}, + {"", {"", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/I18N.h b/i18n/I18N.h index 4857df15..272f65e8 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -17,7 +17,9 @@ namespace i18n { inline void SetLanguage(const std::string &lang) { - if (!lang.compare("russian")) + if (!lang.compare("afrikaans")) + i2p::context.SetLanguage (i2p::i18n::afrikaans::GetLocale()); + else if (!lang.compare("russian")) i2p::context.SetLanguage (i2p::i18n::russian::GetLocale()); else if (!lang.compare("turkmen")) i2p::context.SetLanguage (i2p::i18n::turkmen::GetLocale()); diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 3c560a2f..181a4793 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -56,9 +56,10 @@ namespace i18n }; // Add localization here with language name as namespace - namespace english { std::shared_ptr GetLocale (); } - namespace russian { std::shared_ptr GetLocale (); } - namespace turkmen { std::shared_ptr GetLocale (); } + namespace afrikaans { std::shared_ptr GetLocale (); } + namespace english { std::shared_ptr GetLocale (); } + namespace russian { std::shared_ptr GetLocale (); } + namespace turkmen { std::shared_ptr GetLocale (); } namespace ukrainian { std::shared_ptr GetLocale (); } } // i18n From ac594dbd2646542b9a58cfb58c446638ca681015 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 19:12:05 +0300 Subject: [PATCH 57/64] Update status badges in README --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1aa96fb0..92a2f46f 100644 --- a/README.md +++ b/README.md @@ -68,15 +68,15 @@ Build instructions: **Supported systems:** -* GNU/Linux - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) +* GNU/Linux - [![Build on Ubuntu](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml) * CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/) * Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc. -* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd) -* Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) +* Windows - [![Build on Windows](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml) +* Mac OS X - [![Build on OSX](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml) * Docker image - [![Build Status](https://img.shields.io/docker/cloud/build/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd/builds/) -* Snap -* FreeBSD -* Android +* Snap - [![i2pd](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![i2pd](https://snapcraft.io/i2pd/trending.svg?name=0)](https://snapcraft.io/i2pd) +* FreeBSD - [![Build on FreeBSD](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml) +* Android - [![Android CI](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml/badge.svg)](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml) * iOS Using i2pd From a6be32392d153b57ac266b5b4232d5962bd166a3 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 20:41:41 +0000 Subject: [PATCH 58/64] update debian packaging files Signed-off-by: R4SAS --- {debian => contrib/openrc}/i2pd.openrc | 0 {debian => contrib/upstart}/i2pd.upstart | 0 debian/compat | 2 +- debian/control | 18 ++------------- debian/copyright | 29 ------------------------ debian/docs | 4 ---- debian/i2pd.dirs | 2 -- debian/i2pd.install | 2 +- debian/postinst | 3 +-- debian/rules | 26 ++++++++------------- debian/watch | 6 ++--- 11 files changed, 18 insertions(+), 74 deletions(-) rename {debian => contrib/openrc}/i2pd.openrc (100%) rename {debian => contrib/upstart}/i2pd.upstart (100%) delete mode 100644 debian/i2pd.dirs diff --git a/debian/i2pd.openrc b/contrib/openrc/i2pd.openrc similarity index 100% rename from debian/i2pd.openrc rename to contrib/openrc/i2pd.openrc diff --git a/debian/i2pd.upstart b/contrib/upstart/i2pd.upstart similarity index 100% rename from debian/i2pd.upstart rename to contrib/upstart/i2pd.upstart diff --git a/debian/compat b/debian/compat index 9a037142..ec635144 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -10 \ No newline at end of file +9 diff --git a/debian/control b/debian/control index 843a153c..318463bc 100644 --- a/debian/control +++ b/debian/control @@ -3,30 +3,16 @@ Section: net Priority: optional Maintainer: r4sas Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.17.2~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev -Standards-Version: 3.9.6 +Standards-Version: 3.9.8 Homepage: http://i2pd.website/ Vcs-Git: git://github.com/PurpleI2P/i2pd.git Vcs-Browser: https://github.com/PurpleI2P/i2pd Package: i2pd Architecture: any -Pre-Depends: adduser +Pre-Depends: ${misc:Pre-Depends}, adduser Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base, Description: Full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants don't reveal their real IP addresses. - . - This package contains the full-featured C++ implementation of I2P router. - -Package: i2pd-dbg -Architecture: any -Priority: extra -Section: debug -Depends: i2pd (= ${binary:Version}), ${misc:Depends} -Description: i2pd debugging symbols - I2P (Invisible Internet Protocol) is a universal anonymous network layer. All - communications over I2P are anonymous and end-to-end encrypted, participants - don't reveal their real IP addresses. - . - This package contains symbols required for debugging. diff --git a/debian/copyright b/debian/copyright index 9f18f53a..73df9da0 100644 --- a/debian/copyright +++ b/debian/copyright @@ -6,13 +6,6 @@ Files: * Copyright: 2013-2020 PurpleI2P License: BSD-3-clause -Files: qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl - qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl - qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java - qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtApplication.java -Copyright: 2011-2013 BogDan Vatra -License: BSD-2-Clause - Files: debian/* Copyright: 2013-2015 Kill Your TV 2014-2016 hagen @@ -49,28 +42,6 @@ License: BSD-3-clause TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: BSD-2-Clause - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/debian/docs b/debian/docs index dfa6f572..b43bf86b 100644 --- a/debian/docs +++ b/debian/docs @@ -1,5 +1 @@ README.md -contrib/i2pd.conf -contrib/subscriptions.txt -contrib/tunnels.conf -contrib/tunnels.d diff --git a/debian/i2pd.dirs b/debian/i2pd.dirs deleted file mode 100644 index 3b643352..00000000 --- a/debian/i2pd.dirs +++ /dev/null @@ -1,2 +0,0 @@ -etc/i2pd -var/lib/i2pd diff --git a/debian/i2pd.install b/debian/i2pd.install index d20b2c17..6eb6c8c2 100644 --- a/debian/i2pd.install +++ b/debian/i2pd.install @@ -1,5 +1,5 @@ i2pd usr/sbin/ -contrib/i2pd.conf etc/i2pd/ +contrib/i2pd.conf etc/i2pd/ contrib/tunnels.conf etc/i2pd/ contrib/subscriptions.txt etc/i2pd/ contrib/certificates/ usr/share/i2pd/ diff --git a/debian/postinst b/debian/postinst index 9c9e74ae..720753fd 100755 --- a/debian/postinst +++ b/debian/postinst @@ -12,7 +12,6 @@ case "$1" in # Create user and group as a system user. if getent passwd $I2PDUSER > /dev/null 2>&1; then groupadd -f $I2PDUSER || true - usermod -s "/bin/false" -e 1 $I2PDUSER > /dev/null || true else adduser --system --quiet --group --home $I2PDHOME $I2PDUSER fi @@ -23,7 +22,7 @@ case "$1" in chmod 640 $LOGFILE chown -f ${I2PDUSER}:adm $LOGFILE mkdir -p -m0750 $I2PDHOME - chown -f -R -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME} + chown -f -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME} ;; abort-upgrade|abort-remove|abort-deconfigure) echo "Aborting upgrade" diff --git a/debian/rules b/debian/rules index 77ecd7b7..24a44f55 100755 --- a/debian/rules +++ b/debian/rules @@ -1,22 +1,16 @@ #!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow -#DPKG_EXPORT_BUILDFLAGS = 1 -#include /usr/share/dpkg/buildflags.mk -#CXXFLAGS+=$(CPPFLAGS) -#PREFIX=/usr + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + + +include /usr/share/dpkg/architecture.mk + +export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic -O3 + +export DEB_LDFLAGS_MAINT_APPEND = + %: dh $@ --parallel -# dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd - -override_dh_strip: - dh_strip --dbg-package=i2pd-dbg - -## uncomment this if you have "missing info" problem when building package -#override_dh_shlibdeps: -# dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info diff --git a/debian/watch b/debian/watch index 55cda021..64367c81 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ -version=3 -opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/i2pd-$1\.tar\.gz/ \ - https://github.com/PurpleI2P/i2pd/tags .*/v?(\d\S*)\.tar\.gz +version=4 opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%i2pd-$1.tar.gz%" \ + https://github.com/PurpleI2P/i2pd/tags \ + (?:.*?/)?(\d[\d.]*)\.tar\.gz debian uupdate From f07241bff76e949557e9ec8f5df514b8b4a594f8 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 21:14:22 +0000 Subject: [PATCH 59/64] add deb building Signed-off-by: R4SAS --- .github/workflows/build.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8828f61..b948380f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,3 +38,35 @@ jobs: cd build cmake -DWITH_UPNP=${{ matrix.with_upnp }} . make -j3 + build-deb-stretch: + name: Build package for stretch + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: change debian changelog + run: | + debchange -v `git describe --tags` -M "trunk build" + - uses: singingwolfboy/build-dpkg-stretch@v1 + id: build + with: + args: --unsigned-source --unsigned-changes + - uses: actions/upload-artifact@v1 + with: + name: ${{ steps.build.outputs.filename }} + path: ${{ steps.build.outputs.filename }} + build-deb-buster: + name: Build package for buster + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: change debian changelog + run: | + debchange -v `git describe --tags` -M "trunk build" + - uses: singingwolfboy/build-dpkg-buster@v1 + id: build + with: + args: --unsigned-source --unsigned-changes + - uses: actions/upload-artifact@v1 + with: + name: ${{ steps.build.outputs.filename }} + path: ${{ steps.build.outputs.filename }} From f9d378f1ceb7c5c39a620658b5f59f000c560803 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 21:19:05 +0000 Subject: [PATCH 60/64] [gha] add deb building Signed-off-by: R4SAS --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b948380f..42ec76b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,8 @@ jobs: - uses: actions/checkout@v2 - name: change debian changelog run: | + sudo apt-get update + sudo apt-get install devscripts debchange -v `git describe --tags` -M "trunk build" - uses: singingwolfboy/build-dpkg-stretch@v1 id: build @@ -61,6 +63,8 @@ jobs: - uses: actions/checkout@v2 - name: change debian changelog run: | + sudo apt-get update + sudo apt-get install devscripts debchange -v `git describe --tags` -M "trunk build" - uses: singingwolfboy/build-dpkg-buster@v1 id: build From 8ec478324979ca804d6bce5dc0b42a000d3477c1 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 21:34:59 +0000 Subject: [PATCH 61/64] [gha] fetch all history of git repo for packages (needs for describe) Signed-off-by: R4SAS --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 42ec76b8..5027e180 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: change debian changelog run: | sudo apt-get update @@ -61,6 +63,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: change debian changelog run: | sudo apt-get update From 064ecdb5ec1c8acfd5faa5d00c2a6775bfb706d3 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 21:40:45 +0000 Subject: [PATCH 62/64] [gha] do no check source archive for deb build Signed-off-by: R4SAS --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5027e180..3df73f90 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,7 +53,7 @@ jobs: - uses: singingwolfboy/build-dpkg-stretch@v1 id: build with: - args: --unsigned-source --unsigned-changes + args: --unsigned-source --unsigned-changes --no-tgz-check - uses: actions/upload-artifact@v1 with: name: ${{ steps.build.outputs.filename }} @@ -73,7 +73,7 @@ jobs: - uses: singingwolfboy/build-dpkg-buster@v1 id: build with: - args: --unsigned-source --unsigned-changes + args: --unsigned-source --unsigned-changes --no-tgz-check - uses: actions/upload-artifact@v1 with: name: ${{ steps.build.outputs.filename }} From 71df1fc4d6b20f3a74f5d524a95727d459bf239b Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 21:45:14 +0000 Subject: [PATCH 63/64] [gha] do not check source archive for deb build Signed-off-by: R4SAS --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3df73f90..fb820daa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,7 +53,7 @@ jobs: - uses: singingwolfboy/build-dpkg-stretch@v1 id: build with: - args: --unsigned-source --unsigned-changes --no-tgz-check + args: --unsigned-source --unsigned-changes -b - uses: actions/upload-artifact@v1 with: name: ${{ steps.build.outputs.filename }} @@ -73,7 +73,7 @@ jobs: - uses: singingwolfboy/build-dpkg-buster@v1 id: build with: - args: --unsigned-source --unsigned-changes --no-tgz-check + args: --unsigned-source --unsigned-changes -b - uses: actions/upload-artifact@v1 with: name: ${{ steps.build.outputs.filename }} From 2c7fff077b0544cd98c69657921f3db0262dd15c Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 16 Jun 2021 22:06:48 +0000 Subject: [PATCH 64/64] [gha] add dist name in package changelog Signed-off-by: R4SAS --- .github/workflows/build.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb820daa..22ba60bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: run: | sudo apt-get update sudo apt-get install devscripts - debchange -v `git describe --tags` -M "trunk build" + debchange -v "`git describe --tags`-stretch" -M --distribution stretch "trunk build" - uses: singingwolfboy/build-dpkg-stretch@v1 id: build with: @@ -58,6 +58,10 @@ jobs: with: name: ${{ steps.build.outputs.filename }} path: ${{ steps.build.outputs.filename }} + - uses: actions/upload-artifact@v1 + with: + name: ${{ steps.build.outputs.filename-dbgsym }} + path: ${{ steps.build.outputs.filename-dbgsym }} build-deb-buster: name: Build package for buster runs-on: ubuntu-latest @@ -69,7 +73,7 @@ jobs: run: | sudo apt-get update sudo apt-get install devscripts - debchange -v `git describe --tags` -M "trunk build" + debchange -v "`git describe --tags`-buster" -M --distribution buster "trunk build" - uses: singingwolfboy/build-dpkg-buster@v1 id: build with: @@ -78,3 +82,7 @@ jobs: with: name: ${{ steps.build.outputs.filename }} path: ${{ steps.build.outputs.filename }} + - uses: actions/upload-artifact@v1 + with: + name: ${{ steps.build.outputs.filename-dbgsym }} + path: ${{ steps.build.outputs.filename-dbgsym }}