Browse Source

[uacomment] Sanitize per BIP-0014

* SanitizeString() can be requested to be more strict
* Throw error when SanitizeString() changes uacomments
* Fix tests
0.13
MarcoFalke 9 years ago
parent
commit
1c1b1b315f
  1. 11
      src/init.cpp
  2. 4
      src/test/util_tests.cpp
  3. 17
      src/utilstrencodings.cpp
  4. 16
      src/utilstrencodings.h

11
src/init.cpp

@ -1014,8 +1014,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterNodeSignals(GetNodeSignals()); RegisterNodeSignals(GetNodeSignals());
// format user agent, check total size // sanitize comments per BIP-0014, format user agent and check total size
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, mapMultiArgs.count("-uacomment") ? mapMultiArgs["-uacomment"] : std::vector<string>()); std::vector<string> uacomments;
BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"])
{
if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
return InitError(strprintf("User Agent comment (%s) contains unsafe characters.", cmt));
uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT));
}
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.", return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.",
strSubVersion.size(), MAX_SUBVERSION_LENGTH)); strSubVersion.size(), MAX_SUBVERSION_LENGTH));

4
src/test/util_tests.cpp

@ -413,10 +413,10 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
comments.push_back(std::string("comment1")); comments.push_back(std::string("comment1"));
std::vector<std::string> comments2; std::vector<std::string> comments2;
comments2.push_back(std::string("comment1")); comments2.push_back(std::string("comment1"));
comments2.push_back(std::string("comment2")); comments2.push_back(SanitizeString(std::string("Comment2; .,_?@; !\"#$%&'()*+-/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/")); BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/"));
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/")); BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/"));
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/")); BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; Comment2; .,_?@; )/"));
} }
BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)

17
src/utilstrencodings.cpp

@ -14,17 +14,20 @@
using namespace std; using namespace std;
string SanitizeString(const string& str) static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const string SAFE_CHARS[] =
{
CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT
CHARS_ALPHA_NUM + " .,;_?@" // SAFE_CHARS_UA_COMMENT
};
string SanitizeString(const string& str, int rule)
{ {
/**
* safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
* even possibly remotely dangerous like & or >
*/
static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@()");
string strResult; string strResult;
for (std::string::size_type i = 0; i < str.size(); i++) for (std::string::size_type i = 0; i < str.size(); i++)
{ {
if (safeChars.find(str[i]) != std::string::npos) if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
strResult.push_back(str[i]); strResult.push_back(str[i]);
} }
return strResult; return strResult;

16
src/utilstrencodings.h

@ -22,7 +22,21 @@
/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */ /** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */
#define PAIRTYPE(t1, t2) std::pair<t1, t2> #define PAIRTYPE(t1, t2) std::pair<t1, t2>
std::string SanitizeString(const std::string& str); /** Used by SanitizeString() */
enum SafeChars
{
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset
};
/**
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
* addresses, but avoid anything even possibly remotely dangerous like & or >
* @param[in] str The string to sanitize
* @param[in] rule The set of safe chars to choose (default: least restrictive)
* @return A new string without unsafe chars
*/
std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);
std::vector<unsigned char> ParseHex(const char* psz); std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str); std::vector<unsigned char> ParseHex(const std::string& str);
signed char HexDigit(char c); signed char HexDigit(char c);

Loading…
Cancel
Save