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:
@@ -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
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user