Merge pull request #82 from gradido/api_password_reset

Api password reset
This commit is contained in:
einhornimmond 2021-03-31 12:54:08 +02:00 committed by GitHub
commit 663c11e3c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1060 additions and 692 deletions

View File

@ -22,7 +22,10 @@ loginServer.db.user = root
loginServer.db.password = loginServer.db.password =
loginServer.db.port = 3306 loginServer.db.port = 3306
frontend.checkEmailPath = http://localhost/account/checkEmail
email.disable = true email.disable = true
#email.username = #email.username =
#email.sender = #email.sender =
#email.admin_receiver = #email.admin_receiver =
@ -48,4 +51,6 @@ unsecure.allow_passwort_via_json_request = 1
unsecure.allow_auto_sign_transactions = 1 unsecure.allow_auto_sign_transactions = 1
unsecure.allow_cors_all = 1 unsecure.allow_cors_all = 1
# default disable, passwords must contain a number, a lower character, a high character, special character, and be at least 8 characters long # default disable, passwords must contain a number, a lower character, a high character, special character, and be at least 8 characters long
unsecure.allow_all_passwords = 1
unsecure.allow_all_passwords = 1

View File

@ -98,6 +98,7 @@ Update password can only be used if in Login-Server config:
```ini ```ini
unsecure.allow_passwort_via_json_request = 1 unsecure.allow_passwort_via_json_request = 1
``` ```
is set
POST http://localhost/login_api/updateUserInfos POST http://localhost/login_api/updateUserInfos
```json ```json
@ -207,10 +208,70 @@ return
- registerDirect: code generated by register for check email - registerDirect: code generated by register for check email
- register: code generated by auto-register via elopage for check email - register: code generated by auto-register via elopage for check email
- info can contain additional info strings - info can contain additional info strings
- user hasn't password: if user hasn't set a password yet (for example if he was registered via elopage) - "user hasn't password": if user hasn't set a password yet (for example if he was registered via elopage)
- email already activated: if email was already checked - "email already activated": if email was already checked
- session_id: session_id for new session - session_id: session_id for new session
## Send Emails
Let send Login-Server Password reset E-Mail to User
Can be also used for admin interface to resend email verification code
POST http://localhost/login_api/sendEmail
```json
{"email": "max.musterman@gmail.de", "email_text":7, "email_verification_code_type":"resetPassword" }
```
also valid:
```json
{"email": "max.musterman@gmail.de", "email_text":"user reset Password", "email_verification_code_type":"resetPassword" }
```
or:
```json
{"session_id": -127182, "email": "max.musterman@gmail.de", "email_text":5, "email_verification_code_type":"register" }
```
- session_id: not needed for resetPassword emails
- email_type: choose which email text should be used (number or string can be used)
- "email user verification code" (2): default text used when new user has registered
- "email user verification code resend" (3): text used when user hasn't activated his account 7 days after register
- "email user verification code resend after long time" (4): text used when user hasn't activated his account more than 7 days after register
- "email admin user verification code" (5): used if admin trigger sending the email with email verification code
- "email admin user verification code resend" (6): used if admin trigger sending the email with email verification code again
- "user reset Password" (7): used for reset password email text
- "email custom tex" (8): used if custom email text should be used (than email_custom_text and email_custom_subject must also be filled)
- email_verification_code_type
- resetPassword: for password resets, will be deleted immediately, is a only one use code, can be used without session_id
- registerDirect: code generated by register for check email, can only be used by admins for another user
- register: code generated by auto-register via elopage for check email, can only be used by admins for another user
- email_custom_text (optional): can be used to send email with custom text
placeholder for email text, will be replaced
- [first_name] first name
- [last_name] last name
- [duration] time span since user has created account (ex.: 10 Days) with largest unit, day is last unit
- [link] login-server checkEmail link with email verification code (ex.: http://localhost/account/checkEmail/382738273892983)
- [code] email verification code if you like to use your one link
- email_custom_subject (optional): for custom email the subject
return
```json
{"state":"success"}
```
if everything is okay
return
```json
{"state":"warning", "msg":"email already sended"}
```
if emails was successfully sended but was already sended in past also.
return with "state":"error" and additional "msg" if error occured (no email sended):
- "email already send less than a hour before": User has already get a password reset email and haven't used the link yet
- "not supported email type": with "email_verification_code_type":"resetPassword" only email type 7 or 8 allowed
- "admin needed": only admins can send email verification emails because this emails normally sended out automaticly
- "invalid email": if email wasn't found in db
- "invalid session": if session wasn't found (only checked if session_id is set and != 0)
- "invalid email type": could not parse email type
- "invalid verification code type": could not parse email verification code type
- "json exception": error parsing input json, more infos can be found in details
## Check Running Transactions / password encryption ## Check Running Transactions / password encryption
Check if transactions on login-server for user are processed Check if transactions on login-server for user are processed

View File

@ -7,12 +7,30 @@ const EMAIL_TYPE = {
ADMIN: 5, // if user was registered by an admin ADMIN: 5, // if user was registered by an admin
} }
const apiGet = async (url) => {
try {
const result = await axios.get(url)
if (result.status !== 200) {
throw new Error('HTTP Status Error ' + result.status)
}
if (result.data.state !== 'success') {
throw new Error(result.data.msg)
}
return { success: true, result }
} catch (error) {
return { success: false, result: error }
}
}
const apiPost = async (url, payload) => { const apiPost = async (url, payload) => {
try { try {
const result = await axios.post(url, payload) const result = await axios.post(url, payload)
if (result.status !== 200) { if (result.status !== 200) {
throw new Error('HTTP Status Error ' + result.status) throw new Error('HTTP Status Error ' + result.status)
} }
if (result.data.state === 'warning') {
return { success: true, result: error }
}
if (result.data.state !== 'success') { if (result.data.state !== 'success') {
throw new Error(result.data.msg) throw new Error(result.data.msg)
} }

View File

@ -1,141 +1,153 @@
#include "JsonRequestHandler.h" #include "JsonRequestHandler.h"
#include "Poco/Net/HTTPServerRequest.h" #include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h" #include "Poco/Net/HTTPServerResponse.h"
#include "Poco/URI.h" #include "Poco/URI.h"
#include "Poco/DeflatingStream.h" #include "Poco/DeflatingStream.h"
#include "Poco/JSON/Parser.h" #include "Poco/JSON/Parser.h"
#include "../ServerConfig.h" #include "../ServerConfig.h"
#include "../lib/DataTypeConverter.h" #include "../lib/DataTypeConverter.h"
#include "../SingletonManager/SessionManager.h" #include "../SingletonManager/SessionManager.h"
void JsonRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) void JsonRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{ {
response.setChunkedTransferEncoding(false); response.setChunkedTransferEncoding(false);
response.setContentType("application/json"); response.setContentType("application/json");
if (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_CORS_ALL) { if (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_CORS_ALL) {
response.set("Access-Control-Allow-Origin", "*"); response.set("Access-Control-Allow-Origin", "*");
response.set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); response.set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
} }
//bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); //bool _compressResponse(request.hasToken("Accept-Encoding", "gzip"));
//if (_compressResponse) response.set("Content-Encoding", "gzip"); //if (_compressResponse) response.set("Content-Encoding", "gzip");
std::ostream& responseStream = response.send(); std::ostream& responseStream = response.send();
//Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); //Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
//std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; //std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;
auto method = request.getMethod(); auto method = request.getMethod();
std::istream& request_stream = request.stream(); std::istream& request_stream = request.stream();
Poco::JSON::Object* json_result = nullptr; Poco::JSON::Object* json_result = nullptr;
if (method == "POST" || method == "PUT") { if (method == "POST" || method == "PUT") {
// extract parameter from request // extract parameter from request
Poco::Dynamic::Var parsedResult = parseJsonWithErrorPrintFile(request_stream); Poco::Dynamic::Var parsedResult = parseJsonWithErrorPrintFile(request_stream);
if (parsedResult.size() != 0) { if (parsedResult.size() != 0) {
json_result = handle(parsedResult); json_result = handle(parsedResult);
} }
else { else {
json_result = stateError("empty body"); json_result = stateError("empty body");
} }
} }
else if(method == "GET") { else if(method == "GET") {
Poco::URI uri(request.getURI()); Poco::URI uri(request.getURI());
auto queryParameters = uri.getQueryParameters(); auto queryParameters = uri.getQueryParameters();
json_result = handle(queryParameters); json_result = handle(queryParameters);
} }
if (json_result) { if (json_result) {
if (!json_result->isNull("session_id")) { if (!json_result->isNull("session_id")) {
int session_id = 0; int session_id = 0;
try { try {
json_result->get("session_id").convert(session_id); json_result->get("session_id").convert(session_id);
} }
catch (Poco::Exception& e) { catch (Poco::Exception& e) {
ErrorList erros; ErrorList erros;
erros.addError(new Error("json request", "invalid session_id")); erros.addError(new Error("json request", "invalid session_id"));
erros.sendErrorsAsEmail(); erros.sendErrorsAsEmail();
} }
if (session_id) { if (session_id) {
auto session = SessionManager::getInstance()->getSession(session_id); auto session = SessionManager::getInstance()->getSession(session_id);
response.addCookie(session->getLoginCookie()); response.addCookie(session->getLoginCookie());
} }
} }
json_result->stringify(responseStream); json_result->stringify(responseStream);
delete json_result; delete json_result;
} }
//if (_compressResponse) _gzipStream.close(); //if (_compressResponse) _gzipStream.close();
} }
Poco::Dynamic::Var JsonRequestHandler::parseJsonWithErrorPrintFile(std::istream& request_stream, ErrorList* errorHandler /* = nullptr*/, const char* functionName /* = nullptr*/) Poco::Dynamic::Var JsonRequestHandler::parseJsonWithErrorPrintFile(std::istream& request_stream, ErrorList* errorHandler /* = nullptr*/, const char* functionName /* = nullptr*/)
{ {
// debugging answer // debugging answer
std::stringstream responseStringStream; std::stringstream responseStringStream;
for (std::string line; std::getline(request_stream, line); ) { for (std::string line; std::getline(request_stream, line); ) {
responseStringStream << line << std::endl; responseStringStream << line << std::endl;
} }
// extract parameter from request // extract parameter from request
Poco::JSON::Parser jsonParser; Poco::JSON::Parser jsonParser;
Poco::Dynamic::Var parsedJson; Poco::Dynamic::Var parsedJson;
try { try {
parsedJson = jsonParser.parse(responseStringStream.str()); parsedJson = jsonParser.parse(responseStringStream.str());
return parsedJson; return parsedJson;
} }
catch (Poco::Exception& ex) { catch (Poco::Exception& ex) {
if (errorHandler) { if (errorHandler) {
errorHandler->addError(new ParamError(functionName, "error parsing request answer", ex.displayText().data())); errorHandler->addError(new ParamError(functionName, "error parsing request answer", ex.displayText().data()));
errorHandler->sendErrorsAsEmail(responseStringStream.str()); errorHandler->sendErrorsAsEmail(responseStringStream.str());
} }
std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d_%m_%yT%H_%M_%S"); std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d_%m_%yT%H_%M_%S");
std::string filename = dateTimeString + "_response.html"; std::string filename = dateTimeString + "_response.html";
FILE* f = fopen(filename.data(), "wt"); FILE* f = fopen(filename.data(), "wt");
if (f) { if (f) {
std::string responseString = responseStringStream.str(); std::string responseString = responseStringStream.str();
fwrite(responseString.data(), 1, responseString.size(), f); fwrite(responseString.data(), 1, responseString.size(), f);
fclose(f); fclose(f);
} }
return Poco::Dynamic::Var(); return Poco::Dynamic::Var();
} }
return Poco::Dynamic::Var(); return Poco::Dynamic::Var();
} }
Poco::JSON::Object* JsonRequestHandler::stateError(const char* msg, std::string details) Poco::JSON::Object* JsonRequestHandler::stateError(const char* msg, std::string details)
{ {
Poco::JSON::Object* result = new Poco::JSON::Object; Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "error"); result->set("state", "error");
result->set("msg", msg); result->set("msg", msg);
if (details != "") { if (details != "") {
result->set("details", details); result->set("details", details);
} }
return result; return result;
} }
Poco::JSON::Object* JsonRequestHandler::stateSuccess() Poco::JSON::Object* JsonRequestHandler::stateSuccess()
{ {
Poco::JSON::Object* result = new Poco::JSON::Object; Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "success"); result->set("state", "success");
return result; return result;
} }
Poco::JSON::Object* JsonRequestHandler::customStateError(const char* state, const char* msg, std::string details/* = ""*/) Poco::JSON::Object* JsonRequestHandler::customStateError(const char* state, const char* msg, std::string details/* = ""*/)
{ {
Poco::JSON::Object* result = new Poco::JSON::Object; Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", state); result->set("state", state);
result->set("msg", msg); result->set("msg", msg);
if (details != "") { if (details != "") {
result->set("details", details); result->set("details", details);
} }
return result; return result;
} }
Poco::JSON::Object* JsonRequestHandler::stateWarning(const char* msg, std::string details/* = ""*/)
{
Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "warning");
result->set("msg", msg);
if (details != "") {
result->set("details", details);
}
return result;
}

