// // Created by imper on 2/14/22. // #ifndef PRIVACY_PROTECTION_MESSENGER_MESSENGER_HPP # define PRIVACY_PROTECTION_MESSENGER_MESSENGER_HPP # include # include # include # include # include # include # include # include # include # include # include # include "constants.hpp" # define CONFIG_FILE CONFIG_DIR "/config.lua" # define LUA_REGISTER_USER_FUNC "permit_register_user" # define LUA_SET_PASSWORD_FUNC "permit_set_password" # define LUA_SET_DISPLAY_NAME_FUNC "permit_set_display_name" # define LUA_GET_DISPLAY_NAME_FUNC "permit_get_display_name" # define LUA_BEGIN_SESSION_FUNC "permit_begin_session" # define LUA_GET_PUBKEY_FUNC "permit_get_pubkey" # define LUA_SEND_MESSAGE_FUNC "permit_send_message" # define LUA_CHECK_ONLINE_STATUS_FUNC "permit_check_online_status" # define LUA_FIND_USERS_BY_DISPLAY_NAME_FUNC "permit_find_users_by_display_name" # define LUA_FIND_USERS_BY_LOGIN_FUNC "permit_find_users_by_login" # define E_DERANGED "Server is deranged. This is a bug report it!" # define E_SUCCESS "Success." # define E_USER_ALREADY_EXISTS "This user already exists." # define E_INCORRECT_LOGIN "Incorrect login." # define E_INCORRECT_PASSWORD "Incorrect password." # define E_TOO_LONG_LOGIN "Too long login string." # define E_TOO_LONG_PASSWORD "Too long password string." # define E_TOO_SHORT_PASSWORD "Too short password." # define E_TOO_LONG_DISPLAY_NAME "Too long display name." # define E_USER_NOT_FOUND "User not found." # define E_MESSAGE_NOT_FOUND "Message not found." # define E_NO_PERMISSION "No permission." #define HANDLE_ERRORS_ON_CLIENT case HEADER::e_incorrect_login: \ { \ status = E_INCORRECT_LOGIN; \ return false; \ } \ case HEADER::e_incorrect_password: \ { \ status = E_INCORRECT_PASSWORD; \ return false; \ } \ case HEADER::e_too_long_login: \ { \ status = E_TOO_LONG_LOGIN; \ return false; \ } \ case HEADER::e_too_long_password: \ { \ status = E_TOO_LONG_PASSWORD; \ return false; \ } \ case HEADER::e_too_short_password: \ { \ status = E_TOO_SHORT_PASSWORD; \ return false; \ } \ case HEADER::e_too_long_display_name: \ { \ status = E_TOO_LONG_DISPLAY_NAME; \ return false; \ } \ case HEADER::e_no_permission: \ { \ status = E_NO_PERMISSION; \ return false; \ } \ case HEADER::e_user_already_exists: \ { \ status = E_USER_ALREADY_EXISTS; \ return false; \ } \ case HEADER::e_user_not_found: \ { \ status = E_USER_NOT_FOUND; \ return false; \ } \ case HEADER::e_message_not_found: \ { \ status = E_MESSAGE_NOT_FOUND; \ return false; \ } \ default: \ { \ LOG << E_DERANGED "\n" << ENDENTLN; \ status = E_DERANGED; \ return false; \ } # define SUCCESS 0 # undef LOG # undef ERR # define LOG (inet::__detail__::_log_ << PRINT_PREFIX) # define ERR (inet::__detail__::_err_ << PRINT_PREFIX) namespace msg { static bool verbose = false; namespace __detail__ __attribute__((visibility("hidden"))) { static const unsigned char cov_2_char[64] = { /* from crypto/des/fcrypt.c */ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A }; static const char ascii_dollar[] = {0x24, 0x00}; typedef enum : int { passwd_unset = 0, passwd_md_5, passwd_apr_1, passwd_sha_256, passwd_sha_512, passwd_aix_md_5 } passwd_modes; inline static int random_bytes(char** data, int size); inline static char* md_5_crypt(const char* passwd, const char* magic, const char* salt); inline static char* sha_crypt(const char* passwd, const char* magic, const char* salt); inline static bool contains(const char* str, const char* substr); } struct HEADER { enum signal : int { s_zero = 0, s_register_user, s_set_password, s_set_display_name, s_get_display_name, s_begin_session, s_end_session, s_get_pubkey, s_send_message, s_query_incoming, s_check_online_status, s_find_users_by_display_name, s_find_users_by_login }; signal sig = s_zero; inline static const char* signal_to_name(signal sig) { switch (sig) { CASE_TO_STR(s_register_user) CASE_TO_STR(s_set_password) CASE_TO_STR(s_set_display_name) CASE_TO_STR(s_get_display_name) CASE_TO_STR(s_begin_session) CASE_TO_STR(s_end_session) CASE_TO_STR(s_get_pubkey) CASE_TO_STR(s_send_message) CASE_TO_STR(s_query_incoming) CASE_TO_STR(s_check_online_status) CASE_TO_STR(s_find_users_by_display_name) CASE_TO_STR(s_find_users_by_login) default: return _STR(s_zero); } } inline static signal signal_from_name(const std::string& name) { if (name == _STR(s_register_user)) return s_register_user; else if (name == _STR(s_set_password)) return s_set_password; else if (name == _STR(s_set_display_name)) return s_set_display_name; else if (name == _STR(s_get_display_name)) return s_get_display_name; else if (name == _STR(s_begin_session)) return s_begin_session; else if (name == _STR(s_end_session)) return s_end_session; else if (name == _STR(s_get_pubkey)) return s_get_pubkey; else if (name == _STR(s_send_message)) return s_send_message; else if (name == _STR(s_query_incoming)) return s_query_incoming; else if (name == _STR(s_check_online_status)) return s_check_online_status; else if (name == _STR(s_find_users_by_display_name)) return s_find_users_by_display_name; else if (name == _STR(s_find_users_by_login)) return s_find_users_by_login; else return s_zero; } size_t login_size = 0; size_t password_size = 0; size_t display_name_size = 0; size_t data_size = 0; enum error : int { e_no_permission = 0, e_success, e_user_already_exists, e_incorrect_login, e_incorrect_password, e_too_long_login, e_too_long_password, e_too_short_password, e_too_long_display_name, e_user_not_found, e_message_not_found }; error err = e_no_permission; }; struct MESSAGE { std::string* source = nullptr; std::string* destination = nullptr; std::vector* data = nullptr; size_t source_size = 0; size_t destination_size = 0; size_t data_size = 0; MESSAGE() = default; MESSAGE(const MESSAGE& msg) : source(msg.source ? new std::remove_pointer_t(*msg.source) : nullptr), destination(msg.destination ? new std::remove_pointer_t(*msg.destination) : nullptr), data(msg.data ? new std::remove_pointer_t(*msg.data) : nullptr), source_size(msg.source->size()), destination_size(msg.destination->size()), data_size(msg.data->size()) { } ~MESSAGE() { delete source; delete destination; delete data; } }; class messenger_io : public inet::inet_io { public: explicit messenger_io(const inet::inet_io& io) : inet::inet_io(io) { } inline bool read(HEADER& header) { return read(&header, sizeof header) == sizeof header; } inline bool read(MESSAGE& message) { if (read(&message, sizeof message) == sizeof message && message.data_size > 0) { if (message.source_size > 0) { message.source = new std::string(message.source_size, 0); if (read(message.source->data(), message.source_size) != message.source_size) return false; } if (message.destination_size) { message.destination = new std::string(message.destination_size, 0); if (read(message.destination->data(), message.destination_size) != message.destination_size) return false; } message.data = new std::vector(message.data_size, 0); return read(message.data->data(), message.data_size) == message.data_size; } return false; } template