gradido/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp
2019-10-15 11:26:36 +02:00

212 lines
6.0 KiB
C++

#include "PageRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTMLForm.h"
#include "ConfigPage.h"
#include "LoginPage.h"
#include "RegisterPage.h"
#include "HandleFileRequest.h"
#include "DashboardPage.h"
#include "CheckEmailPage.h"
#include "PassphrasePage.h"
#include "SaveKeysPage.h"
#include "ElopageWebhook.h"
#include "UpdateUserPasswordPage.h"
#include "Error500Page.h"
#include "../SingletonManager/SessionManager.h"
#include "../model/Profiler.h"
PageRequestHandlerFactory::PageRequestHandlerFactory()
: mRemoveGETParameters("^/([a-zA-Z0-9_-]*)")
{
}
Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request)
{
//printf("request uri: %s\n", request.getURI().data());
std::string uri = request.getURI();
std::string url_first_part;
mRemoveGETParameters.extract(uri, url_first_part);
if (uri != "/favicon.ico") {
printf("[PageRequestHandlerFactory] uri: %s, first part: %s\n", uri.data(), url_first_part.data());
auto referer = request.find("Referer");
if (referer != request.end()) {
printf("referer: %s\n", referer->second.data());
}
}
if (url_first_part == "/elopage_webhook_261") {
//printf("choose elopage\n");
return new ElopageWebhook;
}
// check if user has valid session
Poco::Net::NameValueCollection cookies;
request.getCookies(cookies);
int session_id = 0;
try {
session_id = atoi(cookies.get("GRADIDO_LOGIN").data());
} catch (...) {}
auto sm = SessionManager::getInstance();
auto s = sm->getSession(session_id);
// TODO: count invalid session requests from IP and block IP for some time to prevent brute force session hijacking
// or use log file and configure fail2ban for this to do
if (url_first_part == "/checkEmail") {
//return new CheckEmailPage(s);
if (!s || s->getSessionState() < SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED) {
return handleCheckEmail(s, uri, request);
}
}
if (s) {
auto user = s->getUser();
if (s->errorCount() || (!user.isNull() && user->errorCount())) {
return new Error500Page(s);
}
if(url_first_part == "/logout") {
sm->releaseSession(s);
// remove cookie
printf("session released\n");
return new LoginPage;
}
if(url_first_part == "/user_delete") {
if(s->deleteUser()) {
sm->releaseSession(s);
return new LoginPage;
}
}
auto sessionState = s->getSessionState();
if(sessionState == SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED ||
sessionState == SESSION_STATE_PASSPHRASE_GENERATED) {
//if (url_first_part == "/passphrase") {
//return handlePassphrase(s, request);
return new PassphrasePage(s);
}
else if(sessionState == SESSION_STATE_PASSPHRASE_SHOWN) {
//else if (uri == "/saveKeys") {
return new SaveKeysPage(s);
}
if (s && !s->getUser().isNull()) {
printf("[PageRequestHandlerFactory] go to dashboard page with user\n");
return new DashboardPage(s);
}
} else {
if (url_first_part == "/config") {
return new ConfigPage;
}
else if (url_first_part == "/login") {
return new LoginPage;
}
else if (url_first_part == "/register") {
return new RegisterPage;
}
}
return new LoginPage;
//return new HandleFileRequest;
//return new PageRequestHandlerFactory;
}
Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Session* session, const std::string uri, const Poco::Net::HTTPServerRequest& request)
{
Profiler timeUsed;
Poco::Net::HTMLForm form(request);
unsigned long long verificationCode = 0;
// if verification code is valid, go to next page, passphrase
// login via verification code, if no session is active
// try to get code from form get parameter
if (!form.empty()) {
try {
verificationCode = stoull(form.get("email-verification-code", "0"));
} catch (...) {}
}
// try to get code from uri parameter
if (!verificationCode) {
size_t pos = uri.find_last_of("/");
try {
auto str = uri.substr(pos + 1);
verificationCode = stoull(uri.substr(pos + 1));
} catch (const std::invalid_argument& ia) {
std::cerr << "Invalid argument: " << ia.what() << '\n';
} catch (const std::out_of_range& oor) {
std::cerr << "Out of Range error: " << oor.what() << '\n';
}
catch (const std::logic_error & ler) {
std::cerr << "Logical error: " << ler.what() << '\n';
}
catch (...) {
std::cerr << "Unknown error" << '\n';
}
}
// if no verification code given or error with given code, show form
if (!verificationCode) {
return new CheckEmailPage(session);
}
// we have a verification code, now let's check that thing
auto sm = SessionManager::getInstance();
// no session or active session don't belong to verification code
if (!session || session->getEmailVerificationCode() != verificationCode) {
//sm->releaseSession(session);
//session = nullptr;
// it is maybe unsafe
session = sm->findByEmailVerificationCode(verificationCode);
}
// no suitable session in memory, try to create one from db data
if (!session) {
session = sm->getNewSession();
if (session->loadFromEmailVerificationCode(verificationCode)) {
// login not possible in this function, forwarded to PassphrasePage
/*auto cookie_id = session->getHandle();
auto user_host = request.clientAddress().host();
session->setClientIp(user_host);
response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id)));
*/
}
else {
//sm->releaseSession(session);
return new CheckEmailPage(session);
}
}
// suitable session found or created
if (session) {
auto user_host = request.clientAddress().host();
session->setClientIp(user_host);
if (session->getUser()->isEmptyPassword()) {
// user has no password, maybe account created from elopage webhook
return new UpdateUserPasswordPage(session);
}
// update session, mark as verified
if (session->updateEmailVerification(verificationCode)) {
printf("[PageRequestHandlerFactory::handleCheckEmail] timeUsed: %s\n", timeUsed.string().data());
return new PassphrasePage(session);
}
}
if (session) {
sm->releaseSession(session);
}
return new CheckEmailPage(nullptr);
}