mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 08:00:38 +03:00
Error handling and authentication for I2PControl.
This commit is contained in:
parent
996c36b93d
commit
9cca01d159
@ -17,8 +17,8 @@
|
||||
namespace i2p {
|
||||
namespace client {
|
||||
|
||||
I2PControlSession::Response::Response(const std::string& id, const std::string& version)
|
||||
: id(id), version(version), parameters()
|
||||
I2PControlSession::Response::Response(const std::string& version)
|
||||
: id(), version(version), error(ErrorCode::None), parameters()
|
||||
{
|
||||
|
||||
}
|
||||
@ -32,10 +32,42 @@ std::string I2PControlSession::Response::toJsonString() const
|
||||
oss << ',';
|
||||
oss << '"' << it->first << "\":" << it->second;
|
||||
}
|
||||
oss << "},\"jsonrpc\":\"" << version << "\"}";
|
||||
oss << "},\"jsonrpc\":\"" << version << '"';
|
||||
if(error != ErrorCode::None)
|
||||
oss << ",\"error\":{\"code\":" << static_cast<int>(error)
|
||||
<< ",\"message\":\"" << getErrorMsg() << "\"" << "}";
|
||||
oss << "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string I2PControlSession::Response::getErrorMsg() const
|
||||
{
|
||||
switch(error) {
|
||||
case ErrorCode::MethodNotFound:
|
||||
return "Method not found.";
|
||||
case ErrorCode::InvalidParameters:
|
||||
return "Invalid parameters.";
|
||||
case ErrorCode::InvalidRequest:
|
||||
return "Invalid request.";
|
||||
case ErrorCode::ParseError:
|
||||
return "Json parse error.";
|
||||
case ErrorCode::InvalidPassword:
|
||||
return "Invalid password.";
|
||||
case ErrorCode::NoToken:
|
||||
return "No authentication token given.";
|
||||
case ErrorCode::NonexistantToken:
|
||||
return "Nonexistant authentication token given.";
|
||||
case ErrorCode::ExpiredToken:
|
||||
return "Exipred authentication token given.";
|
||||
case ErrorCode::UnspecifiedVersion:
|
||||
return "Version not specified.";
|
||||
case ErrorCode::UnsupportedVersion:
|
||||
return "Version not supported.";
|
||||
default:
|
||||
return "";
|
||||
};
|
||||
}
|
||||
|
||||
void I2PControlSession::Response::setParam(const std::string& param, const std::string& value)
|
||||
{
|
||||
parameters[param] = value.empty() ? "null" : "\"" + value + "\"";
|
||||
@ -53,8 +85,18 @@ void I2PControlSession::Response::setParam(const std::string& param, double valu
|
||||
parameters[param] = oss.str();
|
||||
}
|
||||
|
||||
void I2PControlSession::Response::setError(ErrorCode code)
|
||||
{
|
||||
error = code;
|
||||
}
|
||||
|
||||
void I2PControlSession::Response::setId(const std::string& identifier)
|
||||
{
|
||||
id = identifier;
|
||||
}
|
||||
|
||||
I2PControlSession::I2PControlSession(boost::asio::io_service& ios)
|
||||
: password(I2P_CONTROL_DEFAULT_PASSWORD), service(ios), shutdownTimer(ios)
|
||||
: password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), service(ios), shutdownTimer(ios)
|
||||
{
|
||||
// Method handlers
|
||||
methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate;
|
||||
@ -85,22 +127,54 @@ I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream&
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json(request, pt);
|
||||
|
||||
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
|
||||
auto it = methodHandlers.find(method);
|
||||
if(it == methodHandlers.end()) { // Not found
|
||||
LogPrint(eLogWarning, "Unknown I2PControl method ", method);
|
||||
return Response("error"); // TODO: indicate the error through i2pcontrol
|
||||
Response response;
|
||||
try {
|
||||
response.setId(pt.get<std::string>(I2P_CONTROL_PROPERTY_ID));
|
||||
|
||||
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
|
||||
auto it = methodHandlers.find(method);
|
||||
if(it == methodHandlers.end()) { // Not found
|
||||
LogPrint(eLogWarning, "Unknown I2PControl method ", method);
|
||||
response.setError(ErrorCode::MethodNotFound);
|
||||
return response;
|
||||
}
|
||||
|
||||
PropertyTree params = pt.get_child(I2P_CONTROL_PROPERTY_PARAMS);
|
||||
if(method != I2P_CONTROL_METHOD_AUTHENTICATE && !authenticate(params, response)) {
|
||||
LogPrint(eLogWarning, "I2PControl invalid token presented");
|
||||
return response;
|
||||
}
|
||||
// Call the appropriate handler
|
||||
(this->*(it->second))(params, response);
|
||||
|
||||
} catch(const boost::property_tree::ptree_error& error) {
|
||||
response.setError(ErrorCode::ParseError);
|
||||
} catch(...) {
|
||||
response.setError(ErrorCode::InternalError);
|
||||
}
|
||||
|
||||
Response response(pt.get<std::string>(I2P_CONTROL_PROPERTY_ID));
|
||||
// Call the appropriate handler
|
||||
(this->*(it->second))(pt.get_child(I2P_CONTROL_PROPERTY_PARAMS), response);
|
||||
return response;
|
||||
}
|
||||
|
||||
bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response)
|
||||
{
|
||||
try {
|
||||
std::string token = pt.get<std::string>(I2P_CONTROL_PARAM_TOKEN);
|
||||
if(tokens.find(token) == tokens.end()) {
|
||||
response.setError(ErrorCode::NonexistantToken);
|
||||
return false;
|
||||
}
|
||||
} catch(const boost::property_tree::ptree_error& error) {
|
||||
response.setError(ErrorCode::NoToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response)
|
||||
{
|
||||
int api = pt.get<int>(I2P_CONTROL_PARAM_API);
|
||||
const int api = pt.get<int>(I2P_CONTROL_PARAM_API);
|
||||
const std::string given_pass = pt.get<std::string>(I2P_CONTROL_PARAM_PASSWORD);
|
||||
LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", password);
|
||||
if(given_pass != password) {
|
||||
@ -108,12 +182,14 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res
|
||||
eLogError, "I2PControl Authenticate Invalid password ", password,
|
||||
" expected ", password
|
||||
);
|
||||
response.setError(ErrorCode::InvalidPassword);
|
||||
return;
|
||||
}
|
||||
// TODO: generate a secure token
|
||||
const std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch());
|
||||
response.setParam(I2P_CONTROL_PARAM_API, api);
|
||||
response.setParam(I2P_CONTROL_PARAM_TOKEN, token);
|
||||
// TODO: store tokens to do something useful with them
|
||||
tokens.insert(token);
|
||||
}
|
||||
|
||||
void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response)
|
||||
@ -134,13 +210,16 @@ void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& respo
|
||||
{
|
||||
LogPrint(eLogDebug, "I2PControl RouterInfo");
|
||||
for(const auto& pair : pt) {
|
||||
if(pair.first == I2P_CONTROL_PARAM_TOKEN)
|
||||
continue;
|
||||
LogPrint(eLogDebug, pair.first);
|
||||
auto it = routerInfoHandlers.find(pair.first);
|
||||
LogPrint(eLogDebug, "Still going");
|
||||
if(it != routerInfoHandlers.end())
|
||||
if(it != routerInfoHandlers.end()) {
|
||||
(this->*(it->second))(response);
|
||||
else
|
||||
} else {
|
||||
LogPrint(eLogError, "I2PControl RouterInfo unknown request ", pair.first);
|
||||
response.setError(ErrorCode::InvalidRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,12 +227,16 @@ void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& re
|
||||
{
|
||||
LogPrint(eLogDebug, "I2PControl RouterManager");
|
||||
for(const auto& pair : pt) {
|
||||
if(pair.first == I2P_CONTROL_PARAM_TOKEN)
|
||||
continue;
|
||||
LogPrint(eLogDebug, pair.first);
|
||||
auto it = routerManagerHandlers.find(pair.first);
|
||||
if(it != routerManagerHandlers.end())
|
||||
if(it != routerManagerHandlers.end()) {
|
||||
(this->*(it->second))(response);
|
||||
else
|
||||
} else {
|
||||
LogPrint(eLogError, "I2PControl RouterManager unknown request ", pair.first);
|
||||
response.setError(ErrorCode::InvalidRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
@ -55,16 +56,36 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
|
||||
|
||||
/**
|
||||
* "Null" I2P control implementation, does not do actual networking.
|
||||
* @note authentication tokens are per-session
|
||||
*/
|
||||
class I2PControlSession {
|
||||
|
||||
public:
|
||||
enum class ErrorCode {
|
||||
None = 0,
|
||||
// JSON-RPC2
|
||||
MethodNotFound = 32601,
|
||||
InvalidParameters = 32602,
|
||||
InvalidRequest = 32600,
|
||||
InternalError = 32603,
|
||||
ParseError = 32700,
|
||||
// I2PControl specific
|
||||
InvalidPassword = 32001,
|
||||
NoToken = 32002,
|
||||
NonexistantToken = 32003,
|
||||
ExpiredToken = 32004,
|
||||
UnspecifiedVersion = 32005,
|
||||
UnsupportedVersion = 32006
|
||||
};
|
||||
|
||||
class Response {
|
||||
std::string id;
|
||||
std::string version;
|
||||
ErrorCode error;
|
||||
std::map<std::string, std::string> parameters;
|
||||
|
||||
public:
|
||||
Response(const std::string& id, const std::string& version = "2.0");
|
||||
Response(const std::string& version = "2.0");
|
||||
std::string toJsonString() const;
|
||||
|
||||
/**
|
||||
@ -74,6 +95,11 @@ public:
|
||||
void setParam(const std::string& param, const std::string& value);
|
||||
void setParam(const std::string& param, int value);
|
||||
void setParam(const std::string& param, double value);
|
||||
|
||||
void setError(ErrorCode code);
|
||||
void setId(const std::string& identifier);
|
||||
|
||||
std::string getErrorMsg() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -95,6 +121,13 @@ private:
|
||||
);
|
||||
typedef void (I2PControlSession::*RequestHandler)(Response& results);
|
||||
|
||||
|
||||
/**
|
||||
* Tries to authenticate by checking whether the given token is valid.
|
||||
* Sets the appropriate error code in the given response.
|
||||
*/
|
||||
bool authenticate(const PropertyTree& pt, Response& response);
|
||||
|
||||
// Method handlers
|
||||
void handleAuthenticate(const PropertyTree& pt, Response& response);
|
||||
void handleEcho(const PropertyTree& pt, Response& response);
|
||||
@ -120,6 +153,7 @@ private:
|
||||
void handleReseed(Response& response);
|
||||
|
||||
std::string password;
|
||||
std::set<std::string> tokens;
|
||||
|
||||
std::map<std::string, MethodHandler> methodHandlers;
|
||||
std::map<std::string, RequestHandler> routerInfoHandlers;
|
||||
|
Loading…
Reference in New Issue
Block a user