View File

@ -22,6 +22,7 @@ protected:
static Poco::JSON::Object* stateError(const char* msg, std::string details = ""); static Poco::JSON::Object* stateError(const char* msg, std::string details = "");
static Poco::JSON::Object* customStateError(const char* state, const char* msg, std::string details = ""); static Poco::JSON::Object* customStateError(const char* state, const char* msg, std::string details = "");
static Poco::JSON::Object* stateSuccess(); static Poco::JSON::Object* stateSuccess();
static Poco::JSON::Object* stateWarning(const char* msg, std::string details = "");
}; };

View File

@ -1,82 +1,90 @@
#include "JsonRequestHandlerFactory.h"
#include "JsonRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "../SingletonManager/SessionManager.h"
#include "../SingletonManager/SessionManager.h"
#include "JsonAdminEmailVerificationResend.h"
#include "JsonCheckSessionState.h" #include "JsonAdminEmailVerificationResend.h"
#include "JsonCreateUser.h" #include "JsonCheckSessionState.h"
#include "JsonGetLogin.h" #include "JsonCreateUser.h"
#include "JsonUnknown.h" #include "JsonGetLogin.h"
#include "JsonTransaction.h" #include "JsonUnknown.h"
#include "JsonGetRunningUserTasks.h" #include "JsonTransaction.h"
#include "JsonGetUsers.h" #include "JsonGetRunningUserTasks.h"
#include "JsonLoginViaEmailVerificationCode.h" #include "JsonGetUsers.h"
#include "JsonGetUserInfos.h" #include "JsonLoginViaEmailVerificationCode.h"
#include "JsonUpdateUserInfos.h" #include "JsonLogout.h"
#include "JsonUnsecureLogin.h" #include "JsonSendEmail.h"
#include "JsonLogout.h" #include "JsonAdminEmailVerificationResend.h"
#include "JsonGetUserInfos.h"
JsonRequestHandlerFactory::JsonRequestHandlerFactory() #include "JsonUpdateUserInfos.h"
: mRemoveGETParameters("^/([a-zA-Z0-9_-]*)"), mLogging(Poco::Logger::get("requestLog")) #include "JsonUnsecureLogin.h"
{
}
JsonRequestHandlerFactory::JsonRequestHandlerFactory()
Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)"), mLogging(Poco::Logger::get("requestLog"))
{ {
std::string uri = request.getURI(); }
std::string url_first_part;
std::stringstream logStream; Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request)
{
mRemoveGETParameters.extract(uri, url_first_part); std::string uri = request.getURI();
std::string url_first_part;
std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); std::stringstream logStream;
logStream << dateTimeString << " call " << uri;
mRemoveGETParameters.extract(uri, url_first_part);
mLogging.information(logStream.str());
std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S");
auto client_host = request.clientAddress().host(); logStream << dateTimeString << " call " << uri;
//auto client_ip = request.clientAddress();
// X-Real-IP forwarded ip from nginx config mLogging.information(logStream.str());
auto client_host_string = request.get("X-Real-IP", client_host.toString());
client_host = Poco::Net::IPAddress(client_host_string); auto client_host = request.clientAddress().host();
//auto client_ip = request.clientAddress();
if (url_first_part == "/login") { // X-Real-IP forwarded ip from nginx config
return new JsonGetLogin; auto client_host_string = request.get("X-Real-IP", client_host.toString());
} client_host = Poco::Net::IPAddress(client_host_string);
else if (url_first_part == "/checkSessionState") {
return new JsonCheckSessionState; if (url_first_part == "/login") {
} return new JsonGetLogin;
else if (url_first_part == "/checkTransaction") { }
return new JsonTransaction; else if (url_first_part == "/checkSessionState") {
} return new JsonCheckSessionState;
else if (url_first_part == "/getRunningUserTasks") { }
return new JsonGetRunningUserTasks; else if (url_first_part == "/checkTransaction") {
} return new JsonTransaction;
else if (url_first_part == "/getUsers") { }
return new JsonGetUsers; else if (url_first_part == "/getRunningUserTasks") {
} return new JsonGetRunningUserTasks;
else if (url_first_part == "/createUser") { }
return new JsonCreateUser(client_host); else if (url_first_part == "/getUsers") {
} return new JsonGetUsers;
else if (url_first_part == "/adminEmailVerificationResend") { }
return new JsonAdminEmailVerificationResend; else if (url_first_part == "/createUser") {
} return new JsonCreateUser(client_host);
else if (url_first_part == "/getUserInfos") { }
return new JsonGetUserInfos; else if (url_first_part == "/adminEmailVerificationResend") {
} return new JsonAdminEmailVerificationResend;
else if (url_first_part == "/updateUserInfos") { }
return new JsonUpdateUserInfos; else if (url_first_part == "/getUserInfos") {
} return new JsonGetUserInfos;
else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { }
return new JsonUnsecureLogin(client_host); else if (url_first_part == "/updateUserInfos") {
} return new JsonUpdateUserInfos;
else if (url_first_part == "/loginViaEmailVerificationCode") { }
return new JsonLoginViaEmailVerificationCode(client_host); else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) {
} return new JsonUnsecureLogin(client_host);
else if (url_first_part == "/logout") { }
return new JsonLogout(client_host); else if (url_first_part == "/loginViaEmailVerificationCode") {
} return new JsonLoginViaEmailVerificationCode(client_host);
return new JsonUnknown; }
} else if (url_first_part == "/sendEmail") {
return new JsonSendEmail;
}
else if (url_first_part == "/logout") {
return new JsonLogout(client_host);
}
return new JsonUnknown;
}

View File

@ -0,0 +1,149 @@
#include "JsonSendEmail.h"
#include "Poco/URI.h"
#include "../SingletonManager/SessionManager.h"
#include "../SingletonManager/EmailManager.h"
#include "../SingletonManager/LanguageManager.h"
#include "../controller/User.h"
#include "../controller/EmailVerificationCode.h"
#include "../lib/DataTypeConverter.h"
Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
{
int session_id = 0;
std::string email;
model::EmailType emailType = model::EMAIL_DEFAULT;
model::table::EmailOptInType emailVerificationCodeType;
std::string emailCustomText;
std::string emailCustomSubject;
std::string languageCode;
std::string email_verification_code_type_string;
std::string email_type_string;
int email_type_int = 0;
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
try {
if (paramJsonObject->has("session_id")) {
paramJsonObject->get("session_id").convert(session_id);
}
if (paramJsonObject->has("email_custom_text")) {
paramJsonObject->get("email_custom_text").convert(emailCustomText);
}
if (paramJsonObject->has("email_custom_subject")) {
paramJsonObject->get("email_custom_subject").convert(emailCustomSubject);
}
if (paramJsonObject->has("language")) {
paramJsonObject->get("language").convert(languageCode);
}
paramJsonObject->get("email").convert(email);
paramJsonObject->get("email_verification_code_type").convert(email_verification_code_type_string);
auto email_text = paramJsonObject->get("email_text");
if (email_text.isString()) {
email_text.convert(email_type_string);
}
else if (email_text.isInteger()) {
email_text.convert(email_type_int);
}
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
// convert types into enum
if (email_type_int > 0 && email_type_int < model::EMAIL_MAX) {
emailType = (model::EmailType)email_type_int;
}
else if (email_type_string != "") {
emailType = model::Email::emailType(email_type_string);
}
emailVerificationCodeType = model::table::EmailOptIn::stringToType(email_verification_code_type_string);
if (model::table::EMAIL_OPT_IN_EMPTY == emailVerificationCodeType) {
return stateError("invalid verification code type");
}
switch (emailType) {
case model::EMAIL_DEFAULT:
case model::EMAIL_ERROR:
case model::EMAIL_MAX: return stateError("invalid email type");
}
if (0 == session_id &&
(model::table::EMAIL_OPT_IN_REGISTER == emailVerificationCodeType || model::table::EMAIL_OPT_IN_REGISTER_DIRECT == emailVerificationCodeType)
){
return stateError("login needed");
}
auto sm = SessionManager::getInstance();
auto em = EmailManager::getInstance();
auto lm = LanguageManager::getInstance();
Session* session = nullptr;
if (session_id != 0) {
session = sm->getSession(session_id);
if (nullptr == session) {
return stateError("invalid session");
}
}
auto receiver_user = controller::User::create();
if (1 != receiver_user->load(email)) {
return stateError("invalid email");
}
auto receiver_user_id = receiver_user->getModel()->getID();
if (emailVerificationCodeType == model::table::EMAIL_OPT_IN_RESET_PASSWORD)
{
session = sm->getNewSession();
if (emailType == model::EMAIL_USER_RESET_PASSWORD) {
auto r = session->sendResetPasswordEmail(receiver_user, false);
if (1 == r) {
return stateWarning("email already sended");
}
else if (2 == r) {
return stateError("email already send less than a hour before");
}
}
else if (emailType == model::EMAIL_CUSTOM_TEXT) {
auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, model::table::EMAIL_OPT_IN_RESET_PASSWORD);
auto email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject);
em->addEmail(email);
}
else {
return stateError("not supported email type");
}
return stateSuccess();
}
else
{
if (session->getNewUser()->getModel()->getRole() != model::table::ROLE_ADMIN) {
return stateError("admin needed");
}
auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, emailVerificationCodeType);
model::Email* email = nullptr;
if (emailType == model::EMAIL_CUSTOM_TEXT) {
email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject);
}
else {
email = new model::Email(email_verification_code_object, receiver_user, emailType);
}
em->addEmail(email);
return stateSuccess();
}
}

View File

@ -0,0 +1,16 @@
#ifndef __JSON_SEND_EMAIL_H
#define __JSON_SEND_EMAIL_H
#include "JsonRequestHandler.h"
class JsonSendEmail : public JsonRequestHandler
{
public:
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
};
#endif // __JSON_SEND_EMAIL_H

View File

@ -68,7 +68,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
try { try {
if ( "User.first_name" == name) { if ( "User.first_name" == name && value.size() > 0) {
if (!value.isString()) { if (!value.isString()) {
jsonErrorsArray.add("User.first_name isn't a string"); jsonErrorsArray.add("User.first_name isn't a string");
} }
@ -77,7 +77,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
extractet_values++; extractet_values++;
} }
} }
else if ("User.last_name" == name) { else if ("User.last_name" == name && value.size() > 0) {
if (!value.isString()) { if (!value.isString()) {
jsonErrorsArray.add("User.last_name isn't a string"); jsonErrorsArray.add("User.last_name isn't a string");
} }
@ -103,7 +103,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
jsonErrorsArray.add("User.disabled isn't a boolean or integer"); jsonErrorsArray.add("User.disabled isn't a boolean or integer");
} }
} }
else if ("User.language" == name) { else if ("User.language" == name && value.size() > 0) {
if (!value.isString()) { if (!value.isString()) {
jsonErrorsArray.add("User.language isn't a string"); jsonErrorsArray.add("User.language isn't a string");
} }
@ -118,7 +118,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
} }
} }
} }
else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS) { else if ("User.password" == name && value.size() > 0 && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS) {
if (!value.isString()) { if (!value.isString()) {
jsonErrorsArray.add("User.password isn't string"); jsonErrorsArray.add("User.password isn't string");
} }

View File

@ -1,349 +1,352 @@
#include "ServerConfig.h" #include "ServerConfig.h"
#include "Crypto/mnemonic_german.h" #include "Crypto/mnemonic_german.h"
#include "Crypto/mnemonic_german2.h" #include "Crypto/mnemonic_german2.h"
#include "Crypto/mnemonic_bip0039.h" #include "Crypto/mnemonic_bip0039.h"
#include "Crypto/DRRandom.h" #include "Crypto/DRRandom.h"
#include "lib/DataTypeConverter.h" #include "lib/DataTypeConverter.h"
#include "sodium.h" #include "sodium.h"
#include "Poco/Net/SSLManager.h" #include "Poco/Net/SSLManager.h"
#include "Poco/Net/KeyConsoleHandler.h" #include "Poco/Net/KeyConsoleHandler.h"
#include "Poco/Net/RejectCertificateHandler.h" #include "Poco/Net/RejectCertificateHandler.h"
#include "Poco/Net/DNS.h" #include "Poco/Net/DNS.h"
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
#include "Poco/Mutex.h" #include "Poco/Mutex.h"
#include "Poco/Path.h" #include "Poco/Path.h"
#include "Poco/FileStream.h" #include "Poco/FileStream.h"
#include "Poco/LocalDateTime.h" #include "Poco/LocalDateTime.h"
#include "Poco/DateTimeFormat.h" #include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h" #include "Poco/DateTimeFormatter.h"
using Poco::Net::SSLManager; using Poco::Net::SSLManager;
using Poco::Net::Context; using Poco::Net::Context;
using Poco::Net::KeyConsoleHandler; using Poco::Net::KeyConsoleHandler;
using Poco::Net::PrivateKeyPassphraseHandler; using Poco::Net::PrivateKeyPassphraseHandler;
using Poco::Net::InvalidCertificateHandler; using Poco::Net::InvalidCertificateHandler;
using Poco::Net::RejectCertificateHandler; using Poco::Net::RejectCertificateHandler;
using Poco::SharedPtr; using Poco::SharedPtr;
namespace ServerConfig { namespace ServerConfig {
#define SESSION_TIMEOUT_DEFAULT 10 #define SESSION_TIMEOUT_DEFAULT 10
Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
ObfusArray* g_ServerCryptoKey = nullptr; ObfusArray* g_ServerCryptoKey = nullptr;
ObfusArray* g_ServerKeySeed = nullptr; ObfusArray* g_ServerKeySeed = nullptr;
// std::string g_ServerAdminPublic; // std::string g_ServerAdminPublic;
UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr; UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr;
UniLib::controller::CPUSheduler* g_CryptoCPUScheduler = nullptr; UniLib::controller::CPUSheduler* g_CryptoCPUScheduler = nullptr;
Context::Ptr g_SSL_CLient_Context = nullptr; Context::Ptr g_SSL_CLient_Context = nullptr;
Poco::Util::Timer g_CronJobsTimer; Poco::Util::Timer g_CronJobsTimer;
EmailAccount g_EmailAccount; EmailAccount g_EmailAccount;
int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT; int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT;
std::string g_serverPath; std::string g_serverPath;
int g_serverPort = 0; int g_serverPort = 0;
Languages g_default_locale; Languages g_default_locale;
std::string g_php_serverPath; std::string g_php_serverPath;
std::string g_php_serverHost; std::string g_php_serverHost;
int g_phpServerPort; std::string g_frontend_checkEmailPath;
Poco::Mutex g_TimeMutex; int g_phpServerPort;
int g_FakeLoginSleepTime = 820; Poco::Mutex g_TimeMutex;
std::string g_versionString = ""; int g_FakeLoginSleepTime = 820;
bool g_disableEmail = false; std::string g_versionString = "";
ServerSetupType g_ServerSetupType = SERVER_TYPE_PRODUCTION; bool g_disableEmail = false;
std::string g_gRPCRelayServerFullURL; ServerSetupType g_ServerSetupType = SERVER_TYPE_PRODUCTION;
MemoryBin* g_CryptoAppSecret = nullptr; std::string g_gRPCRelayServerFullURL;
AllowUnsecure g_AllowUnsecureFlags = NOT_UNSECURE; MemoryBin* g_CryptoAppSecret = nullptr;
AllowUnsecure g_AllowUnsecureFlags = NOT_UNSECURE;
#ifdef __linux__
#include <stdio.h> #ifdef __linux__
#include <sys/types.h> #include <stdio.h>
#include <ifaddrs.h> #include <sys/types.h>
#include <netinet/in.h> #include <ifaddrs.h>
#include <string.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <string.h>
#endif //#ifdef __linux__ #include <arpa/inet.h>
#endif //#ifdef __linux__
std::string getHostIpString()
{ std::string getHostIpString()
#ifdef __linux__ {
struct ifaddrs * ifAddrStruct = NULL; #ifdef __linux__
struct ifaddrs * ifa = NULL; struct ifaddrs * ifAddrStruct = NULL;
void * tmpAddrPtr = NULL; struct ifaddrs * ifa = NULL;
void * tmpAddrPtr = NULL;
getifaddrs(&ifAddrStruct);
std::string ipAddressString; getifaddrs(&ifAddrStruct);
std::string ipAddressString;
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) { for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
continue; if (!ifa->ifa_addr) {
} continue;
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 }
// is a valid IP4 Address if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; // is a valid IP4 Address
char addressBuffer[INET_ADDRSTRLEN]; tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); char addressBuffer[INET_ADDRSTRLEN];
ipAddressString = addressBuffer; inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); ipAddressString = addressBuffer;
} printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6 }
// is a valid IP6 Address else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; // is a valid IP6 Address
char addressBuffer[INET6_ADDRSTRLEN]; tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); char addressBuffer[INET6_ADDRSTRLEN];
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
} printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
} }
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct); }
return ipAddressString; if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
#else //__linux__ return ipAddressString;
std::string ipAddressString = ""; #else //__linux__
auto host = Poco::Net::DNS::thisHost(); std::string ipAddressString = "";
for (auto it = host.addresses().begin(); it != host.addresses().end(); it++) { auto host = Poco::Net::DNS::thisHost();
auto ipAddress = *it; for (auto it = host.addresses().begin(); it != host.addresses().end(); it++) {
if (!ipAddress.isIPv4Compatible() && !ipAddress.isIPv4Mapped()) { auto ipAddress = *it;
continue; if (!ipAddress.isIPv4Compatible() && !ipAddress.isIPv4Mapped()) {
} continue;
if (ipAddress.isLoopback()) { }
continue; if (ipAddress.isLoopback()) {
} continue;
ipAddressString = ipAddress.toString(); }
//isIPv4Compatible ipAddressString = ipAddress.toString();
//!isLoopback //isIPv4Compatible
//printf("ipaddress: %s\n", ipAddressString.data()); //!isLoopback
break; //printf("ipaddress: %s\n", ipAddressString.data());
//break; break;
} //break;
return ipAddressString; }
#endif // __linux__ return ipAddressString;
} #endif // __linux__
}
bool replaceZeroIPWithLocalhostIP(std::string& url)
{ bool replaceZeroIPWithLocalhostIP(std::string& url)
auto pos = url.find("0.0.0.0", 0); {
if (pos != std::string::npos) { auto pos = url.find("0.0.0.0", 0);
std::string ipAddressString = getHostIpString(); if (pos != std::string::npos) {
if ("" != ipAddressString) { std::string ipAddressString = getHostIpString();
url.replace(pos, 7, ipAddressString); if ("" != ipAddressString) {
} url.replace(pos, 7, ipAddressString);
} }
}
//printf("ipaddress: %s\n", ipAddress.data());
//printf("ipaddress: %s\n", ipAddress.data());
return true;
} return true;
}
ServerSetupType getServerSetupTypeFromString(const std::string& serverSetupTypeString) {
if ("test" == serverSetupTypeString) { ServerSetupType getServerSetupTypeFromString(const std::string& serverSetupTypeString) {
return SERVER_TYPE_TEST; if ("test" == serverSetupTypeString) {
} return SERVER_TYPE_TEST;
if ("staging" == serverSetupTypeString) { }
return SERVER_TYPE_STAGING; if ("staging" == serverSetupTypeString) {
} return SERVER_TYPE_STAGING;
if ("production" == serverSetupTypeString) { }
return SERVER_TYPE_PRODUCTION; if ("production" == serverSetupTypeString) {
} return SERVER_TYPE_PRODUCTION;
return SERVER_TYPE_PRODUCTION; }
} return SERVER_TYPE_PRODUCTION;
}
bool loadMnemonicWordLists()
{ bool loadMnemonicWordLists()
for (int i = 0; i < MNEMONIC_MAX; i++) { {
int iResult = 0; for (int i = 0; i < MNEMONIC_MAX; i++) {
switch (i) { int iResult = 0;
case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER: switch (i) {
iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german, g_mnemonic_german_original_size, g_mnemonic_german_compressed_size); case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER:
if (iResult) { iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german, g_mnemonic_german_original_size, g_mnemonic_german_compressed_size);
printf("[%s] error init german mnemonic set, error nr: %d\n", __FUNCTION__, iResult); if (iResult) {
return false; printf("[%s] error init german mnemonic set, error nr: %d\n", __FUNCTION__, iResult);
} return false;
g_Mnemonic_WordLists[i].printToFile("de_words.txt"); }
break; g_Mnemonic_WordLists[i].printToFile("de_words.txt");
case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES: break;
iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german2, g_mnemonic_german2_original_size, g_mnemonic_german2_compressed_size); case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES:
if (iResult) { iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german2, g_mnemonic_german2_original_size, g_mnemonic_german2_compressed_size);
printf("[%s] error init german mnemonic set 2, error nr: %d\n", __FUNCTION__, iResult); if (iResult) {
return false; printf("[%s] error init german mnemonic set 2, error nr: %d\n", __FUNCTION__, iResult);
} return false;
g_Mnemonic_WordLists[i].printToFile("de_words2.txt"); }
break; g_Mnemonic_WordLists[i].printToFile("de_words2.txt");
case MNEMONIC_BIP0039_SORTED_ORDER: break;
iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_bip0039, g_mnemonic_bip0039_original_size, g_mnemonic_bip0039_compressed_size); case MNEMONIC_BIP0039_SORTED_ORDER:
if (iResult) { iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_bip0039, g_mnemonic_bip0039_original_size, g_mnemonic_bip0039_compressed_size);
printf("[%s] error init bip0039 mnemonic set, error nr: %d\n", __FUNCTION__, iResult); if (iResult) {
return false; printf("[%s] error init bip0039 mnemonic set, error nr: %d\n", __FUNCTION__, iResult);
} return false;
//g_Mnemonic_WordLists[i].printToFile("en_words.txt"); }
break; //g_Mnemonic_WordLists[i].printToFile("en_words.txt");
default: printf("[%s] unknown MnemonicType\n", __FUNCTION__); return false; break;
} default: printf("[%s] unknown MnemonicType\n", __FUNCTION__); return false;
} }
return true; }
} return true;
}
bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg)
{ bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg)
auto serverKey = cfg.getString("crypto.server_key"); {
unsigned char key[crypto_shorthash_KEYBYTES]; auto serverKey = cfg.getString("crypto.server_key");
size_t realBinSize = 0; unsigned char key[crypto_shorthash_KEYBYTES];
NULLPAD_10; size_t realBinSize = 0;
if (sodium_hex2bin(key, crypto_shorthash_KEYBYTES, serverKey.data(), serverKey.size(), nullptr, &realBinSize, nullptr)) { NULLPAD_10;
printf("[%s] serverKey isn't valid hex: %s\n", __FUNCTION__, serverKey.data()); if (sodium_hex2bin(key, crypto_shorthash_KEYBYTES, serverKey.data(), serverKey.size(), nullptr, &realBinSize, nullptr)) {
return false; printf("[%s] serverKey isn't valid hex: %s\n", __FUNCTION__, serverKey.data());
} return false;
if (realBinSize != crypto_shorthash_KEYBYTES) { }
printf("[%s] serverKey hasn't valid size, expecting: %u, get: %lu\n", if (realBinSize != crypto_shorthash_KEYBYTES) {
__FUNCTION__, crypto_shorthash_KEYBYTES, realBinSize); printf("[%s] serverKey hasn't valid size, expecting: %u, get: %lu\n",
return false; __FUNCTION__, crypto_shorthash_KEYBYTES, realBinSize);
} return false;
g_ServerCryptoKey = new ObfusArray(realBinSize, key); }
g_ServerKeySeed = new ObfusArray(9*8); g_ServerCryptoKey = new ObfusArray(realBinSize, key);
Poco::Int64 i1 = randombytes_random(); g_ServerKeySeed = new ObfusArray(9*8);
Poco::Int64 i2 = randombytes_random(); Poco::Int64 i1 = randombytes_random();
g_ServerKeySeed->put(0, i1 | (i2 << 8)); Poco::Int64 i2 = randombytes_random();
g_ServerKeySeed->put(0, i1 | (i2 << 8));
//g_ServerAdminPublic = cfg.getString("crypto.server_admin_public");
//g_ServerAdminPublic = cfg.getString("crypto.server_admin_public");
DISASM_FALSERET;
g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT); DISASM_FALSERET;
g_serverPath = cfg.getString("loginServer.path", ""); g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT);
replaceZeroIPWithLocalhostIP(g_serverPath); g_serverPath = cfg.getString("loginServer.path", "http://localhost/account");
g_default_locale = LanguageManager::languageFromString(cfg.getString("loginServer.default_locale")); replaceZeroIPWithLocalhostIP(g_serverPath);
g_serverPort = cfg.getInt("loginServer.port", 0); g_default_locale = LanguageManager::languageFromString(cfg.getString("loginServer.default_locale"));
g_phpServerPort = cfg.getInt("phpServer.port", 0); g_serverPort = cfg.getInt("loginServer.port", 0);
// replace 0.0.0.0 with actual server ip g_phpServerPort = cfg.getInt("phpServer.port", 0);
// replace 0.0.0.0 with actual server ip
g_php_serverPath = cfg.getString("phpServer.url", "");
replaceZeroIPWithLocalhostIP(g_php_serverPath); g_php_serverPath = cfg.getString("phpServer.url", "");
g_php_serverHost = cfg.getString("phpServer.host", ""); replaceZeroIPWithLocalhostIP(g_php_serverPath);
replaceZeroIPWithLocalhostIP(g_php_serverHost); g_php_serverHost = cfg.getString("phpServer.host", "");
//g_ServerSetupType replaceZeroIPWithLocalhostIP(g_php_serverHost);
auto serverSetupTypeString = cfg.getString("ServerSetupType", ""); //g_ServerSetupType
g_ServerSetupType = getServerSetupTypeFromString(serverSetupTypeString); auto serverSetupTypeString = cfg.getString("ServerSetupType", "");
g_ServerSetupType = getServerSetupTypeFromString(serverSetupTypeString);
// app secret for encrypt user private keys
// TODO: encrypt with server admin key // app secret for encrypt user private keys
auto app_secret_string = cfg.getString("crypto.app_secret", ""); // TODO: encrypt with server admin key
if ("" != app_secret_string) { auto app_secret_string = cfg.getString("crypto.app_secret", "");
g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string); if ("" != app_secret_string) {
} g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string);
//g_CryptoAppSecret }
std::string defaultCheckEmailPath = g_serverPath + "/checkEmail";
g_gRPCRelayServerFullURL = cfg.getString("grpc.server", ""); g_frontend_checkEmailPath = cfg.getString("frontend.checkEmailPath", defaultCheckEmailPath);
//g_CryptoAppSecret
// unsecure flags
//g_AllowUnsecureFlags g_gRPCRelayServerFullURL = cfg.getString("grpc.server", "");
if (cfg.getInt("unsecure.allow_passwort_via_json_request", 0) == 1) {
g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_PASSWORD_REQUESTS); // unsecure flags
} //g_AllowUnsecureFlags
if (cfg.getInt("unsecure.allow_auto_sign_transactions", 0) == 1) { if (cfg.getInt("unsecure.allow_passwort_via_json_request", 0) == 1) {
g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_AUTO_SIGN_TRANSACTIONS); g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_PASSWORD_REQUESTS);
} }
if (cfg.getInt("unsecure.allow_cors_all", 0) == 1) { if (cfg.getInt("unsecure.allow_auto_sign_transactions", 0) == 1) {
g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_CORS_ALL); g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_AUTO_SIGN_TRANSACTIONS);
} }
if (cfg.getInt("unsecure.allow_all_passwords", 0) == 1) { if (cfg.getInt("unsecure.allow_cors_all", 0) == 1) {
g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_ALLOW_ALL_PASSWORDS); g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_CORS_ALL);
} }
if (cfg.getInt("unsecure.allow_all_passwords", 0) == 1) {
return true; g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_ALLOW_ALL_PASSWORDS);
} }
bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg) return true;
{ }
g_disableEmail = cfg.getBool("email.disable", false);
if (g_disableEmail) { bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg)
printf("Email is disabled!\n"); {
} g_disableEmail = cfg.getBool("email.disable", false);
else { if (g_disableEmail) {
g_EmailAccount.sender = cfg.getString("email.sender"); printf("Email is disabled!\n");
g_EmailAccount.username = cfg.getString("email.username"); }
g_EmailAccount.password = cfg.getString("email.password"); else {
g_EmailAccount.url = cfg.getString("email.smtp.url"); g_EmailAccount.sender = cfg.getString("email.sender");
g_EmailAccount.port = cfg.getInt("email.smtp.port"); g_EmailAccount.username = cfg.getString("email.username");
} g_EmailAccount.password = cfg.getString("email.password");
DISASM_FALSERET; g_EmailAccount.url = cfg.getString("email.smtp.url");
//g_ServerKeySeed->put(3, DRRandom::r64()); g_EmailAccount.port = cfg.getInt("email.smtp.port");
return true; }
} DISASM_FALSERET;
//g_ServerKeySeed->put(3, DRRandom::r64());
bool initSSLClientContext() return true;
{ }
SharedPtr<InvalidCertificateHandler> pCert = new RejectCertificateHandler(false); // reject invalid certificates
/* bool initSSLClientContext()
Context(Usage usage, {
const std::string& certificateNameOrPath, SharedPtr<InvalidCertificateHandler> pCert = new RejectCertificateHandler(false); // reject invalid certificates
VerificationMode verMode = VERIFY_RELAXED, /*
int options = OPT_DEFAULTS, Context(Usage usage,
const std::string& certificateStoreName = CERT_STORE_MY); const std::string& certificateNameOrPath,
*/ VerificationMode verMode = VERIFY_RELAXED,
try { int options = OPT_DEFAULTS,
#ifdef POCO_NETSSL_WIN const std::string& certificateStoreName = CERT_STORE_MY);
g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "cacert.pem", Context::VERIFY_RELAXED, Context::OPT_DEFAULTS); */
#else try {
#ifdef POCO_NETSSL_WIN
g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "", "", Poco::Path::config() + "grd_login/cacert.pem", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "cacert.pem", Context::VERIFY_RELAXED, Context::OPT_DEFAULTS);
#endif #else
} catch(Poco::Exception& ex) {
printf("[ServerConfig::initSSLClientContext] error init ssl context, maybe no cacert.pem found?\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n"); g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "", "", Poco::Path::config() + "grd_login/cacert.pem", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
return false; #endif
} } catch(Poco::Exception& ex) {
DISASM_FALSERET; printf("[ServerConfig::initSSLClientContext] error init ssl context, maybe no cacert.pem found?\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n");
SSLManager::instance().initializeClient(0, pCert, g_SSL_CLient_Context); return false;
}
g_ServerKeySeed->put(5, DRRandom::r64()); DISASM_FALSERET;
SSLManager::instance().initializeClient(0, pCert, g_SSL_CLient_Context);
return true;
} g_ServerKeySeed->put(5, DRRandom::r64());
void unload() { return true;
if (g_ServerCryptoKey) { }
delete g_ServerCryptoKey;
} void unload() {
if (g_ServerKeySeed) { if (g_ServerCryptoKey) {
delete g_ServerKeySeed; delete g_ServerCryptoKey;
} }
if (g_CPUScheduler) { if (g_ServerKeySeed) {
delete g_CPUScheduler; delete g_ServerKeySeed;
} }
if (g_CPUScheduler) {
if (g_CryptoCPUScheduler) { delete g_CPUScheduler;
delete g_CryptoCPUScheduler; }
}
if (g_CryptoAppSecret) { if (g_CryptoCPUScheduler) {
MemoryManager::getInstance()->releaseMemory(g_CryptoAppSecret); delete g_CryptoCPUScheduler;
g_CryptoAppSecret = nullptr; }
} if (g_CryptoAppSecret) {
} MemoryManager::getInstance()->releaseMemory(g_CryptoAppSecret);
g_CryptoAppSecret = nullptr;
void writeToFile(std::istream& datas, std::string fileName) }
{ }
static Poco::Mutex mutex;
void writeToFile(std::istream& datas, std::string fileName)
mutex.lock(); {
static Poco::Mutex mutex;
Poco::FileOutputStream file(fileName, std::ios::out | std::ios::app);
mutex.lock();
if (!file.good()) {
printf("[ServerConfig::writeToFile] error creating file with name: %s\n", fileName.data()); Poco::FileOutputStream file(fileName, std::ios::out | std::ios::app);
mutex.unlock();
return; if (!file.good()) {
} printf("[ServerConfig::writeToFile] error creating file with name: %s\n", fileName.data());
mutex.unlock();
Poco::LocalDateTime now; return;
}
std::string dateTimeStr = Poco::DateTimeFormatter::format(now, Poco::DateTimeFormat::ISO8601_FORMAT);
file << dateTimeStr << std::endl; Poco::LocalDateTime now;
for (std::string line; std::getline(datas, line); ) { std::string dateTimeStr = Poco::DateTimeFormatter::format(now, Poco::DateTimeFormat::ISO8601_FORMAT);
file << line << std::endl; file << dateTimeStr << std::endl;
}
file << std::endl; for (std::string line; std::getline(datas, line); ) {
file.close(); file << line << std::endl;
mutex.unlock(); }
} file << std::endl;
file.close();
mutex.unlock();
}
} }

View File

@ -1,90 +1,92 @@
#ifndef __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ #ifndef __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__
#define __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ #define __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__
#include "Crypto/mnemonic.h" #include "Crypto/mnemonic.h"
#include "Crypto/Obfus_array.h" #include "Crypto/Obfus_array.h"
#include "Poco/Util/LayeredConfiguration.h" #include "Poco/Util/LayeredConfiguration.h"
#include "Poco/Net/Context.h" #include "Poco/Net/Context.h"
#include "Poco/Types.h" #include "Poco/Types.h"
#include "Poco/Util/Timer.h" #include "Poco/Util/Timer.h"
#include "tasks/CPUSheduler.h" #include "tasks/CPUSheduler.h"
#include "SingletonManager/LanguageManager.h" #include "SingletonManager/LanguageManager.h"
#include "SingletonManager/MemoryManager.h" #include "SingletonManager/MemoryManager.h"
#define DISABLE_EMAIL #define DISABLE_EMAIL
namespace ServerConfig { namespace ServerConfig {
enum Mnemonic_Types { enum Mnemonic_Types {
MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER, MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER,
MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES, MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES,
MNEMONIC_BIP0039_SORTED_ORDER, MNEMONIC_BIP0039_SORTED_ORDER,
MNEMONIC_MAX MNEMONIC_MAX
}; };
// depracted, moved to email manager // depracted, moved to email manager
struct EmailAccount { struct EmailAccount {
std::string sender; std::string sender;
std::string admin_receiver; std::string admin_receiver;
std::string username; std::string username;
std::string password; std::string password;
std::string url; std::string url;
int port; int port;
}; };
enum ServerSetupType { enum ServerSetupType {
SERVER_TYPE_TEST, SERVER_TYPE_TEST,
SERVER_TYPE_STAGING, SERVER_TYPE_STAGING,
SERVER_TYPE_PRODUCTION SERVER_TYPE_PRODUCTION
}; };
// used with bit-operators, so only use numbers with control exactly one bit (1,2,4,8,16...) // used with bit-operators, so only use numbers with control exactly one bit (1,2,4,8,16...)
enum AllowUnsecure { enum AllowUnsecure {
NOT_UNSECURE = 0, NOT_UNSECURE = 0,
UNSECURE_PASSWORD_REQUESTS = 1, UNSECURE_PASSWORD_REQUESTS = 1,
UNSECURE_AUTO_SIGN_TRANSACTIONS = 2, UNSECURE_AUTO_SIGN_TRANSACTIONS = 2,
UNSECURE_CORS_ALL = 4, UNSECURE_CORS_ALL = 4,
UNSECURE_ALLOW_ALL_PASSWORDS = 8 UNSECURE_ALLOW_ALL_PASSWORDS = 8
}; };
extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
extern ObfusArray* g_ServerCryptoKey; extern ObfusArray* g_ServerCryptoKey;
extern ObfusArray* g_ServerKeySeed; extern ObfusArray* g_ServerKeySeed;
//extern unsigned char g_ServerAdminPublic[]; //extern unsigned char g_ServerAdminPublic[];
extern UniLib::controller::CPUSheduler* g_CPUScheduler; extern UniLib::controller::CPUSheduler* g_CPUScheduler;
extern UniLib::controller::CPUSheduler* g_CryptoCPUScheduler; extern UniLib::controller::CPUSheduler* g_CryptoCPUScheduler;
extern Poco::Net::Context::Ptr g_SSL_CLient_Context; extern Poco::Net::Context::Ptr g_SSL_CLient_Context;
extern Poco::Util::Timer g_CronJobsTimer; extern Poco::Util::Timer g_CronJobsTimer;
extern EmailAccount g_EmailAccount; extern EmailAccount g_EmailAccount;
extern int g_SessionTimeout; extern int g_SessionTimeout;
extern std::string g_serverPath; extern std::string g_serverPath;
extern int g_serverPort; extern int g_serverPort;
extern Languages g_default_locale; extern Languages g_default_locale;
extern std::string g_php_serverPath; extern std::string g_php_serverPath;
extern std::string g_php_serverHost; extern std::string g_php_serverHost;
extern int g_phpServerPort; extern std::string g_frontend_checkEmailPath;
extern Poco::Mutex g_TimeMutex; extern int g_phpServerPort;
extern int g_FakeLoginSleepTime; extern Poco::Mutex g_TimeMutex;
extern std::string g_versionString; extern int g_FakeLoginSleepTime;
extern bool g_disableEmail; extern std::string g_versionString;
extern ServerSetupType g_ServerSetupType; extern bool g_disableEmail;
extern std::string g_gRPCRelayServerFullURL; extern ServerSetupType g_ServerSetupType;
extern MemoryBin* g_CryptoAppSecret; extern std::string g_gRPCRelayServerFullURL;
extern AllowUnsecure g_AllowUnsecureFlags; extern MemoryBin* g_CryptoAppSecret;
extern AllowUnsecure g_AllowUnsecureFlags;
bool loadMnemonicWordLists();
bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg); bool loadMnemonicWordLists();
bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg); bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg);
bool initSSLClientContext(); bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg);
bool initSSLClientContext();
void writeToFile(std::istream& datas, std::string fileName);
void writeToFile(std::istream& datas, std::string fileName);
void unload();
}; void unload();
};
#endif //__GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ #endif //__GRADIDO_LOGIN_SERVER_SERVER_CONFIG__

View File

@ -67,6 +67,24 @@ namespace controller {
return nullptr; return nullptr;
} }
Poco::AutoPtr<EmailVerificationCode> EmailVerificationCode::loadOrCreate(int user_id, model::table::EmailOptInType type)
{
model::table::EmailOptIn db;
std::vector<std::string> fields = { "user_id", "email_opt_in_type_id" };
std::vector<int> field_values = { user_id, (int)type };
auto results = db.loadFromDB<int, model::table::EmailOptInTuple>(fields, field_values);
if (results.size() > 0) {
return Poco::AutoPtr<EmailVerificationCode>(new EmailVerificationCode(new model::table::EmailOptIn(results[0])));
}
else {
auto result = create(user_id, type);
result->getModel()->insertIntoDB(false);
return result;
}
return nullptr;
}
std::vector<Poco::AutoPtr<EmailVerificationCode>> EmailVerificationCode::load(int user_id) std::vector<Poco::AutoPtr<EmailVerificationCode>> EmailVerificationCode::load(int user_id)
{ {
auto db = new model::table::EmailOptIn(); auto db = new model::table::EmailOptIn();
@ -102,8 +120,10 @@ namespace controller {
std::string EmailVerificationCode::getLink() std::string EmailVerificationCode::getLink()
{ {
std::string link = ServerConfig::g_serverPath; std::string link = ServerConfig::g_frontend_checkEmailPath;
link += "/checkEmail/"; if (link.data()[link.size() - 1] != '/') {
link += '/';
}
link += std::to_string(getModel()->getCode()); link += std::to_string(getModel()->getCode());
return link; return link;
} }

View File

@ -14,6 +14,8 @@ namespace controller {
static Poco::AutoPtr<EmailVerificationCode> create(int user_id, model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER); static Poco::AutoPtr<EmailVerificationCode> create(int user_id, model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER);
static Poco::AutoPtr<EmailVerificationCode> create(model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER); static Poco::AutoPtr<EmailVerificationCode> create(model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER);
//! try to load code, create if not exist and save into db
static Poco::AutoPtr<EmailVerificationCode> loadOrCreate(int user_id, model::table::EmailOptInType type);
static Poco::AutoPtr<EmailVerificationCode> load(const Poco::UInt64& code); static Poco::AutoPtr<EmailVerificationCode> load(const Poco::UInt64& code);
static std::vector<Poco::AutoPtr<EmailVerificationCode>> load(int user_id); static std::vector<Poco::AutoPtr<EmailVerificationCode>> load(int user_id);

View File

@ -130,6 +130,16 @@ Gradido Login-Server\n\
: mUser(user), mType(type) : mUser(user), mType(type)
{ {
}
Email::Email(
AutoPtr<controller::EmailVerificationCode> emailVerification,
AutoPtr<controller::User> user,
const std::string& emailCustomText,
const std::string& customSubject
)
: mEmailVerificationCode(emailVerification), mUser(user), mType(EMAIL_CUSTOM_TEXT), mCustomText(emailCustomText), mCustomSubject(customSubject)
{
} }
Email::~Email() Email::~Email()
@ -177,6 +187,7 @@ Gradido Login-Server\n\
case EMAIL_USER_REGISTER_OLD_ELOPAGE: case EMAIL_USER_REGISTER_OLD_ELOPAGE:
case EMAIL_ADMIN_USER_VERIFICATION_CODE: case EMAIL_ADMIN_USER_VERIFICATION_CODE:
case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND: case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND:
case EMAIL_CUSTOM_TEXT:
if (userTableModel.isNull() || mUser->getModel()->getEmail() == "") { if (userTableModel.isNull() || mUser->getModel()->getEmail() == "") {
addError(new Error(functionName, "no receiver email set for user email verification email")); addError(new Error(functionName, "no receiver email set for user email verification email"));
return false; return false;
@ -204,14 +215,19 @@ Gradido Login-Server\n\
else if (mType == EMAIL_USER_REGISTER_OLD_ELOPAGE) { else if (mType == EMAIL_USER_REGISTER_OLD_ELOPAGE) {
messageTemplate = EmailText_emailVerificationOldElopageTransaction; messageTemplate = EmailText_emailVerificationOldElopageTransaction;
} }
else if (mType == EMAIL_CUSTOM_TEXT) {
messageTemplate = mCustomText.data();
mailMessage->setSubject(mCustomSubject);
}
content_string = replaceUserNamesAndLink( content_string = replaceUserNamesAndLink(
langCatalog->gettext(messageTemplate), langCatalog->gettext(messageTemplate),
userTableModel->getFirstName(), userTableModel->getFirstName(),
userTableModel->getLastName(), userTableModel->getLastName(),
mEmailVerificationCode->getLink() mEmailVerificationCode->getLink(),
mEmailVerificationCode->getModel()->getCode()
); );
if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType) { if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType || EMAIL_CUSTOM_TEXT == mType) {
content_string = replaceDuration(content_string, mEmailVerificationCode->getAge(), langCatalog); content_string = replaceDuration(content_string, mEmailVerificationCode->getAge(), langCatalog);
} }
mailMessage->addContent(new Poco::Net::StringPartSource(content_string, mt.toString())); mailMessage->addContent(new Poco::Net::StringPartSource(content_string, mt.toString()));
@ -234,7 +250,8 @@ Gradido Login-Server\n\
langCatalog->gettext(EmailText_emailResetPassword), langCatalog->gettext(EmailText_emailResetPassword),
userTableModel->getFirstName(), userTableModel->getFirstName(),
userTableModel->getLastName(), userTableModel->getLastName(),
mEmailVerificationCode->getLink() mEmailVerificationCode->getLink(),
mEmailVerificationCode->getModel()->getCode()
), mt.toString()) ), mt.toString())
); );
break; break;
@ -264,8 +281,13 @@ Gradido Login-Server\n\
return true; return true;
} }
std::string Email::replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link) std::string Email::replaceUserNamesAndLink(
{ const char* src,
const std::string& first_name,
const std::string& last_name,
const std::string& link,
Poco::UInt64 code
) {
std::string result = src; std::string result = src;
int findCursor = 0; int findCursor = 0;
static const char* functionName = "Email::replaceUserNamesAndLink"; static const char* functionName = "Email::replaceUserNamesAndLink";
@ -296,6 +318,12 @@ Gradido Login-Server\n\
else { else {
//addError(new Error(functionName, "no email placeholder found")); //addError(new Error(functionName, "no email placeholder found"));
} }
findPos = result.find("[code]", findCursor);
if (findPos != result.npos) {
auto code_string = std::to_string(code);
findCursor = findPos + code_string.size();
result.replace(findPos, 6, code_string);
}
return result; return result;
} }
@ -376,12 +404,38 @@ Gradido Login-Server\n\
case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND: return "email admin user verification code resend"; case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND: return "email admin user verification code resend";
case EMAIL_USER_RESET_PASSWORD: return "user reset Password"; case EMAIL_USER_RESET_PASSWORD: return "user reset Password";
case EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE: return "user reset password without memorized passphrase"; case EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE: return "user reset password without memorized passphrase";
case EMAIL_NOTIFICATION_TRANSACTION_CREATION: return "email notification transaction creation";
case EMAIL_NOTIFICATION_TRANSACTION_TRANSFER: return "email notification transaction transfer";
case EMAIL_USER_REGISTER_OLD_ELOPAGE: return "user register automatic throw elopage"; case EMAIL_USER_REGISTER_OLD_ELOPAGE: return "user register automatic throw elopage";
case EMAIL_CUSTOM_TEXT: return "email custom text";
case EMAIL_MAX: return "<last entry, invalid>"; case EMAIL_MAX: return "<last entry, invalid>";
} }
return "<unknown>"; return "<unknown>";
} }
EmailType Email::emailType(const std::string& emailTypeString)
{
if ("email user verification code" == emailTypeString) {
return EMAIL_USER_VERIFICATION_CODE;
}
else if ("email user verification code resend" == emailTypeString) {
return EMAIL_USER_VERIFICATION_CODE_RESEND;
}
else if ("email user verification code resend after long time" == emailTypeString) {
return EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME;
}
else if ("email admin user verification code") {
return EMAIL_ADMIN_USER_VERIFICATION_CODE;
}
else if ("email admin user verification code resend") {
return EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND;
}
else if ("user reset Password") {
return EMAIL_USER_RESET_PASSWORD;
}
else if ("email custom text") {
return EMAIL_CUSTOM_TEXT;
}
else {
return EMAIL_ERROR;
}
}
} }

