mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-09 06:23:47 +01:00
Expire tokens, use std::shared_ptr for I2PControlSession.
This commit is contained in:
parent
109127a39e
commit
69d93146f2
4 changed files with 69 additions and 14 deletions
|
@ -101,7 +101,8 @@ void I2PControlSession::Response::setId(const std::string& identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PControlSession::I2PControlSession(boost::asio::io_service& ios)
|
I2PControlSession::I2PControlSession(boost::asio::io_service& ios)
|
||||||
: password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), service(ios), shutdownTimer(ios)
|
: password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), tokensMutex(),
|
||||||
|
service(ios), shutdownTimer(ios), expireTokensTimer(ios)
|
||||||
{
|
{
|
||||||
// Method handlers
|
// Method handlers
|
||||||
methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate;
|
methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate;
|
||||||
|
@ -127,15 +128,16 @@ I2PControlSession::I2PControlSession(boost::asio::io_service& ios)
|
||||||
routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed;
|
routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PControlSession::~I2PControlSession()
|
void I2PControlSession::start()
|
||||||
{
|
{
|
||||||
stop();
|
startExpireTokensJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlSession::stop()
|
void I2PControlSession::stop()
|
||||||
{
|
{
|
||||||
boost::system::error_code e; // Make sure this doesn't throw
|
boost::system::error_code e; // Make sure this doesn't throw
|
||||||
shutdownTimer.cancel(e);
|
shutdownTimer.cancel(e);
|
||||||
|
expireTokensTimer.cancel(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request)
|
I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request)
|
||||||
|
@ -176,10 +178,17 @@ bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::string token = pt.get<std::string>(I2P_CONTROL_PARAM_TOKEN);
|
std::string token = pt.get<std::string>(I2P_CONTROL_PARAM_TOKEN);
|
||||||
if(tokens.find(token) == tokens.end()) {
|
|
||||||
|
std::lock_guard<std::mutex> lock(tokensMutex);
|
||||||
|
auto it = tokens.find(token);
|
||||||
|
if(it == tokens.end()) {
|
||||||
response.setError(ErrorCode::NonexistantToken);
|
response.setError(ErrorCode::NonexistantToken);
|
||||||
return false;
|
return false;
|
||||||
|
} else if(util::GetSecondsSinceEpoch() - it->second > I2P_CONTROL_TOKEN_LIFETIME) {
|
||||||
|
response.setError(ErrorCode::ExpiredToken);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(const boost::property_tree::ptree_error& error) {
|
} catch(const boost::property_tree::ptree_error& error) {
|
||||||
response.setError(ErrorCode::NoToken);
|
response.setError(ErrorCode::NoToken);
|
||||||
return false;
|
return false;
|
||||||
|
@ -219,7 +228,9 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res
|
||||||
const std::string token = generateToken();
|
const std::string token = generateToken();
|
||||||
response.setParam(I2P_CONTROL_PARAM_API, api);
|
response.setParam(I2P_CONTROL_PARAM_API, api);
|
||||||
response.setParam(I2P_CONTROL_PARAM_TOKEN, token);
|
response.setParam(I2P_CONTROL_PARAM_TOKEN, token);
|
||||||
tokens.insert(token);
|
|
||||||
|
std::lock_guard<std::mutex> lock(tokensMutex);
|
||||||
|
tokens.insert(std::make_pair(token, util::GetSecondsSinceEpoch()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response)
|
void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response)
|
||||||
|
@ -367,5 +378,30 @@ void I2PControlSession::handleReseed(Response& response)
|
||||||
i2p::data::netdb.Reseed();
|
i2p::data::netdb.Reseed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2PControlSession::expireTokens(const boost::system::error_code& error)
|
||||||
|
{
|
||||||
|
if(error == boost::asio::error::operation_aborted)
|
||||||
|
return; // Do not restart timer, shutting down
|
||||||
|
|
||||||
|
startExpireTokensJob();
|
||||||
|
LogPrint(eLogDebug, "I2PControl is expiring tokens.");
|
||||||
|
const uint64_t now = util::GetSecondsSinceEpoch();
|
||||||
|
std::lock_guard<std::mutex> lock(tokensMutex);
|
||||||
|
for(auto it = tokens.begin(); it != tokens.end(); ) {
|
||||||
|
if(now - it->second > I2P_CONTROL_TOKEN_LIFETIME)
|
||||||
|
it = tokens.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlSession::startExpireTokensJob()
|
||||||
|
{
|
||||||
|
expireTokensTimer.expires_from_now(boost::posix_time::seconds(I2P_CONTROL_TOKEN_LIFETIME));
|
||||||
|
expireTokensTimer.async_wait(std::bind(
|
||||||
|
&I2PControlSession::expireTokens, shared_from_this(), std::placeholders::_1
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
namespace i2p {
|
namespace i2p {
|
||||||
namespace client {
|
namespace client {
|
||||||
|
|
||||||
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
|
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
|
||||||
|
const uint64_t I2P_CONTROL_TOKEN_LIFETIME = 600; // Token lifetime in seconds
|
||||||
|
|
||||||
const char I2P_CONTROL_PROPERTY_ID[] = "id";
|
const char I2P_CONTROL_PROPERTY_ID[] = "id";
|
||||||
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
|
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
|
||||||
|
@ -57,9 +58,10 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
|
||||||
/**
|
/**
|
||||||
* "Null" I2P control implementation, does not do actual networking.
|
* "Null" I2P control implementation, does not do actual networking.
|
||||||
* @note authentication tokens are per-session
|
* @note authentication tokens are per-session
|
||||||
|
* @note I2PControlSession must always be used as a std::shared_ptr
|
||||||
* @warning an I2PControlSession must be destroyed before its io_service
|
* @warning an I2PControlSession must be destroyed before its io_service
|
||||||
*/
|
*/
|
||||||
class I2PControlSession {
|
class I2PControlSession : public std::enable_shared_from_this<I2PControlSession> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class ErrorCode {
|
enum class ErrorCode {
|
||||||
|
@ -110,11 +112,16 @@ public:
|
||||||
*/
|
*/
|
||||||
I2PControlSession(boost::asio::io_service& ios);
|
I2PControlSession(boost::asio::io_service& ios);
|
||||||
|
|
||||||
~I2PControlSession();
|
/**
|
||||||
|
* Starts the I2PControlSession.
|
||||||
|
* In essence, this starts the expireTokensTimer.
|
||||||
|
* @note should always be called after construction
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all operations that are waiting.
|
* Cancels all operations that are waiting.
|
||||||
* @note must not be called before destruction, destructor handles this
|
* @note it's a good idea to call this before destruction (shared_ptr reset)
|
||||||
*/
|
*/
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
@ -143,6 +150,13 @@ private:
|
||||||
*/
|
*/
|
||||||
std::string generateToken() const;
|
std::string generateToken() const;
|
||||||
|
|
||||||
|
void startExpireTokensJob();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expire tokens that are too old.
|
||||||
|
*/
|
||||||
|
void expireTokens(const boost::system::error_code& error);
|
||||||
|
|
||||||
// Method handlers
|
// Method handlers
|
||||||
void handleAuthenticate(const PropertyTree& pt, Response& response);
|
void handleAuthenticate(const PropertyTree& pt, Response& response);
|
||||||
void handleEcho(const PropertyTree& pt, Response& response);
|
void handleEcho(const PropertyTree& pt, Response& response);
|
||||||
|
@ -168,7 +182,8 @@ private:
|
||||||
void handleReseed(Response& response);
|
void handleReseed(Response& response);
|
||||||
|
|
||||||
std::string password;
|
std::string password;
|
||||||
std::set<std::string> tokens;
|
std::map<std::string, uint64_t> tokens;
|
||||||
|
std::mutex tokensMutex;
|
||||||
|
|
||||||
std::map<std::string, MethodHandler> methodHandlers;
|
std::map<std::string, MethodHandler> methodHandlers;
|
||||||
std::map<std::string, RequestHandler> routerInfoHandlers;
|
std::map<std::string, RequestHandler> routerInfoHandlers;
|
||||||
|
@ -177,6 +192,7 @@ private:
|
||||||
|
|
||||||
boost::asio::io_service& service;
|
boost::asio::io_service& service;
|
||||||
boost::asio::deadline_timer shutdownTimer;
|
boost::asio::deadline_timer shutdownTimer;
|
||||||
|
boost::asio::deadline_timer expireTokensTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@ namespace i2p
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
I2PControlService::I2PControlService(const std::string& address, int port)
|
I2PControlService::I2PControlService(const std::string& address, int port)
|
||||||
: m_Session(new I2PControlSession(m_Service)), m_IsRunning(false), m_Thread(nullptr),
|
: m_Session(std::make_shared<I2PControlSession>(m_Service)),
|
||||||
|
m_IsRunning(false), m_Thread(nullptr),
|
||||||
m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint(
|
m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint(
|
||||||
boost::asio::ip::address::from_string(address), port)
|
boost::asio::ip::address::from_string(address), port)
|
||||||
)
|
)
|
||||||
|
@ -29,6 +30,7 @@ namespace client
|
||||||
if (!m_IsRunning)
|
if (!m_IsRunning)
|
||||||
{
|
{
|
||||||
Accept ();
|
Accept ();
|
||||||
|
m_Session->start();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
|
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
|
||||||
}
|
}
|
||||||
|
@ -40,8 +42,9 @@ namespace client
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Acceptor.cancel ();
|
m_Acceptor.cancel ();
|
||||||
// Delete the session before the io_service is stopped and destroyed
|
m_Session->stop();
|
||||||
delete m_Session;
|
// Release ownership before the io_service is stopped and destroyed
|
||||||
|
m_Session.reset();
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,7 @@ private:
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
|
|
||||||
I2PControlSession* m_Session;
|
std::shared_ptr<I2PControlSession> m_Session;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue