1
0
mirror of https://github.com/anope/anope.git synced 2026-07-07 11:43:12 +02:00

Also allow hashed RPC tokens in the config file.

This commit is contained in:
Sadie Powell
2025-05-04 14:39:20 +01:00
parent 4b854d3935
commit 72f5e3580f
4 changed files with 70 additions and 23 deletions
+19 -1
View File
@@ -672,7 +672,7 @@ module
/*
* If your database uses a password hashing algorithm that can not be compared using a simple
* comparison method then you can specify it here to compare locally.
* comparison function then you can specify it here to compare locally.
*
* You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order
* for this to work.
@@ -820,6 +820,15 @@ module
/* The token used for authentication. */
token = "BmcxTaiYjoBtayfnxCFq"
/*
* The algorithm which the above token is hashed with. If this is not
* set then services will assume the above password is not hashed.
*
* You will need to have the appropriate encryption module (e.g.
* enc_bcrypt) loaded in order for this to work.
*/
#token_hash = "bcrypt"
/** A list of glob patterns for methods the token can execute. */
methods = "~anope.message* anope.*"
}
@@ -867,6 +876,15 @@ module
/* The token used for authentication. */
token = "BmcxTaiYjoBtayfnxCFq"
/*
* The algorithm which the above token is hashed with. If this is not
* set then services will assume the above password is not hashed.
*
* You will need to have the appropriate encryption module (e.g.
* enc_bcrypt) loaded in order for this to work.
*/
#token_hash = "bcrypt"
/** A list of glob patterns for methods the token can execute. */
methods = "~anope.message* anope.*"
}
+37 -12
View File
@@ -8,6 +8,7 @@
#pragma once
#include "encryption.h"
#include "httpd.h"
#include <variant>
@@ -19,6 +20,7 @@ namespace RPC
class Map;
class Request;
class ServiceInterface;
struct Token;
class Value;
/** Represents possible types of RPC value. */
@@ -189,11 +191,32 @@ public:
virtual bool Run(ServiceInterface *iface, HTTPClient *client, Request &request) = 0;
};
struct RPC::Token final
{
std::vector<Anope::string> methods;
Anope::string token;
Anope::string token_hash;
};
class RPC::ServiceInterface
: public Service
{
private:
bool CompareToken(const RPC::Token &token, const Anope::string &rawtoken) const
{
if (token.token_hash.empty())
return token.token.equals_cs(rawtoken); // Plaintext token.
auto *service = Service::FindService("Encryption::Provider", token.token_hash);
if (!service)
return false; // Malformed hash.
auto *hashprov = static_cast<Encryption::Provider *>(service);
return hashprov->Compare(token.token, rawtoken);
}
public:
Anope::map<std::vector<Anope::string>> tokens;
std::vector<Token> tokens;
ServiceInterface(Module *creator)
: Service(creator, "RPC::ServiceInterface", "rpc")
@@ -205,20 +228,22 @@ public:
if (header.compare(0, 7, "Bearer ", 7) != 0)
return false; // No token provided.
Anope::string token;
Anope::B64Decode(header.substr(7), token);
Anope::string rawtoken;
Anope::B64Decode(header.substr(7), rawtoken);
auto it = tokens.find(token);
if (it == tokens.end())
return false; // No valid token.
for (const auto &glob : it->second)
for (const auto &token : tokens)
{
if (glob[0] == '~' && Anope::Match(method, glob.substr(1)))
return false; // Negative match.
if (!CompareToken(token, rawtoken))
continue; // No valid token.
if (Anope::Match(method, glob))
return true; // Positive match.
for (const auto &glob : token.methods)
{
if (glob[0] == '~' && Anope::Match(method, glob.substr(1)))
return false; // Negative match.
if (Anope::Match(method, glob))
return true; // Positive match.
}
}
return false; // No match.
}
+7 -5
View File
@@ -324,12 +324,14 @@ public:
for (int i = 0; i < modconf.CountBlock("token"); ++i)
{
const auto &block = modconf.GetBlock("token", i);
const auto &token = block.Get<const Anope::string>("token");
if (!token.empty())
RPC::Token token;
token.token = block.Get<const Anope::string>("token");
if (!token.token.empty())
{
std::vector<Anope::string> methods;
spacesepstream(block.Get<const Anope::string>("methods")).GetTokens(methods);
xmlrpcinterface.tokens.emplace(token, methods);
token.token_hash = block.Get<const Anope::string>("token_hash");
spacesepstream(block.Get<const Anope::string>("methods")).GetTokens(token.methods);
xmlrpcinterface.tokens.emplace_back(token);
}
}
+7 -5
View File
@@ -281,12 +281,14 @@ public:
for (int i = 0; i < modconf.CountBlock("token"); ++i)
{
const auto &block = modconf.GetBlock("token", i);
const auto &token = block.Get<const Anope::string>("token");
if (!token.empty())
RPC::Token token;
token.token = block.Get<const Anope::string>("token");
if (!token.token.empty())
{
std::vector<Anope::string> methods;
spacesepstream(block.Get<const Anope::string>("methods")).GetTokens(methods);
jsonrpcinterface.tokens.emplace(token, methods);
token.token_hash = block.Get<const Anope::string>("token_hash");
spacesepstream(block.Get<const Anope::string>("methods")).GetTokens(token.methods);
jsonrpcinterface.tokens.emplace_back(token);
}
}