View File

@ -22,21 +22,20 @@
namespace model { namespace model {
using namespace Poco; using namespace Poco;
enum EmailType enum EmailType
{ {
EMAIL_DEFAULT, EMAIL_DEFAULT = 0,
EMAIL_ERROR, EMAIL_ERROR = 1,
EMAIL_USER_VERIFICATION_CODE, EMAIL_USER_VERIFICATION_CODE = 2,
EMAIL_USER_VERIFICATION_CODE_RESEND, EMAIL_USER_VERIFICATION_CODE_RESEND = 3,
EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME, EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME = 4,
EMAIL_ADMIN_USER_VERIFICATION_CODE, EMAIL_ADMIN_USER_VERIFICATION_CODE = 5,
EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND, EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND = 6,
EMAIL_USER_RESET_PASSWORD, EMAIL_USER_RESET_PASSWORD = 7,
EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE, EMAIL_CUSTOM_TEXT = 8,
EMAIL_NOTIFICATION_TRANSACTION_CREATION, EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE = 9,
EMAIL_NOTIFICATION_TRANSACTION_TRANSFER, EMAIL_USER_REGISTER_OLD_ELOPAGE = 10,
EMAIL_USER_REGISTER_OLD_ELOPAGE, EMAIL_MAX = 11
EMAIL_MAX
}; };
class Email: public ErrorList class Email: public ErrorList
@ -44,6 +43,7 @@ namespace model {
public: public:
Email(AutoPtr<controller::EmailVerificationCode> emailVerification, AutoPtr<controller::User> user, EmailType type); Email(AutoPtr<controller::EmailVerificationCode> emailVerification, AutoPtr<controller::User> user, EmailType type);
Email(AutoPtr<controller::User> user, EmailType type); Email(AutoPtr<controller::User> user, EmailType type);
Email(AutoPtr<controller::EmailVerificationCode> emailVerification, AutoPtr<controller::User> user, const std::string& emailCustomText, const std::string& customSubject);
//! \param errors copy errors into own memory //! \param errors copy errors into own memory
Email(const std::string& errorHtml, EmailType type); Email(const std::string& errorHtml, EmailType type);
~Email(); ~Email();
@ -51,6 +51,7 @@ namespace model {
static EmailType convertTypeFromInt(int type); static EmailType convertTypeFromInt(int type);
inline EmailType getType() { return mType; } inline EmailType getType() { return mType; }
static const char* emailTypeString(EmailType type); static const char* emailTypeString(EmailType type);
static EmailType emailType(const std::string& emailTypeString);
inline controller::User* getUser() { if (!mUser.isNull()) return mUser.get(); return nullptr; } inline controller::User* getUser() { if (!mUser.isNull()) return mUser.get(); return nullptr; }
virtual bool draft(Net::MailMessage* mailMessage, LanguageCatalog* langCatalog); virtual bool draft(Net::MailMessage* mailMessage, LanguageCatalog* langCatalog);
@ -58,7 +59,7 @@ namespace model {
protected: protected:
std::string replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link); std::string replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link, Poco::UInt64 code);
std::string replaceEmail(const char* src, const std::string& email); std::string replaceEmail(const char* src, const std::string& email);
std::string replaceAmount(const char* src, Poco::Int64 gradido_cent); std::string replaceAmount(const char* src, Poco::Int64 gradido_cent);
std::string replaceDuration(std::string src, Poco::Timespan duration, LanguageCatalog* lang); std::string replaceDuration(std::string src, Poco::Timespan duration, LanguageCatalog* lang);
@ -69,7 +70,9 @@ namespace model {
EmailType mType; EmailType mType;
std::queue<Poco::Net::StringPartSource*> mAdditionalStringPartSrcs; std::queue<Poco::Net::StringPartSource*> mAdditionalStringPartSrcs;
std::string mCustomText;
std::string mCustomSubject;
}; };
} }
#endif //GRADIDO_LOGIN_SERVER_MODEL_EMAIL_INCLUDE #endif //GRADIDO_LOGIN_SERVER_MODEL_EMAIL_INCLUDE

View File

@ -172,6 +172,19 @@ namespace model {
default: return "<unknown>"; default: return "<unknown>";
} }
} }
EmailOptInType EmailOptIn::stringToType(const std::string& typeString)
{
if (typeString == "register") {
return EMAIL_OPT_IN_REGISTER;
}
else if (typeString == "resetPassword") {
return EMAIL_OPT_IN_RESET_PASSWORD;
}
else if (typeString == "registerDirect") {
return EMAIL_OPT_IN_REGISTER_DIRECT;
}
return EMAIL_OPT_IN_EMPTY;
}
} }
} }

View File

@ -44,6 +44,7 @@ namespace model {
size_t addResendCountAndUpdate(); size_t addResendCountAndUpdate();
static const char* typeToString(EmailOptInType type); static const char* typeToString(EmailOptInType type);
static EmailOptInType stringToType(const std::string& typeString);
protected: protected:
Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName);
Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session);