diff --git a/cli/cli.cc b/cli/cli.cc index b38852f10..08cbec082 100644 --- a/cli/cli.cc +++ b/cli/cli.cc @@ -49,6 +49,8 @@ sig_atomic_t manualUpdate = false; char const* torrentPath = nullptr; using Arg = tr_option::Arg; +static_assert(TrDefaultPeerPort == 51413, "update 'port' desc"); +static_assert(TrDefaultPeerSocketTos == "le", "update 'tos' desc"); auto constexpr Options = std::array{ { { 'b', "blocklist", "Enable peer blocklists", "b", Arg::None, nullptr }, { 'B', "no-blocklist", "Disable peer blocklists", "B", Arg::None, nullptr }, @@ -61,11 +63,10 @@ auto constexpr Options = std::array{ { { 'g', "config-dir", "Where to find configuration files", "g", Arg::Required, "" }, { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", Arg::None, nullptr }, { 'M', "no-portmap", "Disable portmapping", "M", Arg::None, nullptr }, - { 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", Arg::Required, "" }, + { 'p', "port", "Port for incoming peers (Default: 51413)", "p", Arg::Required, "" }, { 't', "tos", - "Peer socket DSCP / ToS setting (number, or a DSCP string, e.g. 'af11' or 'cs0', default=" TR_DEFAULT_PEER_SOCKET_TOS_STR - ")", + "Peer socket DSCP / ToS. Number or DSCP string, e.g. 'af11' or 'cs0' (Default: 'le')", "t", Arg::Required, "" }, diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 28977f0b9..de370327a 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -80,8 +80,13 @@ char constexpr Usage[] = "Transmission " LONG_VERSION_STRING "Usage: transmission-daemon [options]"; using Arg = tr_option::Arg; +static_assert(TrDefaultRpcWhitelist == "127.0.0.1,::1", "update 'allowed' desc"); +static_assert(TrDefaultPeerPort == 51413, "update 'peerport' desc"); +static_assert(TrDefaultPeerLimitTorrent == 50, "update 'peerlimit-torrent' desc"); +static_assert(TrDefaultPeerLimitGlobal == 200, "update 'peerlimit-global' desc"); +static_assert(TrDefaultRpcPort == 9091 && R"(update "port" desc)"); auto constexpr Options = std::array{ { - { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", Arg::Required, "" }, + { 'a', "allowed", "Allowed IP addresses. (Default: '127.0.0.1,::1')", "a", Arg::Required, "" }, { 'b', "blocklist", "Enable peer blocklists", "b", Arg::None, nullptr }, { 'B', "no-blocklist", "Disable peer blocklists", "B", Arg::None, nullptr }, { 'c', "watch-dir", "Where to watch for new torrent files", "c", Arg::Required, "" }, @@ -93,7 +98,7 @@ auto constexpr Options = std::array{ { { 'e', "logfile", "Dump the log messages to this filename", "e", Arg::Required, "" }, { 'f', "foreground", "Run in the foreground instead of daemonizing", "f", Arg::None, nullptr }, { 'g', "config-dir", "Where to look for configuration files", "g", Arg::Required, "" }, - { 'p', "port", "RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p", Arg::Required, "" }, + { 'p', "port", "RPC port (Default: 9091)", "p", Arg::Required, "" }, { 't', "auth", "Require authentication", "t", Arg::None, nullptr }, { 'T', "no-auth", "Don't require authentication", "T", Arg::None, nullptr }, { 'u', "username", "Set username for authentication", "u", Arg::Required, "" }, @@ -122,21 +127,11 @@ auto constexpr Options = std::array{ { "" }, { 831, "utp", "*DEPRECATED* Enable µTP for peer connections", nullptr, Arg::None, nullptr }, { 832, "no-utp", "*DEPRECATED* Disable µTP for peer connections", nullptr, Arg::None, nullptr }, - { 'P', "peerport", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "P", Arg::Required, "" }, + { 'P', "peerport", "Port for incoming peers (Default: 51413)", "P", Arg::Required, "" }, { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", Arg::None, nullptr }, { 'M', "no-portmap", "Disable portmapping", "M", Arg::None, nullptr }, - { 'L', - "peerlimit-global", - "Maximum overall number of peers (Default: " TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ")", - "L", - Arg::Required, - "" }, - { 'l', - "peerlimit-torrent", - "Maximum number of peers per torrent (Default: " TR_DEFAULT_PEER_LIMIT_TORRENT_STR ")", - "l", - Arg::Required, - "" }, + { 'L', "peerlimit-global", "Maximum overall number of peers (Default: 200)", "L", Arg::Required, "" }, + { 'l', "peerlimit-torrent", "Maximum number of peers per torrent (Default: 50)", "l", Arg::Required, "" }, { 910, "encryption-required", "Encrypt all peer connections", "er", Arg::None, nullptr }, { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", Arg::None, nullptr }, { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", Arg::None, nullptr }, diff --git a/libtransmission/blocklist.cc b/libtransmission/blocklist.cc index 27840b1c4..13c4beb8e 100644 --- a/libtransmission/blocklist.cc +++ b/libtransmission/blocklist.cc @@ -565,7 +565,7 @@ size_t Blocklists::update_primary_blocklist(std::string_view external_file, bool { // These rules will replace the default blocklist. // Build the path of the default blocklist .bin file where we'll save these rules. - auto const bin_file = tr_pathbuf{ folder_, '/', DEFAULT_BLOCKLIST_FILENAME }; + auto const bin_file = tr_pathbuf{ folder_, '/', TrDefaultBlocklistFilename }; // Try to save it auto added = Blocklist::saveNew(external_file, bin_file, is_enabled); diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index 273723b38..e27491524 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -477,7 +477,7 @@ bool isHostnameAllowed(tr_rpc_server const* server, evhttp_request* const req) bool test_session_id(tr_rpc_server const* server, evhttp_request* const req) { auto const* const input_headers = evhttp_request_get_input_headers(req); - char const* const session_id = evhttp_find_header(input_headers, TR_RPC_SESSION_ID_HEADER); + char const* const session_id = evhttp_find_header(input_headers, std::data(TrRpcSessionIdHeader)); return session_id != nullptr && server->session->sessionId() == session_id; } @@ -624,26 +624,26 @@ void handle_request(struct evhttp_request* req, void* arg) else if (!test_session_id(server, req)) { auto const session_id = std::string{ server->session->sessionId() }; + evhttp_add_header(output_headers, std::data(TrRpcSessionIdHeader), session_id.c_str()); + + evhttp_add_header(output_headers, std::data(TrRpcVersionHeader), std::data(TrRpcVersionSemver)); + + auto const expose_val = fmt::format("{:s}, {:s}", TrRpcSessionIdHeader, TrRpcVersionHeader); + evhttp_add_header(output_headers, "Access-Control-Expose-Headers", expose_val.c_str()); + auto const body = fmt::format( "

Your request had an invalid session_id header.

" "

To fix this, follow these steps:" - "

  1. When reading a response, get its " TR_RPC_SESSION_ID_HEADER - " header and remember it" + "
    1. When reading a response, get its {0:s} header and remember it" "
    2. Add the updated header to your outgoing requests" "
    3. When you get this 409 error message, resend your request with the updated header" "

    " "

    This requirement has been added to help prevent " "CSRF " "attacks.

    " - "

    {:s}: {:s}

    ", - TR_RPC_SESSION_ID_HEADER, + "

    {0:s}: {1:s}

    ", + TrRpcSessionIdHeader, session_id); - evhttp_add_header(output_headers, TR_RPC_SESSION_ID_HEADER, session_id.c_str()); - evhttp_add_header(output_headers, TR_RPC_RPC_VERSION_HEADER, std::data(TrRpcVersionSemver)); - evhttp_add_header( - output_headers, - "Access-Control-Expose-Headers", - TR_RPC_SESSION_ID_HEADER ", " TR_RPC_RPC_VERSION_HEADER); send_simple_response(req, 409, body.c_str()); } #endif diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index 88df76444..121c75a10 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -67,9 +67,9 @@ public: std::string bind_address_str = "0.0.0.0"; std::string host_whitelist_str; std::string salted_password; - std::string url = std::string{ TrHttpServerDefaultBasePath }; + std::string url = std::string{ TrDefaultHttpServerBasePath }; std::string username; - std::string whitelist_str = TR_DEFAULT_RPC_WHITELIST; + std::string whitelist_str = std::string{ TrDefaultRpcWhitelist }; tr_mode_t socket_mode = 0750; tr_port port = tr_port::from_host(TrDefaultRpcPort); diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 10d03a94d..6fda5aca6 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -31,6 +31,20 @@ using tr_tracker_id_t = uint32_t; using tr_torrent_id_t = int; using tr_mode_t = uint16_t; +inline auto constexpr TrDefaultBlocklistFilename = std::string_view{ "blocklist.bin" }; +inline auto constexpr TrDefaultHttpServerBasePath = std::string_view{ "/transmission/" }; +inline auto constexpr TrDefaultPeerLimitGlobal = 200U; +inline auto constexpr TrDefaultPeerLimitTorrent = 50U; +inline auto constexpr TrDefaultPeerPort = 51413U; +inline auto constexpr TrDefaultPeerSocketTos = std::string_view{ "le" }; +inline auto constexpr TrDefaultRpcPort = 9091U; +inline auto constexpr TrDefaultRpcWhitelist = std::string_view{ "127.0.0.1,::1" }; + +inline auto constexpr TrHttpServerRpcRelativePath = std::string_view{ "rpc" }; +inline auto constexpr TrHttpServerWebRelativePath = std::string_view{ "web/" }; +inline auto constexpr TrRpcSessionIdHeader = std::string_view{ "X-Transmission-Session-Id" }; +inline auto constexpr TrRpcVersionHeader = std::string_view{ "X-Transmission-Rpc-Version" }; + struct tr_block_span_t { tr_block_index_t begin; @@ -50,9 +64,6 @@ struct tr_torrent; struct tr_torrent_metainfo; struct tr_variant; -#define TR_RPC_SESSION_ID_HEADER "X-Transmission-Session-Id" -#define TR_RPC_RPC_VERSION_HEADER "X-Transmission-Rpc-Version" - enum tr_verify_added_mode : uint8_t { // See discussion @ https://github.com/transmission/transmission/pull/2626 @@ -124,21 +135,6 @@ size_t tr_getDefaultConfigDirToBuf(char const* appname, char* buf, size_t buflen /** @brief buffer variant of `tr_getDefaultDownloadDir()`. See `tr_strv_to_buf()`. */ size_t tr_getDefaultDownloadDirToBuf(char* buf, size_t buflen); -#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1,::1" -#define TR_DEFAULT_RPC_PORT_STR "9091" -inline auto constexpr TrDefaultRpcPort = 9091U; -#define TR_DEFAULT_PEER_PORT_STR "51413" -inline auto constexpr TrDefaultPeerPort = 51413U; -#define TR_DEFAULT_PEER_SOCKET_TOS_STR "le" -#define TR_DEFAULT_PEER_LIMIT_GLOBAL_STR "200" -inline auto constexpr TrDefaultPeerLimitGlobal = 200U; -#define TR_DEFAULT_PEER_LIMIT_TORRENT_STR "50" -inline auto constexpr TrDefaultPeerLimitTorrent = 50U; - -inline auto constexpr TrHttpServerDefaultBasePath = std::string_view{ "/transmission/" }; -inline auto constexpr TrHttpServerRpcRelativePath = std::string_view{ "rpc" }; -inline auto constexpr TrHttpServerWebRelativePath = std::string_view{ "web/" }; - /** * Add libtransmission's default settings to the benc dictionary. * @@ -717,10 +713,6 @@ char const* tr_blocklistGetURL(tr_session const* session); invokes the "blocklist_update" method */ void tr_blocklistSetURL(tr_session* session, char const* url); -/** @brief the file in the $config/blocklists/ directory that's - used by `tr_blocklistSetContent()` and "blocklist_update" */ -#define DEFAULT_BLOCKLIST_FILENAME "blocklist.bin" - /** @} */ /** diff --git a/macosx/PrefsController.mm b/macosx/PrefsController.mm index 0858797f3..bf2910c0c 100644 --- a/macosx/PrefsController.mm +++ b/macosx/PrefsController.mm @@ -138,9 +138,11 @@ static NSString* const kWebUIURLFormat = @"http://localhost:%ld/"; NSURL* blocklistDir = [[NSFileManager.defaultManager URLsForDirectory:NSApplicationDirectory inDomains:NSUserDomainMask][0] URLByAppendingPathComponent:@"Transmission/blocklists/"]; - [NSFileManager.defaultManager moveItemAtURL:[blocklistDir URLByAppendingPathComponent:@"level1.bin"] - toURL:[blocklistDir URLByAppendingPathComponent:@DEFAULT_BLOCKLIST_FILENAME] - error:nil]; + [NSFileManager.defaultManager + moveItemAtURL:[blocklistDir URLByAppendingPathComponent:@"level1.bin"] + toURL:[blocklistDir + URLByAppendingPathComponent:[NSString stringWithUTF8String:TrDefaultBlocklistFilename.data()]] + error:nil]; } //save a new random port diff --git a/qt/Prefs.cc b/qt/Prefs.cc index c6ede9744..65530004f 100644 --- a/qt/Prefs.cc +++ b/qt/Prefs.cc @@ -238,7 +238,7 @@ tr_variant::Map Prefs::defaults() map.try_emplace(TR_KEY_remote_session_password, tr_variant::unmanaged_string(""sv)); map.try_emplace(TR_KEY_remote_session_port, TrDefaultRpcPort); map.try_emplace(TR_KEY_remote_session_requires_authentication, false); - map.try_emplace(TR_KEY_remote_session_url_base_path, tr_variant::unmanaged_string(TrHttpServerDefaultBasePath)); + map.try_emplace(TR_KEY_remote_session_url_base_path, tr_variant::unmanaged_string(TrDefaultHttpServerBasePath)); map.try_emplace(TR_KEY_remote_session_username, tr_variant::unmanaged_string(""sv)); map.try_emplace(TR_KEY_show_backup_trackers, false); map.try_emplace(TR_KEY_show_filterbar, true); diff --git a/qt/RpcClient.cc b/qt/RpcClient.cc index a536b653b..5fdd8cd4f 100644 --- a/qt/RpcClient.cc +++ b/qt/RpcClient.cc @@ -121,7 +121,7 @@ void RpcClient::sendNetworkRequest(QByteArray const& body, QFutureInterfaceattribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409 && - reply->hasRawHeader(TR_RPC_SESSION_ID_HEADER)) + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409 && reply->hasRawHeader(SessionIdHeaderName)) { // we got a 409 telling us our session id has expired. // update it and resubmit the request. auto version_str = QString::fromUtf8("unknown"); - if (reply->hasRawHeader(TR_RPC_RPC_VERSION_HEADER)) + if (reply->hasRawHeader(VersionHeaderName)) { network_style_ = api_compat::Style::Tr5; - version_str = QString::fromUtf8(reply->rawHeader(TR_RPC_RPC_VERSION_HEADER)); + version_str = QString::fromUtf8(reply->rawHeader(VersionHeaderName)); if (QVersionNumber::fromString(version_str).majorVersion() > TrRpcVersionSemverMajor) { fmt::print( @@ -243,7 +242,7 @@ void RpcClient::networkRequestFinished(QNetworkReply* reply) static_cast(network_style_)); } - session_id_ = reply->rawHeader(TR_RPC_SESSION_ID_HEADER); + session_id_ = reply->rawHeader(SessionIdHeaderName); sendNetworkRequest(reply->property(RequestBodyKey).toByteArray(), promise); return; } diff --git a/qt/RpcClient.h b/qt/RpcClient.h index 3eeb13595..8c3999f52 100644 --- a/qt/RpcClient.h +++ b/qt/RpcClient.h @@ -86,6 +86,9 @@ private slots: void localRequestFinished(TrVariantPtr response); private: + QByteArray const SessionIdHeaderName = std::data(TrRpcSessionIdHeader); + QByteArray const VersionHeaderName = std::data(TrRpcVersionHeader); + QNetworkAccessManager* networkAccessManager(); void sendNetworkRequest(QByteArray const& body, QFutureInterface const& promise); diff --git a/utils/remote.cc b/utils/remote.cc index 06dd70b67..ea7b336bd 100644 --- a/utils/remote.cc +++ b/utils/remote.cc @@ -213,6 +213,7 @@ enum // --- Command-Line Arguments using Arg = tr_option::Arg; +static_assert(TrDefaultPeerPort == 51413, "update 'port' desc"); auto constexpr Options = std::array{ { { 'a', "add", "Add torrent files by filename or URL", "a", Arg::None, nullptr }, { 970, "alt-speed", "Use the alternate Limits", "as", Arg::None, nullptr }, @@ -271,7 +272,7 @@ auto constexpr Options = std::array{ { { 820, "ssl", "Use SSL when talking to daemon", nullptr, Arg::None, nullptr }, { 'o', "dht", "Enable distributed hash tables (DHT)", "o", Arg::None, nullptr }, { 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", Arg::None, nullptr }, - { 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", Arg::Required, "" }, + { 'p', "port", "Port for incoming peers (Default: 51413)", "p", Arg::Required, "" }, { 962, "port-test", "Port testing", "pt", Arg::None, nullptr }, { 'P', "random-port", "Random port for incoming peers", "P", Arg::None, nullptr }, { 900, "priority-high", "Try to download these file(s) first", "ph", Arg::Required, "" }, @@ -875,8 +876,8 @@ void warn_if_unsupported_rpc_version(std::string_view const semver) [[nodiscard]] size_t parse_response_header(void* ptr, size_t size, size_t nmemb, void* vconfig) { using namespace header_utils; - static auto const session_id_header = tr_strlower(TR_RPC_SESSION_ID_HEADER); - static auto const rpc_version_header = tr_strlower(TR_RPC_RPC_VERSION_HEADER); + static auto const session_id_header = tr_strlower(TrRpcSessionIdHeader); + static auto const rpc_version_header = tr_strlower(TrRpcVersionHeader); auto& config = *static_cast(vconfig); @@ -2403,7 +2404,7 @@ CURL* tr_curl_easy_init(std::string* writebuf, RemoteConfig& config) if (auto const& str = config.session_id; !std::empty(str)) { - auto const h = fmt::format("{:s}: {:s}", TR_RPC_SESSION_ID_HEADER, str); + auto const h = fmt::format("{:s}: {:s}", TrRpcSessionIdHeader, str); auto* const custom_headers = curl_slist_append(nullptr, h.c_str()); (void)curl_easy_setopt(curl, CURLOPT_HTTPHEADER, custom_headers); @@ -3578,7 +3579,7 @@ int tr_main(int argc, char* argv[]) if (std::empty(rpcurl)) { - rpcurl = fmt::format("{:s}:{:d}{:s}{:s}", host, port, TrHttpServerDefaultBasePath, TrHttpServerRpcRelativePath); + rpcurl = fmt::format("{:s}:{:d}{:s}{:s}", host, port, TrDefaultHttpServerBasePath, TrHttpServerRpcRelativePath); } return process_args(rpcurl.c_str(), argc, (char const* const*)argv, config);