diff --git a/.gitignore b/.gitignore index 15361cf..da45b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* + +# VSCode +/.vscode diff --git a/MRCI.pro b/MRCI.pro index 40b5f24..7b33264 100644 --- a/MRCI.pro +++ b/MRCI.pro @@ -60,7 +60,6 @@ SOURCES += src/main.cpp \ src/commands/mods.cpp \ src/commands/info.cpp \ src/commands/cast.cpp \ - src/commands/bans.cpp \ src/commands/admin.cpp \ src/commands/auth.cpp \ src/commands/acct_recovery.cpp \ @@ -88,7 +87,6 @@ HEADERS += \ src/commands/mods.h \ src/commands/info.h \ src/commands/cast.h \ - src/commands/bans.h \ src/commands/admin.h \ src/commands/auth.h \ src/commands/acct_recovery.h \ diff --git a/cmd_docs.qrc b/cmd_docs.qrc index 85ddeda..c78c0b4 100644 --- a/cmd_docs.qrc +++ b/cmd_docs.qrc @@ -2,7 +2,6 @@ docs/intern_commands/accept_ch.md docs/intern_commands/add_acct.md - docs/intern_commands/add_ban.md docs/intern_commands/add_cert.md docs/intern_commands/add_ch.md docs/intern_commands/add_mod.md @@ -34,7 +33,6 @@ docs/intern_commands/lock_acct.md docs/intern_commands/ls_act_log.md docs/intern_commands/ls_auth_log.md - docs/intern_commands/ls_bans.md docs/intern_commands/ls_certs.md docs/intern_commands/ls_ch_members.md docs/intern_commands/ls_chs.md @@ -62,7 +60,6 @@ docs/intern_commands/request_pw_reset.md docs/intern_commands/restart_host.md docs/intern_commands/rm_acct.md - docs/intern_commands/rm_ban.md docs/intern_commands/rm_cert.md docs/intern_commands/rm_ch.md docs/intern_commands/rm_mod.md diff --git a/docs/README.md b/docs/README.md index d6334c0..5d884eb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,7 @@ Usage: mrci -status : display status information about the host instance if it is currently running. -reset_root : reset the root account password to the default password. -host : start a new host instance. (this blocks). + -default_pw : show the default password. -public_cmds : run the internal module to list it's public commands. for internal use only. -exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only. -user_cmds : run the internal module to list it's user commands. for internal use only. @@ -30,7 +31,7 @@ Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |: The host can only be managed via a connected client that supports text input/output so the host application is always listening for clients while running entirely in the background. By default the host listen for clients on address 0.0.0.0 and port 35516, effectively making it reachable on any network interface of the host platform via that specific port. -Just like any linux based OS, the host will have an administrative user called root. This account can be used to modify anything on the host without restriction. The default password is randomized and set on the root user account upon running the host for the first time. To find out what the default password is, run -help or -about. When logging in as root with the default password, the host will require you to change the password before continuing. +Any one user account registered with the host can be given root privileges which basically gives this user unrestricted access to anything in the host for administrative purposes. When a host instance is created for the first time, it will create a new user account called 'root' with a randomized default password. To find out what the default password is, run -default_pw. When logging in for the fist time, the host will require you to change the user name and password before continuing. ### More Than Just a Command Interpreter ### diff --git a/docs/async.md b/docs/async.md index c43e19f..4776ddf 100644 --- a/docs/async.md +++ b/docs/async.md @@ -2,7 +2,7 @@ An async command is a virtual command that the host can use to send data to the client at any time while connected to the host. As the name implies, the occurance of a client receiving data from an async command is not always the result of running a regular command in the current session. This can occur for example when information in your account is changed by another client connected to the host; your client would not know about this change until an async command is sent notify it of the change. These commands can be called directly or indirectly by a module and are considered "virtual" commands because there is no defined objects attached to them. Instead, async commands are best identified by command id values 1-255. -Async commands are not only used to send data to the client but also used internally within the host to help objects operating in different processes to communicate with each other. Some async commands in fact are considered internal only because the client should never see any data come from them at anytime. There is also data flow contriants for aysnc commands, meaning some gets blocked if sent from the module or has no effect if sent with the unexpected [IPC](type_ids.md) type id. The list below shows the various data flow contriants each of these async commands have. +Async commands are not only used to send data to the client but also used internally within the host to help objects operating in different processes to communicate with each other. Some async commands in fact are considered internal only because the client should never see any data come from them at anytime. There is also data flow contriants for async commands, meaning some gets blocked if sent from the module or has no effect if sent with the unexpected [IPC](type_ids.md) type id. The list below shows the various data flow contriants each of these async commands have. Here is a describtion of what the keywords in the list mean: ``` @@ -74,7 +74,6 @@ enum AsyncCommands : quint16 ASYNC_PING_PEERS = 38, // internal | private ASYNC_OPEN_SUBCH = 39, // internal | private ASYNC_CLOSE_SUBCH = 40, // internal | private - ASYNC_UPDATE_BANS = 41, // internal | private ASYNC_KEEP_ALIVE = 42, // internal | private ASYNC_SET_DIR = 43, // internal | private ASYNC_DEBUG_TEXT = 44 // internal | private @@ -289,9 +288,6 @@ format: [8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)] ```ASYNC_CLOSE_SUBCH (40)``` This is the other half to ASYNC_OPEN_SUBCH that tells the session to close the requested sub-channel. -```ASYNC_UPDATE_BANS (41)``` -This internal only async command doesn't carry any data. It can be use by modules to tell the TCPServer object to update it's ip ban list cache from the database. This generally only needs to be used if the ip ban list in the database has changed in anyway. - ```ASYNC_KEEP_ALIVE (42)``` This internal only async command doesn't carry any data. The session object normally sends a [KILL_CMD](type_ids.md) to the module when it detects that the module process has not sent an IPC frame in 2 minutes to terminate the module process. If desired, the module can send this async command in regular intervals to reset this 2 minute idle timer to prevent auto termination. diff --git a/docs/intern_commands.md b/docs/intern_commands.md index bcb57fe..f1dcd3f 100644 --- a/docs/intern_commands.md +++ b/docs/intern_commands.md @@ -6,8 +6,6 @@ The host is extendable via 3rd party modules but the host itself is an internal * [add_acct](intern_commands/add_acct.md) - create a new host user account. -* [add_ban](intern_commands/add_ban.md) - add an ip address to the host ban list. - * [add_cert](intern_commands/add_cert.md) - install a new SSL/TLS cert into the host. * [add_ch](intern_commands/add_ch.md) - create a new channel. @@ -72,8 +70,6 @@ The host is extendable via 3rd party modules but the host itself is an internal * [ls_auth_log](intern_commands/ls_auth_log.md) - display the host authorization activity log. -* [ls_bans](intern_commands/ls_bans.md) - display or manage the host ip address ban table. - * [ls_certs](intern_commands/ls_certs.md) - display a list of all SSL/TLS certificates installed in the host database. * [ls_ch_members](intern_commands/ls_ch_members.md) - list all members in a channel. @@ -128,8 +124,6 @@ The host is extendable via 3rd party modules but the host itself is an internal * [rm_acct](intern_commands/rm_acct.md) - delete a user account from the host database. -* [rm_ban](intern_commands/rm_ban.md) - remove an ip address from the ban list. - * [rm_cert](intern_commands/rm_cert.md) - remove the SSL/TLS cert associated with the given common name. * [rm_ch](intern_commands/rm_ch.md) - permanently remove a channel and all of it's sub-shannels from the host. diff --git a/docs/intern_commands/add_acct.md b/docs/intern_commands/add_acct.md index 24a33c0..54b39bf 100644 --- a/docs/intern_commands/add_acct.md +++ b/docs/intern_commands/add_acct.md @@ -8,4 +8,8 @@ create a new host user account. ### Description ### -this creates a new user account with the user name given in -name and an email address used for account recovery in -email. the command will fail if the user name or email address already exists. you can pass the optional -disp to set the display name for the new user account. the display name can be used by clients to present the user account to other clients without showing the true user name or make it easier for users to identify each other since the display name is not restricted by uniqueness. the display name can be anything; it's only restricted to 32 chars or less but it cannot contain new lines or lines breaks. \ No newline at end of file +this creates a new user account with the user name given in -name and an email address used for account recovery in -email. the command will fail if the user name or email address already exists. you can pass the optional -disp to set the display name for the new user account. + +the command will ask for a new password during execution. avoid using a password that contains the user name, email address or display name; the command will actively block this. also aviod using a user name that is formatted like a email address since this would cause undesired behaviour in 3rd party client applications. setting the user name as 'root' is forbidden. + +the display name can be used by clients to present the user account to other clients without showing the true user name or make it easier for users to identify each other since the display name is not restricted by uniqueness. the display name can be anything; it's only restricted to 32 chars or less but it cannot contain new lines or lines breaks. \ No newline at end of file diff --git a/docs/intern_commands/add_ban.md b/docs/intern_commands/add_ban.md deleted file mode 100644 index 59fb524..0000000 --- a/docs/intern_commands/add_ban.md +++ /dev/null @@ -1,11 +0,0 @@ -### Summary ### - -add an ip address to the host ban list. - -### IO ### - -```[-ip (text)]/[text]``` - -### Description ### - -add an ip address or its integer representative given in -ip to the host ban list that will prevent any client from connecting to the host with that ip address. \ No newline at end of file diff --git a/docs/intern_commands/auth.md b/docs/intern_commands/auth.md index b47c212..5c5d537 100644 --- a/docs/intern_commands/auth.md +++ b/docs/intern_commands/auth.md @@ -8,4 +8,4 @@ login to the host using a registered user account name or email address. ### Description ### -login into a user account name given in -user or email address given in -email. this command will ask for the password during execution to complete the authentication. \ No newline at end of file +login into a user account name given in -user or email address given in -email. this command will ask for the password during execution to complete the authentication. this command will also honor any request to change the password or user name before completing the authentication. \ No newline at end of file diff --git a/docs/intern_commands/ls_bans.md b/docs/intern_commands/ls_bans.md deleted file mode 100644 index 92856f3..0000000 --- a/docs/intern_commands/ls_bans.md +++ /dev/null @@ -1,16 +0,0 @@ -### Summary ### - -display or manage the host ip address ban table. - -### IO ### - -```[{search_terms} {-delete}]/[text]``` - -### Description ### - -by default, all entries in the table are displayed in 50 entries per page. you can pass the column names as -column_name (text) to refine your search to specific entries. this command can handle the following columns: - --time_stamp --ip_address - -you can also pass -delete that will cause the command to delete the entries instead of displaying them. note: passing no search terms with this option will delete all entries in the table. keep in mind, the host use this table to enforce the ban-by-ip option. deleting entries in this table will un-ban the ip's affected by the deletion. \ No newline at end of file diff --git a/docs/intern_commands/rm_ban.md b/docs/intern_commands/rm_ban.md deleted file mode 100644 index e533c78..0000000 --- a/docs/intern_commands/rm_ban.md +++ /dev/null @@ -1,11 +0,0 @@ -### Summary ### - -remove an ip address from the ban list. - -### IO ### - -```[-ip (text)]/[text]``` - -### Description ### - -this removes an ip address from the host ban list. nothing happens if the ip does not exists in the list. \ No newline at end of file diff --git a/docs/intern_commands/set_pw.md b/docs/intern_commands/set_pw.md index 87679d9..7bb9685 100644 --- a/docs/intern_commands/set_pw.md +++ b/docs/intern_commands/set_pw.md @@ -8,4 +8,4 @@ update your account password. ### Description ### -this changes the password on your own account. during execution, this command will ask for a new password to be entered. \ No newline at end of file +this changes the password on your own account. the command will ask for a new password during execution. avoid using a password that contains the user name, email address or display name; the command will actively block this. \ No newline at end of file diff --git a/docs/modules.md b/docs/modules.md index 565285d..b1afa0e 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -2,7 +2,15 @@ Modules in this project are independent applications that communicate with the host application's session objects via named pipes and/or shared memory segments. The host will call multiple instances of these modules if needed using the command line options described in section 2.3 depending on session activity. The format for data transport between the session and module via the named pipe is a modified version of the MRCI frame described in section 2.2 called the IPC frame. -Basically the module's main job is to input and output IPC frames with the session object with the option to read session data from shared memory. +Basically the module's main job is to input and output IPC frames with the session object with the option to read session data from shared memory. The MRCI host have internal commands that are loaded using the module interface so the MRCI host project itself is a good example of a module. See the following classes and source files to understand how the internal module works and to understand how to make an external module based on it. + +``` +int main() - main.cpp +class Module - module.h, module.cpp +class MemShare - mem_share.h, mem_share.cpp +class CmdObject - cmd_object.h, cmd_object.cpp +class IPCWorker - cmd_object.h, cmd_object.cpp +``` ### 2.2 IPC Frame ### diff --git a/docs/type_ids.md b/docs/type_ids.md index ad1376b..3ab4f99 100644 --- a/docs/type_ids.md +++ b/docs/type_ids.md @@ -77,7 +77,27 @@ This id can be treated exactly like TEXT except this should tell the client to h Also formatted exactly like TEXT but this indicates to the client that this is a large body of text that is recommended to be word wrapped when displaying to the user. It can contain line breaks so clients are also recommended to honor those line breaks. ```IDLE``` -This doesn't carry any actual data, instead this indicates that the command id and branch id that sent it has finished it's task. Modules that send this doesn't need to terminate it's process. +All commands started during the session returns this type id when it has finished it's task. by default, it carries a 16bit unsigned integer indicating the result of the task that the command was running. + +``` +enum RetCode : quint16 +{ + NO_ERRORS = 1, // task execution completed without any issues. + ABORTED = 2, // the task aborted via user or host intervention. + INVALID_PARAMS = 3, // invalid/missing parameters prevented the task from executing. + CRASH = 4, // the command process has crashed. + FAILED_TO_START = 5, // the command process could not start. + EXECUTION_FAIL = 6, // command specific error prevented execution of the task. + CUSTOM = 7 // indicates a custom return code. +}; + +notes: +1. the custom return code can be additional data added to the end of the 16bit + integer that can carry additional data about the result of the task. it can + be any format that the module itself decides it should be. nothing is + stopping modules from defining return codes beyond the value of 7 but it is + advised not to because this enum might be expanded in the future. +``` ```KILL_CMD``` This doesn't carry any actual data, instead can be sent by the client or session object to tell the command-branch id sent in the frame to terminate the module process. Modules that receive this need to send a IDLE frame if a command is still running and then terminate itself. The module will have 3 seconds to do this before it is force killed by the session. diff --git a/linux_build.sh b/linux_build.sh index 509192b..8395609 100644 --- a/linux_build.sh +++ b/linux_build.sh @@ -5,7 +5,7 @@ installer_file="$2" src_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" bin_name="mrci" -app_version="2.1.3" +app_version="2.2.3" app_name="MRCI" install_dir="/opt/$bin_name" var_dir="/var/opt/$bin_name" diff --git a/modules/Tester/Tester.pro b/modules/Tester/Tester.pro deleted file mode 100644 index f380b4a..0000000 --- a/modules/Tester/Tester.pro +++ /dev/null @@ -1,36 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-06-26T15:36:12 -# -# This file is part of MRCI. -# -# MRCI is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# MRCI is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with MRCI under the LICENSE.md file. If not, see -# . -# -#------------------------------------------------- - -QT -= gui - -TARGET = ModTester -TEMPLATE = lib - -DEFINES += MOD_TESTER - -SOURCES += \ - command.cpp \ - main.cpp - -HEADERS += \ - command.h \ - main.h diff --git a/modules/Tester/command.cpp b/modules/Tester/command.cpp deleted file mode 100644 index aec6ebc..0000000 --- a/modules/Tester/command.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "command.h" - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -SharedObjs::SharedObjs(QObject *parent) : QObject(parent) -{ - p2pAccepted = nullptr; - p2pPending = nullptr; - chIds = nullptr; - wrAbleChIds = nullptr; - chList = nullptr; - activeUpdate = nullptr; - chOwnerOverride = nullptr; - sessionAddr = nullptr; - userName = nullptr; - groupName = nullptr; - displayName = nullptr; - appName = nullptr; - clientMajor = nullptr; - clientMinor = nullptr; - clientPatch = nullptr; - sessionId = nullptr; - userId = nullptr; - moreInputCmds = nullptr; - activeLoopCmds = nullptr; - pausedCmds = nullptr; - hostRank = nullptr; - cmdNames = nullptr; -} - -bool ExternCommand::errState() -{ - return errSent; -} - -void ExternCommand::mainTxt(const QString &txt) -{ - emit dataToClient(QTextCodec::codecForName(TXT_CODEC)->fromUnicode(txt).mid(2), TEXT); -} - -void ExternCommand::errTxt(const QString &txt) -{ - errSent = true; - - emit dataToClient(QTextCodec::codecForName(TXT_CODEC)->fromUnicode(txt).mid(2), ERR); -} - -void ExternCommand::privTxt(const QString &txt) -{ - emit dataToClient(QTextCodec::codecForName(TXT_CODEC)->fromUnicode(txt).mid(2), PRIV_TEXT); -} - -void ExternCommand::bigTxt(const QString &txt) -{ - emit dataToClient(QTextCodec::codecForName(TXT_CODEC)->fromUnicode(txt).mid(2), BIG_TEXT); -} diff --git a/modules/Tester/command.h b/modules/Tester/command.h deleted file mode 100644 index d6953ec..0000000 --- a/modules/Tester/command.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef EXTERN_COMMAND_H -#define EXTERN_COMMAND_H - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -#define TXT_CODEC "UTF-16LE" -#define TXT_CODEC_BITS 16 -#define MOD_LOADER_IID "MCRI.host.module" - -#include -#include -#include -#include -#include - -enum TypeID -{ - GEN_FILE = 30, - TEXT = 31, - ERR = 32, - PRIV_TEXT = 33, - IDLE = 34, - HOST_CERT = 35, - FILE_INFO = 36, - PEER_INFO = 37, - MY_INFO = 38, - PEER_STAT = 39, - P2P_REQUEST = 40, - P2P_CLOSE = 41, - P2P_OPEN = 42, - BYTES = 43, - SESSION_ID = 44, - NEW_CMD = 45, - CMD_ID = 46, - BIG_TEXT = 47 -}; - -enum ChannelMemberLevel -{ - OWNER = 1, - ADMIN = 2, - OFFICER = 3, - REGULAR = 4, - PUBLIC = 5 -}; - -class ExternCommand; - -class SharedObjs : public QObject -{ - Q_OBJECT - -public: - - const QHash *cmdNames; - const QList *chList; - const QList *p2pAccepted; - const QList *p2pPending; - const QList *moreInputCmds; - const QList *activeLoopCmds; - const QList *pausedCmds; - const QString *sessionAddr; - const QString *userName; - const QString *groupName; - const QString *displayName; - const QString *appName; - const ushort *clientMajor; - const ushort *clientMinor; - const ushort *clientPatch; - const QByteArray *chIds; - const QByteArray *wrAbleChIds; - const QByteArray *sessionId; - const QByteArray *userId; - const bool *activeUpdate; - const bool *chOwnerOverride; - const uint *hostRank; - - explicit SharedObjs(QObject *parent = nullptr); -}; - -class ExternCommand : public QObject -{ - Q_OBJECT - -protected: - - void mainTxt(const QString &txt); - void errTxt(const QString &txt); - void privTxt(const QString &txt); - void bigTxt(const QString &txt); - -public: - - explicit ExternCommand(QObject *parent = nullptr) : QObject(parent) {} - - virtual ~ExternCommand() {} - - virtual void procBin(const SharedObjs *, const QByteArray &, uchar) {} - virtual void aboutToDelete() {} - virtual void term() {} - virtual bool handlesGenfile() {return false;} - virtual bool errState(); - virtual QString shortText() {return "";} - virtual QString ioText() {return "";} - virtual QString longText() {return "";} - virtual QString libText() {return "";} - virtual QStringList internRequest() {return QStringList();} - - QHash internCommands; - quint16 cmdId; - bool errSent; - bool inLoopMode; - bool inMoreInputMode; - -signals: - - void dataToClient(const QByteArray &data, uchar typeId = TEXT); - void castToPeers(const QByteArray &data, uchar typeId = TEXT); - void toPeer(const QByteArray &dst, const QByteArray &data, uchar typeId = TEXT); - void closeChByName(const QString &ch, const QString &sub); - void closeChById(quint64 id, uchar subId); - void openChByName(const QString &ch, const QString &sub); - void openChById(quint64 id, uchar subId); - void enableLoop(bool state); - void enableMoreInput(bool state); - void closeSession(); - void cmdFinished(); - void logout(); -}; - -class CommandLoader : public QObject -{ - Q_OBJECT - -public: - - explicit CommandLoader(QObject *parent = nullptr) : QObject(parent) {} - - virtual ~CommandLoader() {} - - virtual void modPath(const QString &) {} - virtual void aboutToDelete() {} - virtual bool hostRevOk(quint64, quint16, quint16, quint16) {return false;} - virtual QString lastError() {return "";} - virtual quint64 rev() {return 0;} - virtual QStringList pubCmdList() {return QStringList();} - virtual QStringList cmdList() {return QStringList();} - virtual QStringList rankExemptList() {return QStringList();} - virtual ExternCommand *cmdObj(const QString &) {return nullptr;} -}; - -QT_BEGIN_NAMESPACE -Q_DECLARE_INTERFACE(CommandLoader, MOD_LOADER_IID) -QT_END_NAMESPACE - -#endif // EXTERN_COMMAND_H diff --git a/modules/Tester/main.cpp b/modules/Tester/main.cpp deleted file mode 100644 index 51b23ad..0000000 --- a/modules/Tester/main.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include "main.h" - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -CommandLoader *hostImport() -{ - return new Loader(); -} - -QString libName() -{ - return QString(LIB_NAME) + "_" + QString(LIB_VERSION); -} - -Loader::Loader(QObject *parent) : CommandLoader(parent) -{ -} - -bool Loader::hostRevOk(quint64 minRev, quint16 vMajor, quint16 vMinor, quint16 vPatch) -{ - Q_UNUSED(vPatch) - - bool ret = false; - - if (minRev < IMPORT_REV) - { - err = "This module requires the host to supprt minimum import rev " + QString::number(IMPORT_REV) + " or higher."; - } - else if (vMajor != 1) - { - err = "Host major " + QString::number(vMajor) + " not supported. expected 1."; - } - else if (vMinor < 1) - { - err = "Host minor " + QString::number(vMinor) + " not supported. expected 1 or higher."; - } - else - { - ret = true; - } - - return ret; -} - -quint64 Loader::rev() -{ - return IMPORT_REV; -} - -QStringList Loader::cmdList() -{ - return QStringList() << "test_text" << "test_input" << "test_loop" << "test_inherit"; -} - -QString Loader::lastError() -{ - return err; -} - -ExternCommand *Loader::cmdObj(const QString &name) -{ - ExternCommand *ret = nullptr; - - if (name == "test_text") ret = new ModText(this); - else if (name == "test_input") ret = new ModInput(this); - else if (name == "test_loop") ret = new ModLoop(this); - else if (name == "test_inherit") ret = new ModInherit(this); - else - { - err = "Command name '" + name + "' does not exists in this module. (" + QString(LIB_NAME) + ")"; - } - - return ret; -} - -ModText::ModText(QObject *parent) : ExternCommand(parent) {} - -QString ModText::shortText() {return "test module text output.";} -QString ModText::ioText() {return "[none]/[text]";} -QString ModText::longText() {return "this test the module interface text output. input data is ignored.";} -QString ModText::libText() {return libName();} - -ModInput::ModInput(QObject *parent) : ExternCommand(parent) {} - -QString ModInput::shortText() {return "test module input hook.";} -QString ModInput::ioText() {return "[text]/[text]";} -QString ModInput::longText() {return "this command will ask you to enter Yes or No and will not release until a valid response is entered. this demonstrates how to impliment a confirmation question using the more input mode.";} -QString ModInput::libText() {return libName();} - -ModLoop::ModLoop(QObject *parent) : ExternCommand(parent) {index = 0;} - -QString ModLoop::shortText() {return "test module looping command.";} -QString ModLoop::ioText() {return "[none]/[text]";} -QString ModLoop::longText() {return "this command will display 'loop' along with the loop number 10 times to demonstrate looping.";} -QString ModLoop::libText() {return libName();} - -ModInherit::ModInherit(QObject *parent) : ExternCommand(parent) {} - -QString ModInherit::shortText() {return "module internal command inheritance test.";} -QString ModInherit::ioText() {return "[text]/[text]";} -QString ModInherit::longText() {return "this command will run the output of the known internal command 'my_info' to demonstrate internal command inheritance.";} -QString ModInherit::libText() {return libName();} - -void ModText::procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType) -{ - Q_UNUSED(data) - Q_UNUSED(dType) - Q_UNUSED(sharedObjs) - - // mainTxt() is convenience function that sends a TEXT frame to the CmdExecutor - // object to be processed by the host. it's basically a short hand for the emit - // call: - - // emit dataToClient(toTEXT("some text\n"), TEXT); - - // errTxt() does the same thing but indicates to the client that it is a error - // message so it can be displayed in a different color, size, logged etc.. - // depending on the client. - - // emit dataToClient(toTEXT("some error\n"), ERR); - - // privTxt() this also does that same thing except it indicates to the client - // that the command is asking for private data like a password, SSN, pin number - // etc.. clients that get this indicator should not echo or display the next - // data frame to be sent back to the host. - - // emit dataToClient(toTEXT("enter your password: "), PRIV); - - mainTxt("Main text out from module: " + QString(LIB_NAME) + "\n"); - errTxt("Error text out from module: " + QString(LIB_NAME) + "\n"); -} - -void ModInput::procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType) -{ - Q_UNUSED(sharedObjs) - - if (dType == TEXT) - { - QString text = QTextCodec::codecForName(TXT_CODEC)->toUnicode(data); - - if (inMoreInputMode) - { - if (text.isEmpty()) - { - errTxt("err: You entered nothing.\n"); - } - else - { - if ((text.toLower() == "yes") || (text.toLower() == "no")) - { - // setting moreInput false tells the host that the command - // is no longer asking for more input from the client so the - // host will consider the command finished at this point. - - emit enableMoreInput(false); - - mainTxt("You entered: '" + text + "' Good bye.\n"); - } - else - { - errTxt("err: Invalid response.\n"); - } - } - } - else - { - // setting moreInput true tells the host that the command is not - // finished and is awaiting more input from the client. you don't - // need to reimplement term() if all it takes for the command to - // finish its task is to set moreInput and/or loop false; the - // host will do that externally. - - emit enableMoreInput(true); - - mainTxt("Please enter Yes or No: "); - } - } -} - -void ModLoop::term() -{ - // this function is called by the host to terminate the command if - // termination is requested and only if the more input or loop modes - // are active. - - // this command has a variable called 'index' that the host is not aware - // of and does not have access to it so in this case, index needs reset - // to 0 when the command is requested to terminate. - - index = 0; -} - -void ModLoop::procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType) -{ - Q_UNUSED(data) - Q_UNUSED(dType) - Q_UNUSED(sharedObjs) - - // the host will constantly call this function for as long as loop - // mode remains true or if requested to terminate. keep in mind that - // in all subsequent calls after the initial call, the input data will - // always be empty and dType will always default to TEXT. - - if (inLoopMode) - { - mainTxt("Loop: " + QString::number(index++) + "\n"); - - if (index == 10) - { - emit enableLoop(false); - - index = 0; - } - } - else - { - emit enableLoop(true); - } -} - -QStringList ModInherit::internRequest() -{ - return QStringList() << "my_info"; -} - -void ModInherit::procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType) -{ - Q_UNUSED(data) - Q_UNUSED(dType) - - if (!internCommands.contains("my_info")) - { - errTxt("err: This command object did not successfully inherit 'my_info' unable to continue.\n"); - } - else - { - mainTxt("If inherited correctly, the output of 'my_info' should show below:\n\n"); - - internCommands["my_info"]->procBin(sharedObjs, QByteArray(), TEXT); - } -} diff --git a/modules/Tester/main.h b/modules/Tester/main.h deleted file mode 100644 index d4f79a2..0000000 --- a/modules/Tester/main.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef MOD_TESTER_H -#define MOD_TESTER_H - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -#include -#include -#include - -#include "command.h" - -#define IMPORT_REV 3 - -// the import revision is a module compatibility version number -// used by the host to determine if it can successfully load and -// run this library or not. as of right now, the host supports rev1 -// and up. - -#define LIB_VERSION "1.0.1" -#define LIB_NAME "MRCITestMod" - -// the versioning system for the library itself can be completely -// different from the host import revision. - -#if defined(MOD_TESTER) -# define MOD_TESTER_EXPORT Q_DECL_EXPORT -#else -# define MOD_TESTER_EXPORT Q_DECL_IMPORT -#endif - -extern "C" MOD_TESTER_EXPORT CommandLoader *hostImport(); - -QString libName(); - -class Loader : public CommandLoader -{ - Q_OBJECT - -private: - - QString err; - -public: - - bool hostRevOk(quint64 minRev, quint16 vMajor, quint16 vMinor, quint16 vPatch); - quint64 rev(); - ExternCommand *cmdObj(const QString &name); - QStringList cmdList(); - QString lastError(); - - explicit Loader(QObject *parent = nullptr); -}; - -//----------------- - -class ModText : public ExternCommand -{ - Q_OBJECT - -public: - - explicit ModText(QObject *parent = nullptr); - - void procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType); - QString shortText(); - QString ioText(); - QString longText(); - QString libText(); -}; - -//-------------------- - -class ModInput : public ExternCommand -{ - Q_OBJECT - -public: - - explicit ModInput(QObject *parent = nullptr); - - void procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType); - QString shortText(); - QString ioText(); - QString longText(); - QString libText(); -}; - -//----------------------- - -class ModLoop : public ExternCommand -{ - Q_OBJECT - -private: - - int index; - -public: - - explicit ModLoop(QObject *parent = nullptr); - - void term(); - void procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType); - QString shortText(); - QString ioText(); - QString longText(); - QString libText(); -}; - -//-------------------------- - -class ModInherit : public ExternCommand -{ - Q_OBJECT - -public: - - explicit ModInherit(QObject *parent = nullptr); - - void procBin(const SharedObjs *sharedObjs, const QByteArray &data, uchar dType); - QString shortText(); - QString ioText(); - QString longText(); - QString libText(); - QStringList internRequest(); -}; - -#endif // MOD_TESTER_H diff --git a/src/cmd_object.cpp b/src/cmd_object.cpp index bb57e24..3d083bd 100644 --- a/src/cmd_object.cpp +++ b/src/cmd_object.cpp @@ -70,12 +70,13 @@ void IPCWorker::connectIPC() CmdObject::CmdObject(QObject *parent) : MemShare(parent) { - flags = 0; + flags = 0; + retCode = NO_ERRORS; - QStringList args = QCoreApplication::instance()->arguments(); - QString pipe = getParam("-pipe_name", args); - QString sMemKey = getParam("-mem_ses", args); - QString hMemKey = getParam("-mem_host", args); + auto args = QCoreApplication::instance()->arguments(); + auto pipe = getParam("-pipe_name", args); + auto sMemKey = getParam("-mem_ses", args); + auto hMemKey = getParam("-mem_host", args); if (attachSharedMem(sMemKey, hMemKey)) { @@ -114,7 +115,8 @@ void CmdObject::term() { if (flags & (MORE_INPUT | HALT_STATE | LOOPING)) { - flags = 0; + flags = 0; + retCode = ABORTED; onTerminate(); postProc(); @@ -180,7 +182,9 @@ void CmdObject::postProc() { keepAliveTimer->stop(); - emit procOut(QByteArray(), IDLE); + emit procOut(wrInt(retCode, 16), IDLE); + + retCode = NO_ERRORS; } } diff --git a/src/cmd_object.h b/src/cmd_object.h index b298a6c..15336ee 100644 --- a/src/cmd_object.h +++ b/src/cmd_object.h @@ -67,6 +67,7 @@ protected: QTimer *keepAliveTimer; IPCWorker *ipcWorker; quint32 flags; + quint16 retCode; void mainTxt(const QString &txt); void errTxt(const QString &txt); diff --git a/src/cmd_proc.cpp b/src/cmd_proc.cpp index 53ffeae..0976c63 100644 --- a/src/cmd_proc.cpp +++ b/src/cmd_proc.cpp @@ -428,7 +428,7 @@ void CmdProcess::onReady() void CmdProcess::onFailToStart() { emit dataToClient(cmdId, toTEXT("err: The command failed to start. error details were logged for admin review.\n"), ERR); - emit dataToClient(cmdId, QByteArray(), IDLE); + emit dataToClient(cmdId, wrInt(FAILED_TO_START, 16), IDLE); } void CmdProcess::onFinished(int exitCode, QProcess::ExitStatus exitStatus) @@ -436,7 +436,7 @@ void CmdProcess::onFinished(int exitCode, QProcess::ExitStatus exitStatus) if (!cmdIdle) { emit dataToClient(cmdId, toTEXT("err: The command has stopped unexpectedly or it has failed to send an IDLE frame before exiting.\n"), ERR); - emit dataToClient(cmdId, QByteArray(), IDLE); + emit dataToClient(cmdId, wrInt(CRASH, 16), IDLE); } emit cmdProcFinished(cmdId); @@ -648,9 +648,20 @@ void CmdProcess::onDataFromProc(quint8 typeId, const QByteArray &data) if (typeId == IDLE) { cmdIdle = true; - } - emit dataToClient(cmdId, data, typeId); + if (data.isEmpty()) + { + emit dataToClient(cmdId, wrInt(NO_ERRORS, 16), typeId); + } + else + { + emit dataToClient(cmdId, data, typeId); + } + } + else + { + emit dataToClient(cmdId, data, typeId); + } } } diff --git a/src/commands/acct_recovery.cpp b/src/commands/acct_recovery.cpp index 40f42e4..46d2e1b 100644 --- a/src/commands/acct_recovery.cpp +++ b/src/commands/acct_recovery.cpp @@ -48,7 +48,7 @@ void delRecoverPw(const QByteArray &uId) bool expired(const QByteArray &uId) { - bool ret = true; + auto ret = true; Query db; @@ -57,7 +57,7 @@ bool expired(const QByteArray &uId) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - QDateTime expiry = db.getData(COLUMN_TIME).toDateTime().addSecs(3600); // pw datetime + 1hour; + auto expiry = db.getData(COLUMN_TIME).toDateTime().addSecs(3600); // pw datetime + 1hour; if (expiry > QDateTime::currentDateTime().toUTC()) { @@ -88,7 +88,7 @@ void RecoverAcct::addToThreshold() db.addColumn(COLUMN_LOCK_LIMIT); db.exec(); - quint32 maxAttempts = db.getData(COLUMN_LOCK_LIMIT).toUInt(); + auto maxAttempts = db.getData(COLUMN_LOCK_LIMIT).toUInt(); db.setType(Query::PULL, TABLE_AUTH_LOG); db.addColumn(COLUMN_IPADDR); @@ -107,7 +107,7 @@ void RecoverAcct::addToThreshold() else { errTxt("err: Access denied.\n"); - privTxt("Enter the temporary password: "); + privTxt("Enter the temporary password (leave blank to cancel): "); } } @@ -115,14 +115,21 @@ void RecoverAcct::procIn(const QByteArray &binIn, quint8 dType) { if ((flags & MORE_INPUT) && (dType == TEXT)) { - QString pw = fromTEXT(binIn); + auto pw = fromTEXT(binIn); if (inputOk) { - if (!validPassword(pw)) + QString errMsg; + + if (pw.isEmpty()) { - errTxt("err: Invalid password. it must be 8-200 chars long containing numbers, mixed case letters and special chars.\n"); - privTxt("Enter a new password: "); + retCode = ABORTED; + flags &= ~MORE_INPUT; + } + else if (!acceptablePw(pw, uId, &errMsg)) + { + errTxt(errMsg + "\n"); + privTxt("Enter a new password (leave blank to cancel): "); } else { @@ -136,7 +143,8 @@ void RecoverAcct::procIn(const QByteArray &binIn, quint8 dType) { if (pw.isEmpty()) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else if (!validPassword(pw)) { @@ -148,7 +156,7 @@ void RecoverAcct::procIn(const QByteArray &binIn, quint8 dType) } else { - privTxt("Enter a new password: "); + privTxt("Enter a new password (leave blank to cancel): "); inputOk = true; } @@ -156,15 +164,17 @@ void RecoverAcct::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString email = getParam("-email", args); - QString name = getParam("-user", args); + auto args = parseArgs(binIn, 2); + auto email = getParam("-email", args); + auto name = getParam("-user", args); if (!email.isEmpty() && validEmailAddr(email)) { name = getUserNameForEmail(email); } + retCode = INVALID_PARAMS; + if (name.isEmpty() || !validUserName(name)) { errTxt("err: The -user or -email argument is empty, not found or invalid.\n"); @@ -186,6 +196,7 @@ void RecoverAcct::procIn(const QByteArray &binIn, quint8 dType) privTxt("Enter the temporary password (leave blank to cancel): "); inputOk = false; + retCode = NO_ERRORS; flags |= MORE_INPUT; } } @@ -195,16 +206,19 @@ void ResetPwRequest::procIn(const QByteArray &binIn, uchar dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString email = getParam("-email", args); - QString name = getParam("-user", args); - QByteArray uId; + auto args = parseArgs(binIn, 2); + auto email = getParam("-email", args); + auto name = getParam("-user", args); + + QByteArray uId; if (!email.isEmpty() && validEmailAddr(email)) { name = getUserNameForEmail(email); } + retCode = INVALID_PARAMS; + if (name.isEmpty() || !validUserName(name)) { errTxt("err: The -user or -email argument is empty, not found or invalid.\n"); @@ -215,9 +229,10 @@ void ResetPwRequest::procIn(const QByteArray &binIn, uchar dType) } else { - QString pw = genPw(); - QString date = QDateTime::currentDateTimeUtc().toString("YYYY-MM-DD HH:MM:SS"); + retCode = NO_ERRORS; + auto pw = genPw(); + if (recoverPWExists(uId)) { updatePassword(uId, pw, TABLE_PW_RECOVERY); @@ -236,10 +251,11 @@ void ResetPwRequest::procIn(const QByteArray &binIn, uchar dType) db.addColumn(COLUMN_MAIL_SEND); db.exec(); - QString subject = db.getData(COLUMN_TEMP_PW_SUBJECT).toString(); - QString body = db.getData(COLUMN_TEMP_PW_MSG).toString(); - QString app = db.getData(COLUMN_MAILERBIN).toString(); - QString cmdLine = db.getData(COLUMN_MAIL_SEND).toString(); + auto date = QDateTime::currentDateTimeUtc().toString("YYYY-MM-DD HH:MM:SS"); + auto subject = db.getData(COLUMN_TEMP_PW_SUBJECT).toString(); + auto body = db.getData(COLUMN_TEMP_PW_MSG).toString(); + auto app = db.getData(COLUMN_MAILERBIN).toString(); + auto cmdLine = db.getData(COLUMN_MAIL_SEND).toString(); body.replace(DATE_SUB, date); body.replace(USERNAME_SUB, name); @@ -260,11 +276,12 @@ void VerifyEmail::procIn(const QByteArray &binIn, quint8 dType) { if ((flags & MORE_INPUT) && (dType == TEXT)) { - QString txt = fromTEXT(binIn); + auto txt = fromTEXT(binIn); if (txt.isEmpty()) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else if (txt == code) { @@ -289,10 +306,12 @@ void VerifyEmail::procIn(const QByteArray &binIn, quint8 dType) { uId = rdFromBlock(userId, BLKSIZE_USER_ID); - QString email = getEmailForUser(uId); + auto email = getEmailForUser(uId); if (email.isEmpty()) { + retCode = INVALID_PARAMS; + errTxt("err: Your account currently has no email address, please update it.\n"); } else @@ -309,12 +328,12 @@ void VerifyEmail::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_MAIL_SEND); db.exec(); - QString uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); - QString date = QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd HH:mm:ss"); - QString subject = db.getData(COLUMN_CONFIRM_SUBJECT).toString(); - QString body = db.getData(COLUMN_CONFIRM_MSG).toString(); - QString app = db.getData(COLUMN_MAILERBIN).toString(); - QString cmdLine = db.getData(COLUMN_MAIL_SEND).toString(); + auto uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); + auto date = QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd HH:mm:ss"); + auto subject = db.getData(COLUMN_CONFIRM_SUBJECT).toString(); + auto body = db.getData(COLUMN_CONFIRM_MSG).toString(); + auto app = db.getData(COLUMN_MAILERBIN).toString(); + auto cmdLine = db.getData(COLUMN_MAIL_SEND).toString(); body.replace(DATE_SUB, date); body.replace(USERNAME_SUB, uName); @@ -337,7 +356,7 @@ void IsEmailVerified::procIn(const QByteArray &binIn, quint8 dType) if (dType == TEXT) { - QByteArray uId = rdFromBlock(userId, BLKSIZE_USER_ID); + auto uId = rdFromBlock(userId, BLKSIZE_USER_ID); Query db(this); @@ -368,7 +387,7 @@ void SetEmailTemplate::procIn(const QByteArray &binIn, quint8 dType) } else if ((dType == GEN_FILE) || (dType == TEXT)) { - QStringList args = parseArgs(binIn, 9); + auto args = parseArgs(binIn, 9); dataSent = 0; textFromFile = argExists("-client_file", args); @@ -389,6 +408,8 @@ void SetEmailTemplate::procIn(const QByteArray &binIn, quint8 dType) eType = NONE; } + retCode = INVALID_PARAMS; + if (eType == NONE) { errTxt("err: Which template do you want to change? -reset_template or -confirm_template not found.\n"); @@ -407,6 +428,8 @@ void SetEmailTemplate::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + if (argExists("-subject", args) && subject.isEmpty()) { if (eType == CONFIRM_EMAIL) subject = DEFAULT_CONFIRM_SUBJECT; @@ -442,6 +465,8 @@ void SetEmailTemplate::proc() { if (bodyText.isEmpty() && subject.isEmpty()) { + retCode = INVALID_PARAMS; + errTxt("err: The email body and subject text are empty, nothing will be changed.\n"); } else @@ -453,7 +478,8 @@ void SetEmailTemplate::proc() QString codeSub; QString bodyColumn; QString subjectColumn; - bool execQuery = false; + + auto execQuery = false; if (eType == PW_RESET) { @@ -470,6 +496,8 @@ void SetEmailTemplate::proc() if (!bodyText.isEmpty()) { + retCode = INVALID_PARAMS; + if (!bodyText.contains(DATE_SUB, Qt::CaseInsensitive)) { errTxt("err: The email body does not contain: " + QString(DATE_SUB) + "\n"); @@ -493,11 +521,14 @@ void SetEmailTemplate::proc() db.addColumn(bodyColumn, bodyText); execQuery = true; + retCode = NO_ERRORS; } } if (!subject.isEmpty()) { + retCode = INVALID_PARAMS; + if (subject.size() > 120) { errTxt("err: The subject is too large. it cannot exceed 120 chars.\n"); @@ -509,6 +540,7 @@ void SetEmailTemplate::proc() db.addColumn(subjectColumn, subject); execQuery = true; + retCode = NO_ERRORS; } } @@ -522,14 +554,16 @@ void PreviewEmail::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - TemplateType eType = NONE; + auto args = parseArgs(binIn, 4); + auto eType = NONE; if (argExists("-reset_email", args)) eType = PW_RESET; else if (argExists("-confirm_email", args)) eType = CONFIRM_EMAIL; if (eType == NONE) { + retCode = INVALID_PARAMS; + errTxt("err: which template do you want to preview? -reset_email or -confirm_email not found.\n"); } else @@ -538,7 +572,8 @@ void PreviewEmail::procIn(const QByteArray &binIn, quint8 dType) QString code; QString bodyColumn; QString subjectColumn; - QString date = QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd HH:mm:ss"); + + auto date = QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd HH:mm:ss"); if (eType == PW_RESET) { @@ -562,9 +597,9 @@ void PreviewEmail::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(subjectColumn); db.exec(); - QString uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); - QString subject = db.getData(subjectColumn).toString(); - QString body = db.getData(bodyColumn).toString(); + auto uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); + auto subject = db.getData(subjectColumn).toString(); + auto body = db.getData(bodyColumn).toString(); body.replace(DATE_SUB, date); body.replace(USERNAME_SUB, uName); diff --git a/src/commands/admin.cpp b/src/commands/admin.cpp index e653fde..f927800 100644 --- a/src/commands/admin.cpp +++ b/src/commands/admin.cpp @@ -30,7 +30,7 @@ void CloseHost::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString input = fromTEXT(binIn); + auto input = fromTEXT(binIn); if (input == "CLOSE") { @@ -40,7 +40,8 @@ void CloseHost::procIn(const QByteArray &binIn, quint8 dType) } else if (input.isEmpty()) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else { @@ -63,7 +64,7 @@ void RestartHost::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString input = fromTEXT(binIn); + auto input = fromTEXT(binIn); if (input == "RESTART") { @@ -73,7 +74,8 @@ void RestartHost::procIn(const QByteArray &binIn, quint8 dType) } else if (input.isEmpty()) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else if (!input.isEmpty()) { @@ -96,7 +98,6 @@ void ServSettings::printSettings() db.setType(Query::PULL, TABLE_SERV_SETTINGS); db.addColumn(COLUMN_PUB_USERS); - db.addColumn(COLUMN_BAN_LIMIT); db.addColumn(COLUMN_LOCK_LIMIT); db.addColumn(COLUMN_MAXSESSIONS); db.addColumn(COLUMN_INITRANK); @@ -108,26 +109,26 @@ void ServSettings::printSettings() db.addColumn(COLUMN_MAX_SUB_CH); db.exec(); - QString pubBool = boolStr(db.getData(COLUMN_PUB_USERS).toBool()); - QString resBool = boolStr(db.getData(COLUMN_ENABLE_PW_RESET).toBool()); - QString conBool = boolStr(db.getData(COLUMN_ENABLE_CONFIRM).toBool()); - QString actBool = boolStr(db.getData(COLUMN_ACTIVE_UPDATE).toBool()); + auto pubBool = boolStr(db.getData(COLUMN_PUB_USERS).toBool()); + auto resBool = boolStr(db.getData(COLUMN_ENABLE_PW_RESET).toBool()); + auto conBool = boolStr(db.getData(COLUMN_ENABLE_CONFIRM).toBool()); + auto actBool = boolStr(db.getData(COLUMN_ACTIVE_UPDATE).toBool()); QString txt; QTextStream txtOut(&txt); - txtOut << "All Sub-Channels Active Update: " << actBool << endl; - txtOut << "Public Registration: " << pubBool << endl; - txtOut << "Automated Password Resets: " << resBool << endl; - txtOut << "Automated Email Verify: " << conBool << endl; - txtOut << "Maximum Sessions: " << db.getData(COLUMN_MAXSESSIONS).toUInt() << endl; - txtOut << "Autoban Threshold: " << db.getData(COLUMN_BAN_LIMIT).toUInt() << endl; - txtOut << "Autolock Threshold: " << db.getData(COLUMN_LOCK_LIMIT).toUInt() << endl; - txtOut << "Maximum Sub-Channels: " << db.getData(COLUMN_MAX_SUB_CH).toUInt() << endl; - txtOut << "Initial Host Rank: " << db.getData(COLUMN_INITRANK).toUInt() << endl; - txtOut << "Database Path: " << sqlDataPath() << endl; - txtOut << "Mailer Executable: " << db.getData(COLUMN_MAILERBIN).toString() << endl; - txtOut << "Mailer Command: " << db.getData(COLUMN_MAIL_SEND).toString() << endl << endl; + txtOut << "All Sub-Channels Active Update: " << actBool << endl; + txtOut << "Public Registration: " << pubBool << endl; + txtOut << "Automated Password Resets: " << resBool << endl; + txtOut << "Automated Email Verify: " << conBool << endl; + txtOut << "Maximum Sessions: " << db.getData(COLUMN_MAXSESSIONS).toUInt() << endl; + txtOut << "Autolock Threshold: " << db.getData(COLUMN_LOCK_LIMIT).toUInt() << endl; + txtOut << "Maximum Sub-Channels: " << db.getData(COLUMN_MAX_SUB_CH).toUInt() << endl; + txtOut << "Initial Host Rank: " << db.getData(COLUMN_INITRANK).toUInt() << endl; + txtOut << "Root User: " << getUserName(rootUserId()) << endl; + txtOut << "Database Path: " << sqlDataPath() << endl; + txtOut << "Mailer Executable: " << db.getData(COLUMN_MAILERBIN).toString() << endl; + txtOut << "Mailer Command: " << db.getData(COLUMN_MAIL_SEND).toString() << endl << endl; mainTxt(txt); } @@ -139,12 +140,12 @@ void ServSettings::printOptions() QString txt; QTextStream txtOut(&txt); - txtOut << "[01] Autoban Threshold [02] Autolock Threshold" << endl; - txtOut << "[03] Max Sessions [04] Public Registration" << endl; - txtOut << "[05] Initial Rank [06] Mailer Exe" << endl; - txtOut << "[07] Mailer Command [08] Password Resets" << endl; - txtOut << "[09] Email Verify [10] Active Update" << endl; - txtOut << "[11] Max Sub-Channels [00] Exit" << endl << endl; + txtOut << "[01] Autolock Threshold [02] Max Sessions" << endl; + txtOut << "[03] Public Registration [04] Initial Rank" << endl; + txtOut << "[05] Mailer Exe [06] Mailer Command" << endl; + txtOut << "[07] Password Resets [08] Email Verify" << endl; + txtOut << "[09] Active Update [10] Max Sub-Channels" << endl; + txtOut << "[11] Set Root User [00] Exit" << endl << endl; txtOut << "Select an option: "; level = 1; @@ -174,33 +175,21 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) QString txt; QTextStream txtOut(&txt); - bool ok = false; + auto ok = false; select = fromTEXT(binIn).toInt(&ok); if ((select == 1) && ok) { - txtOut << "" << endl; - txtOut << "The autoban threshold is an integar value that determines how many" << endl; - txtOut << "failed login attempts can be made to the " << ROOT_USER << " user before the" << endl; - txtOut << "offending ip address is blocked by the host." << endl << endl; + txtOut << "" << endl; + txtOut << "The autolock threshold is an integer value that determines how many" << endl; + txtOut << "failed login attempts can be made before the user account is locked" << endl; + txtOut << "by the host." << endl << endl; txtOut << "Enter a new value (leave blank to cancel): "; level = 2; } else if ((select == 2) && ok) - { - txtOut << "" << endl; - txtOut << "The autolock threshold is an integer value that determines how many" << endl; - txtOut << "failed login attempts can be made before the user account is locked" << endl; - txtOut << "by the host." << endl << endl; - txtOut << "note: the " << ROOT_USER << " user never gets locked. instead, the offenders are blocked" << endl; - txtOut << " by ip address according to the autoban threshold." << endl << endl; - txtOut << "Enter a new value (leave blank to cancel): "; - - level = 2; - } - else if ((select == 3) && ok) { txtOut << "" << endl; txtOut << "Max sessions is an integar value that determines how many simultaneous" << endl; @@ -209,11 +198,11 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 4) && ok) + else if ((select == 3) && ok) { txtOut << "" << endl; txtOut << "Public registration basically allows un-logged in clients to run the" << endl; - txtOut << "new_user command. doing this allows un-registered users to become" << endl; + txtOut << "add_acct command. doing this allows un-registered users to become" << endl; txtOut << "registered users without the need to contact an admin." << endl << endl; txtOut << "[0] Disable" << endl; txtOut << "[1] Enable" << endl << endl; @@ -221,7 +210,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 5) && ok) + else if ((select == 4) && ok) { txtOut << "" << endl; txtOut << "The initial host rank is the rank all new user accounts are registered" << endl; @@ -231,7 +220,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 6) && ok) + else if ((select == 5) && ok) { txtOut << "" << endl; txtOut << "This is the path to the command line email client executable" << endl; @@ -242,7 +231,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 7) && ok) + else if ((select == 6) && ok) { txtOut << "" << endl; txtOut << "This is the command line that will be used with the email client" << endl; @@ -254,31 +243,32 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 8) && ok) + else if ((select == 7) && ok) { txtOut << "" << endl; txtOut << "This enables automated password resets via email so users can" << endl; txtOut << "reset their account passwords without the need to contact an" << endl; txtOut << "admin. this basically tells the host if it is allowed to load" << endl; - txtOut << "the request_pw_reset and recover_account commands or not." << endl << endl; + txtOut << "the request_pw_reset and recover_acct commands or not." << endl << endl; txtOut << "[0] Disable" << endl; txtOut << "[1] Enable" << endl << endl; txtOut << "Select an option (leave blank to cancel): "; level = 2; } - else if ((select == 9) && ok) + else if ((select == 8) && ok) { - txtOut << "" << endl; - txtOut << "This enables automated email confirmations. this tells the" << endl; - txtOut << "host if it is allowed to load the confirm_email command." << endl << endl; - txtOut << "[0] Disable" << endl; - txtOut << "[1] Enable" << endl << endl; + txtOut << "" << endl; + txtOut << "This enables/disables automated email confirmations. this" << endl; + txtOut << "tells the host if it is allowed to load the verify_email " << endl; + txtOut << "command for any user, regardless of rank." << endl << endl; + txtOut << "[0] Disable" << endl; + txtOut << "[1] Enable" << endl << endl; txtOut << "Select an option (leave blank to cancel): "; level = 2; } - else if ((select == 10) && ok) + else if ((select == 9) && ok) { txtOut << "" << endl; txtOut << "This option tells the host if all sub-channels should be considered" << endl; @@ -293,7 +283,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } - else if ((select == 11) && ok) + else if ((select == 10) && ok) { txtOut << "" << endl; txtOut << "This option sets the maximum amount of sub-channels each channel can" << endl; @@ -302,6 +292,27 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) level = 2; } + else if ((select == 11) && ok) + { + txtOut << "" << endl; + txtOut << "Set the root user of the host by the given user name. the root user" << endl; + txtOut << "is an unrestricted user that can do anything on the host. this user" << endl; + txtOut << "however is unable to change rank (1) and cannot get deleted. only" << endl; + txtOut << "the current root user can use this option to appoint an existing" << endl; + txtOut << "user as the new root." << endl << endl; + + if (rdFromBlock(userId, BLKSIZE_USER_ID) != rootUserId()) + { + txtOut << "Enter a new user name (leave blank to cancel): "; + } + else + { + txtOut << "You are not the current root user so this option is blocked." << endl; + txtOut << "Press enter to return to the main menu."; + } + + level = 2; + } else if ((select == 0) && ok) { flags &= ~MORE_INPUT; @@ -315,7 +326,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) } else if (level == 2) { - QString value = fromTEXT(binIn); + auto value = fromTEXT(binIn); if (value.isEmpty()) { @@ -324,7 +335,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) } else { - if ((select == 1) || (select == 2) || (select == 3) || (select == 5)) + if ((select == 1) || (select == 2) || (select == 4)) { bool ok; quint32 num = value.toUInt(&ok, 10); @@ -345,14 +356,13 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) db.setType(Query::UPDATE, TABLE_SERV_SETTINGS); - if (select == 1) db.addColumn(COLUMN_BAN_LIMIT, num); - else if (select == 2) db.addColumn(COLUMN_LOCK_LIMIT, num); - else if (select == 3) db.addColumn(COLUMN_MAXSESSIONS, num); + if (select == 1) db.addColumn(COLUMN_LOCK_LIMIT, num); + else if (select == 2) db.addColumn(COLUMN_MAXSESSIONS, num); else db.addColumn(COLUMN_INITRANK, num); db.exec(); - if (select == 3) + if (select == 2) { async(ASYNC_MAXSES, PRIV_IPC, wrInt(num, BLKSIZE_HOST_LOAD * 8)); } @@ -360,7 +370,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) returnToStart(); } } - else if ((select == 4) || (select == 8) || (select == 9) || (select == 10)) + else if ((select == 3) || (select == 7) || (select == 8) || (select == 9)) { if (!isBool(value)) { @@ -371,9 +381,9 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) { QString column; - if (select == 4) column = COLUMN_PUB_USERS; - else if (select == 8) column = COLUMN_ENABLE_PW_RESET; - else if (select == 9) column = COLUMN_ENABLE_CONFIRM; + if (select == 3) column = COLUMN_PUB_USERS; + else if (select == 7) column = COLUMN_ENABLE_PW_RESET; + else if (select == 8) column = COLUMN_ENABLE_CONFIRM; else column = COLUMN_ACTIVE_UPDATE; Query db(this); @@ -385,7 +395,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) returnToStart(); } } - else if (select == 6) + else if (select == 5) { if (!QFile::exists(expandEnvVariables(value))) { @@ -403,7 +413,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) returnToStart(); } } - else if (select == 7) + else if (select == 6) { if (!value.contains(SUBJECT_SUB, Qt::CaseInsensitive)) { @@ -431,7 +441,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) returnToStart(); } } - else if (select == 11) + else if (select == 10) { if (!isInt(value)) { @@ -451,6 +461,35 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_MAX_SUB_CH, value.toInt()); db.exec(); + returnToStart(); + } + } + else if (select == 11) + { + QByteArray uId; + + if (rdFromBlock(userId, BLKSIZE_USER_ID) != rootUserId()) + { + returnToStart(); + } + else if (!validUserName(value)) + { + errTxt("err: Invalid user name. it must be 2-24 chars long and contain no spaces.\n"); + mainTxt("Enter a new user name (leave blank to cancel): "); + } + else if (!userExists(value, &uId)) + { + errTxt("err: The requested user name does not exists.\n"); + mainTxt("Enter a new user name (leave blank to cancel): "); + } + else + { + Query db(this); + + db.setType(Query::UPDATE, TABLE_SERV_SETTINGS); + db.addColumn(COLUMN_ROOT_USER, value); + db.exec(); + returnToStart(); } } diff --git a/src/commands/auth.cpp b/src/commands/auth.cpp index f00ce0a..78bd0ca 100644 --- a/src/commands/auth.cpp +++ b/src/commands/auth.cpp @@ -48,26 +48,10 @@ void Auth::addToThreshold() db.exec(); db.setType(Query::PULL, TABLE_SERV_SETTINGS); + db.addColumn(COLUMN_LOCK_LIMIT); + db.exec(); - quint32 maxAttempts = 0; - bool isRoot = false; - - if (noCaseMatch(ROOT_USER, uName)) - { - isRoot = true; - - db.addColumn(COLUMN_BAN_LIMIT); - db.exec(); - - maxAttempts = db.getData(COLUMN_BAN_LIMIT).toUInt(); - } - else - { - db.addColumn(COLUMN_LOCK_LIMIT); - db.exec(); - - maxAttempts = db.getData(COLUMN_LOCK_LIMIT).toUInt(); - } + auto maxAttempts = db.getData(COLUMN_LOCK_LIMIT).toUInt(); db.setType(Query::PULL, TABLE_AUTH_LOG); db.addColumn(COLUMN_IPADDR); @@ -75,32 +59,14 @@ void Auth::addToThreshold() db.addCondition(COLUMN_AUTH_ATTEMPT, true); db.addCondition(COLUMN_COUNT, true); db.addCondition(COLUMN_ACCEPTED, false); - - if (isRoot) db.addCondition(COLUMN_IPADDR, ip); - db.exec(); if (static_cast(db.rows()) > maxAttempts) { - if (isRoot) - { - if (!QHostAddress(ip).isLoopback()) - { - db.setType(Query::PUSH, TABLE_IPBANS); - db.addColumn(COLUMN_IPADDR, ip); - db.exec(); - - async(ASYNC_UPDATE_BANS, PRIV_IPC); - async(ASYNC_END_SESSION, PRIV_IPC); - } - } - else - { - db.setType(Query::UPDATE, TABLE_USERS); - db.addColumn(COLUMN_LOCKED, true); - db.addCondition(COLUMN_USER_ID, uId); - db.exec(); - } + db.setType(Query::UPDATE, TABLE_USERS); + db.addColumn(COLUMN_LOCKED, true); + db.addCondition(COLUMN_USER_ID, uId); + db.exec(); flags &= ~MORE_INPUT; } @@ -121,7 +87,7 @@ void Auth::confirmAuth() db.addCondition(COLUMN_USER_ID, uId); db.addCondition(COLUMN_AUTH_ATTEMPT, true); - if (noCaseMatch(ROOT_USER, uName)) + if (rootUserId() == uId) { db.addCondition(COLUMN_IPADDR, ip); } @@ -155,15 +121,18 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) { if (newPassword) { + QString errMsg; + if (text.isEmpty()) { mainTxt("\n"); - flags &= ~MORE_INPUT; + flags &= ~MORE_INPUT; + retCode = ABORTED; } - else if (!validPassword(text)) + else if (!acceptablePw(text, uId, &errMsg)) { - errTxt("err: Invalid password. it must be 8-200 chars long containing numbers, mixed case letters and special chars.\n\n"); + errTxt(errMsg + "\n"); privTxt("Enter a new password (leave blank to cancel): "); } else @@ -195,16 +164,32 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) { mainTxt("\n"); - flags &= ~MORE_INPUT; + flags &= ~MORE_INPUT; + retCode = ABORTED; + } + else if (noCaseMatch(DEFAULT_ROOT_USER, text)) + { + errTxt("err: '" + QString(DEFAULT_ROOT_USER) + "' is a reserved keyword. invalid for use as a user name.\n"); + mainTxt("Enter a new user name (leave blank to cancel): "); + } + else if (validEmailAddr(text)) + { + errTxt("err: Invaild use rname. it looks like an email address.\n"); + mainTxt("Enter a new user name (leave blank to cancel): "); } else if (!validUserName(text)) { - errTxt("err: Invalid username. it must be 2-24 chars long and contain no spaces.\n\n"); + errTxt("err: Invalid user name. it must be 2-24 chars long and contain no spaces.\n\n"); mainTxt("Enter a new user name (leave blank to cancel): "); } - else if (!userExists(text)) + else if (noCaseMatch(text, uName)) { - errTxt("err: The requested User name already exists.\n\n"); + errTxt("err: You cannot re-apply your old user name.\n\n"); + mainTxt("Enter a new user name (leave blank to cancel): "); + } + else if (userExists(text)) + { + errTxt("err: The requested user name already exists.\n\n"); mainTxt("Enter a new user name (leave blank to cancel): "); } else @@ -230,7 +215,8 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) { mainTxt("\n"); - flags &= ~MORE_INPUT; + flags &= ~MORE_INPUT; + retCode = ABORTED; } else if (!validPassword(text)) { @@ -260,15 +246,17 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 2); - QString email = getParam("-email", args); - QString name = getParam("-user", args); + auto args = parseArgs(binIn, 2); + auto email = getParam("-email", args); + auto name = getParam("-user", args); if (!email.isEmpty() && validEmailAddr(email)) { name = getUserNameForEmail(email); } + retCode = INVALID_PARAMS; + if (name.isEmpty() || !validUserName(name)) { errTxt("err: The -user or -email argument is empty, not found or invalid.\n"); @@ -294,6 +282,7 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) loginOk = false; uName = name; + retCode = NO_ERRORS; flags |= MORE_INPUT; ip = rdStringFromBlock(clientIp, BLKSIZE_CLIENT_IP); newPassword = db.getData(COLUMN_NEED_PASS).toBool(); diff --git a/src/commands/bans.cpp b/src/commands/bans.cpp deleted file mode 100644 index 7faa2d0..0000000 --- a/src/commands/bans.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "bans.h" - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -ListBans::ListBans(QObject *parent) : TableViewer(parent) -{ - setParams(TABLE_IPBANS, true); - addTableColumn(TABLE_IPBANS, COLUMN_TIME); - addTableColumn(TABLE_IPBANS, COLUMN_IPADDR); -} - -BanIP::BanIP(QObject *parent) : CmdObject(parent) {} -UnBanIP::UnBanIP(QObject *parent) : CmdObject(parent) {} - -QString ListBans::cmdName() {return "ls_bans";} -QString BanIP::cmdName() {return "add_ban";} -QString UnBanIP::cmdName() {return "rm_ban";} - -void ListBans::onDel() -{ - async(ASYNC_UPDATE_BANS, PRIV_IPC); -} - -void BanIP::procIn(const QByteArray &binIn, quint8 dType) -{ - if (dType == TEXT) - { - QStringList args = parseArgs(binIn, 2); - QString ip = getParam("-ip", args); - - if (ip.isEmpty()) - { - errTxt("err: The ip address argument (-ip) was not found or is empty.\n"); - } - else if (!QHostAddress().setAddress(ip)) - { - errTxt("err: '" + ip + "' is not a valid ip address.\n"); - } - else - { - QHostAddress addr(ip); - - Query db(this); - - db.setType(Query::PUSH, TABLE_IPBANS); - db.addColumn(COLUMN_IPADDR, addr.toString()); - db.exec(); - - async(ASYNC_UPDATE_BANS, PRIV_IPC); - } - } -} - -void UnBanIP::procIn(const QByteArray &binIn, quint8 dType) -{ - if (dType == TEXT) - { - QStringList args = parseArgs(binIn, 2); - QString ip = getParam("-ip", args); - - if (ip.isEmpty()) - { - errTxt("err: The ip address argument (-ip) was not found or is empty.\n"); - } - else if (!QHostAddress().setAddress(ip)) - { - errTxt("err: '" + ip + "' is not a valid ip address.\n"); - } - else - { - QHostAddress addr(ip); - - Query db; - - db.setType(Query::DEL, TABLE_IPBANS); - db.addCondition(COLUMN_IPADDR, addr.toString()); - db.exec(); - - async(ASYNC_UPDATE_BANS, PRIV_IPC); - } - } -} diff --git a/src/commands/bans.h b/src/commands/bans.h deleted file mode 100644 index 96b9e27..0000000 --- a/src/commands/bans.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef BAN_CMDS_H -#define BAN_CMDS_H - -// This file is part of MRCI. - -// MRCI is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// MRCI is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with MRCI under the LICENSE.md file. If not, see -// . - -#include "../common.h" -#include "../cmd_object.h" -#include "table_viewer.h" - -class ListBans : public TableViewer -{ - Q_OBJECT - -private: - - void onDel(); - -public: - - static QString cmdName(); - - explicit ListBans(QObject *parent = nullptr); -}; - -//--------------------------------- - -class BanIP : public CmdObject -{ - Q_OBJECT - -public: - - static QString cmdName(); - - void procIn(const QByteArray &binIn, quint8 dType); - - explicit BanIP(QObject *parent = nullptr); -}; - -//-------------------------------- - -class UnBanIP : public CmdObject -{ - Q_OBJECT - -public: - - static QString cmdName(); - - void procIn(const QByteArray &binIn, quint8 dType); - - explicit UnBanIP(QObject *parent = nullptr); -}; - -#endif // BAN_CMDS_H diff --git a/src/commands/cast.cpp b/src/commands/cast.cpp index 9e8b6c4..641b005 100644 --- a/src/commands/cast.cpp +++ b/src/commands/cast.cpp @@ -45,15 +45,15 @@ QString ListRDonlyFlags::cmdName() {return "ls_rdonly_flags";} bool canOpenSubChannel(const QByteArray &uId, const char *override, quint64 chId, quint8 subId) { - int uLevel = channelAccessLevel(uId, override, chId); - int sLevel = lowestAcessLevel(chId, subId); + auto uLevel = channelAccessLevel(uId, override, chId); + auto sLevel = lowestAcessLevel(chId, subId); return uLevel <= sLevel; } int lowestAcessLevel(quint64 chId, quint8 subId) { - int ret = 5000; + auto ret = 5000; Query db; @@ -80,11 +80,14 @@ void OpenSubChannel::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString ch = getParam("-ch_name", args); - QString sub = getParam("-sub_name", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 4); + auto ch = getParam("-ch_name", args); + auto sub = getParam("-sub_name", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (ch.isEmpty()) { @@ -108,6 +111,8 @@ void OpenSubChannel::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + async(ASYNC_OPEN_SUBCH, PRIV_IPC, wrInt(chId, 64) + wrInt(subId, 8)); } } @@ -117,11 +122,14 @@ void CloseSubChannel::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString ch = getParam("-ch_name", args); - QString sub = getParam("-sub_name", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 4); + auto ch = getParam("-ch_name", args); + auto sub = getParam("-sub_name", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (ch.isEmpty()) { @@ -141,6 +149,8 @@ void CloseSubChannel::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + async(ASYNC_CLOSE_SUBCH, PRIV_IPC, wrInt(chId, 64) + wrInt(subId, 8)); } } @@ -168,8 +178,8 @@ void LsOpenChannels::procIn(const QByteArray &binIn, quint8 dType) for (int i = 0; i < MAX_OPEN_SUB_CHANNELS; i += BLKSIZE_SUB_CHANNEL) { - quint64 chId = rd64BitFromBlock(openSubChs + i); - quint8 subId = rd8BitFromBlock(openSubChs + (i + 8)); + auto chId = rd64BitFromBlock(openSubChs + i); + auto subId = rd8BitFromBlock(openSubChs + (i + 8)); if (chId) { @@ -183,8 +193,9 @@ void LsOpenChannels::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_SUB_CH_ID, subId); db.exec(); - QString chName = db.getData(COLUMN_CHANNEL_NAME).toString(); - QString subName = db.getData(COLUMN_SUB_CH_NAME).toString(); + auto chName = db.getData(COLUMN_CHANNEL_NAME).toString(); + auto subName = db.getData(COLUMN_SUB_CH_NAME).toString(); + QString rdOnly; if (posOfBlock(openSubChs + i, openWritableSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) == -1) @@ -233,6 +244,8 @@ void PingPeers::procIn(const QByteArray &binIn, quint8 dType) { if (rd8BitFromBlock(activeUpdate) == 0) { + retCode = INVALID_PARAMS; + errTxt("err: You don't currently have any active update sub-channels open. sending a ping request is pointless because peers won't be able to respond.\n"); } else @@ -246,11 +259,14 @@ void AddRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString subId = getParam("-sub_id", args); - QString level = getParam("-level", args); - quint64 chId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto subId = getParam("-sub_id", args); + auto level = getParam("-level", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -290,7 +306,9 @@ void AddRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray frame = wrInt(chId, 64) + wrInt(subId.toUInt(), 8) + wrInt(level.toUInt(), 8); + retCode = NO_ERRORS; + + auto frame = wrInt(chId, 64) + wrInt(subId.toUInt(), 8) + wrInt(level.toUInt(), 8); Query db(this); @@ -309,11 +327,14 @@ void RemoveRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString subId = getParam("-sub_id", args); - QString level = getParam("-level", args); - quint64 chId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto subId = getParam("-sub_id", args); + auto level = getParam("-level", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -353,7 +374,9 @@ void RemoveRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray frame = wrInt(chId, 64) + wrInt(subId.toUInt(), 8) + wrInt(level.toUInt(), 8); + retCode = NO_ERRORS; + + auto frame = wrInt(chId, 64) + wrInt(subId.toUInt(), 8) + wrInt(level.toUInt(), 8); Query db(this); @@ -378,9 +401,12 @@ void ListRDonlyFlags::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -396,6 +422,8 @@ void ListRDonlyFlags::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + if (channelAccessLevel(rdFromBlock(userId, BLKSIZE_USER_ID), chOwnerOverride, chId) > REGULAR) { TableViewer::procIn(toTEXT("-" + QString(COLUMN_CHANNEL_NAME) + " " + chName + " -" + QString(COLUMN_LOWEST_LEVEL) + " " + QString::number(PUBLIC)), dType); diff --git a/src/commands/certs.cpp b/src/commands/certs.cpp index 39f5955..bd40a0a 100644 --- a/src/commands/certs.cpp +++ b/src/commands/certs.cpp @@ -35,8 +35,10 @@ void CertInfo::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString coName = getParam("-name", args); + auto args = parseArgs(binIn, 2); + auto coName = getParam("-name", args); + + retCode = INVALID_PARAMS; if (coName.isEmpty()) { @@ -52,6 +54,8 @@ void CertInfo::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + QString txt; QTextStream txtOut(&txt); @@ -62,7 +66,7 @@ void CertInfo::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_COMMON_NAME, coName); db.exec(); - QSslCertificate cert = toSSLCert(db.getData(COLUMN_CERT).toByteArray()); + auto cert = toSSLCert(db.getData(COLUMN_CERT).toByteArray()); txtOut << "Self Signed: " << boolStr(cert.isSelfSigned()) << endl; txtOut << "Black Listed: " << boolStr(cert.isBlacklisted()) << endl; @@ -98,11 +102,12 @@ void AddCert::procIn(const QByteArray &binIn, quint8 dType) { if ((dType == TEXT) && (flags & MORE_INPUT)) { - QString ans = fromTEXT(binIn); + auto ans = fromTEXT(binIn); if (noCaseMatch("n", ans)) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else if (noCaseMatch("y", ans)) { @@ -115,12 +120,13 @@ void AddCert::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == TEXT) { - QStringList args = parseArgs(binIn, 7); - QString cert = getParam("-cert", args); - QString priv = getParam("-priv", args); - bool force = argExists("-force", args); + auto args = parseArgs(binIn, 7); + auto cert = getParam("-cert", args); + auto priv = getParam("-priv", args); + auto force = argExists("-force", args); - coName = getParam("-name", args); + coName = getParam("-name", args); + retCode = INVALID_PARAMS; QFile certFile(cert, this); QFile privFile(priv, this); @@ -167,8 +173,9 @@ void AddCert::procIn(const QByteArray &binIn, quint8 dType) } else { - certBa = certFile.readAll(); - privBa = privFile.readAll(); + retCode = NO_ERRORS; + certBa = certFile.readAll(); + privBa = privFile.readAll(); if (certExists(coName)) { @@ -216,7 +223,8 @@ void RemoveCert::procIn(const QByteArray &binIn, quint8 dType) if (noCaseMatch("n", ans)) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else if (noCaseMatch("y", ans)) { @@ -229,9 +237,11 @@ void RemoveCert::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == TEXT) { - QStringList args = parseArgs(binIn, -1); - QString name = getParam("-name", args); - bool force = argExists("-force", args); + auto args = parseArgs(binIn, -1); + auto name = getParam("-name", args); + auto force = argExists("-force", args); + + retCode = INVALID_PARAMS; if (name.isEmpty()) { @@ -247,7 +257,8 @@ void RemoveCert::procIn(const QByteArray &binIn, quint8 dType) } else { - coName = name; + retCode = NO_ERRORS; + coName = name; if (force) run(); else ask(); diff --git a/src/commands/channels.cpp b/src/commands/channels.cpp index a455ed2..97bdab8 100644 --- a/src/commands/channels.cpp +++ b/src/commands/channels.cpp @@ -130,9 +130,12 @@ void ListSubCh::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -148,6 +151,8 @@ void ListSubCh::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + if (channelAccessLevel(rdFromBlock(userId, BLKSIZE_USER_ID), chOwnerOverride, chId) > REGULAR) { TableViewer::procIn(toTEXT("-" + QString(COLUMN_CHANNEL_NAME) + " " + chName + " -" + QString(COLUMN_LOWEST_LEVEL) + " " + QString::number(PUBLIC)), dType); @@ -170,9 +175,11 @@ void SearchChannels::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 4); - QString name = getParam("-name", args); - QString chId = getParam("-id", args); + auto args = parseArgs(binIn, 4); + auto name = getParam("-name", args); + auto chId = getParam("-id", args); + + retCode = INVALID_PARAMS; if (!name.isEmpty() && !validChName(name)) { @@ -184,14 +191,20 @@ void SearchChannels::procIn(const QByteArray &binIn, quint8 dType) } else if (!name.isEmpty()) { + retCode = NO_ERRORS; + TableViewer::procIn(toTEXT("-" + QString(COLUMN_CHANNEL_NAME) + " " + name), dType); } else if (!chId.isEmpty()) { + retCode = NO_ERRORS; + TableViewer::procIn(toTEXT("-" + QString(COLUMN_CHANNEL_ID) + " " + chId), dType); } else { + retCode = NO_ERRORS; + TableViewer::procIn(QByteArray(), dType); } } @@ -208,11 +221,14 @@ void ListMembers::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString userFind = getParam("-user_name", args); - QString dispFind = getParam("-disp_name", args); - quint64 chId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto userFind = getParam("-user_name", args); + auto dispFind = getParam("-disp_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -232,7 +248,9 @@ void ListMembers::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray argsBa = toTEXT("-" + QString(COLUMN_CHANNEL_NAME) + " " + chName); + retCode = NO_ERRORS; + + auto argsBa = toTEXT("-" + QString(COLUMN_CHANNEL_NAME) + " " + chName); if (!userFind.isEmpty()) { @@ -254,9 +272,12 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -272,15 +293,17 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PUSH, TABLE_CHANNELS); db.addColumn(COLUMN_CHANNEL_NAME, chName); db.exec(); - QByteArray uId = rdFromBlock(userId, BLKSIZE_USER_ID); - QString uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); - QString dName = rdStringFromBlock(displayName, BLKSIZE_DISP_NAME); + auto uId = rdFromBlock(userId, BLKSIZE_USER_ID); + auto uName = rdStringFromBlock(userName, BLKSIZE_USER_NAME); + auto dName = rdStringFromBlock(displayName, BLKSIZE_DISP_NAME); db.setType(Query::PUSH, TABLE_CH_MEMBERS); db.addColumn(COLUMN_CHANNEL_ID, chId); @@ -289,7 +312,7 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType) db.addColumn(COLUMN_PENDING_INVITE, false); db.exec(); - QByteArray frame = createChMemberAsyncFrame(chId, uId, false, OWNER, uName, dName, chName); + auto frame = createChMemberAsyncFrame(chId, uId, false, OWNER, uName, dName, chName); async(ASYNC_NEW_CH_MEMBER, PUB_IPC_WITH_FEEDBACK, frame); } @@ -300,9 +323,12 @@ void RemoveChannel::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -322,6 +348,8 @@ void RemoveChannel::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_CHANNELS); @@ -337,10 +365,13 @@ void RenameChannel::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString chName = getParam("-ch_name", args); - QString newName = getParam("-new_name", args); - quint64 chId; + auto args = parseArgs(binIn, 4); + auto chName = getParam("-ch_name", args); + auto newName = getParam("-new_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -372,6 +403,8 @@ void RenameChannel::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_CHANNELS); @@ -390,12 +423,15 @@ void SetActiveState::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString subName = getParam("-sub_name", args); - QString state = getParam("-state", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto subName = getParam("-sub_name", args); + auto state = getParam("-state", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -435,6 +471,8 @@ void SetActiveState::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_SUB_CHANNELS); @@ -459,11 +497,14 @@ void CreateSubCh::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString chName = getParam("-ch_name", args); - QString subName = getParam("-sub_name", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 4); + auto chName = getParam("-ch_name", args); + auto subName = getParam("-sub_name", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -499,6 +540,8 @@ void CreateSubCh::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PUSH, TABLE_SUB_CHANNELS); @@ -509,7 +552,7 @@ void CreateSubCh::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_ACTIVE_UPDATE, false); db.exec(); - QByteArray frame = wrInt(chId, 64) + wrInt(subId, 8) + wrInt(REGULAR, 8) + wrInt(0, 8) + nullTermTEXT(subName); + auto frame = wrInt(chId, 64) + wrInt(subId, 8) + wrInt(REGULAR, 8) + wrInt(0, 8) + nullTermTEXT(subName); async(ASYNC_NEW_SUB_CH, PUB_IPC_WITH_FEEDBACK, frame); } @@ -520,11 +563,14 @@ void RemoveSubCh::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString chName = getParam("-ch_name", args); - QString subName = getParam("-sub_name", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 4); + auto chName = getParam("-ch_name", args); + auto subName = getParam("-sub_name", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -556,6 +602,8 @@ void RemoveSubCh::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_SUB_CHANNELS); @@ -572,12 +620,15 @@ void RenameSubCh::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString subName = getParam("-sub_name", args); - QString newName = getParam("-new_name", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto subName = getParam("-sub_name", args); + auto newName = getParam("-new_name", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -617,6 +668,8 @@ void RenameSubCh::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_SUB_CHANNELS); @@ -625,7 +678,7 @@ void RenameSubCh::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_SUB_CH_ID, subId); db.exec(); - QByteArray frame = wrInt(chId, 64) + wrInt(subId, 8) + nullTermTEXT(newName); + auto frame = wrInt(chId, 64) + wrInt(subId, 8) + nullTermTEXT(newName); async(ASYNC_RENAME_SUB_CH, PUB_IPC_WITH_FEEDBACK, frame); } @@ -636,11 +689,14 @@ void InviteToCh::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString chName = getParam("-ch_name", args); - QString uName = getParam("-user", args); - QByteArray uId; - quint64 chId; + auto args = parseArgs(binIn, 4); + auto chName = getParam("-ch_name", args); + auto uName = getParam("-user", args); + + QByteArray uId; + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -680,6 +736,8 @@ void InviteToCh::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PUSH, TABLE_CH_MEMBERS); @@ -689,7 +747,7 @@ void InviteToCh::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_ACCESS_LEVEL, REGULAR); db.exec(); - QByteArray frame = createChMemberAsyncFrame(chId, uId, true, REGULAR, uName, getDispName(uId), chName); + auto frame = createChMemberAsyncFrame(chId, uId, true, REGULAR, uName, getDispName(uId), chName); async(ASYNC_INVITED_TO_CH, PUB_IPC_WITH_FEEDBACK, frame); } @@ -700,9 +758,12 @@ void DeclineChInvite::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -718,6 +779,8 @@ void DeclineChInvite::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_CH_MEMBERS); @@ -734,9 +797,12 @@ void AcceptChInvite::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString chName = getParam("-ch_name", args); - quint64 chId; + auto args = parseArgs(binIn, 2); + auto chName = getParam("-ch_name", args); + + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -752,6 +818,8 @@ void AcceptChInvite::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_CH_MEMBERS); @@ -767,11 +835,11 @@ void AcceptChInvite::procIn(const QByteArray &binIn, quint8 dType) bool RemoveChMember::allowMemberDel(const QByteArray &uId, quint64 chId) { - QByteArray myId = rdFromBlock(userId, BLKSIZE_USER_ID); - bool ret = false; - bool leaving = (uId == myId); - int targetLevel = channelAccessLevel(uId, chId); - int myLevel = channelAccessLevel(myId, chOwnerOverride, BLKSIZE_USER_ID); + auto myId = rdFromBlock(userId, BLKSIZE_USER_ID); + auto ret = false; + auto leaving = (uId == myId); + auto targetLevel = channelAccessLevel(uId, chId); + auto myLevel = channelAccessLevel(myId, chOwnerOverride, BLKSIZE_USER_ID); if (leaving && (myLevel == OWNER)) { @@ -797,11 +865,14 @@ void RemoveChMember::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString chName = getParam("-ch_name", args); - QString uName = getParam("-user", args); - QByteArray uId; - quint64 chId; + auto args = parseArgs(binIn, 4); + auto chName = getParam("-ch_name", args); + auto uName = getParam("-user", args); + + QByteArray uId; + quint64 chId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -833,6 +904,8 @@ void RemoveChMember::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_CH_MEMBERS); @@ -847,8 +920,8 @@ void RemoveChMember::procIn(const QByteArray &binIn, quint8 dType) bool SetMemberLevel::allowLevelChange(const QByteArray &uId, int newLevel, quint64 chId) { - int targetLevel = channelAccessLevel(uId, chId); - int myLevel = channelAccessLevel(rdFromBlock(userId, BLKSIZE_USER_ID), chOwnerOverride, BLKSIZE_USER_ID); + auto targetLevel = channelAccessLevel(uId, chId); + auto myLevel = channelAccessLevel(rdFromBlock(userId, BLKSIZE_USER_ID), chOwnerOverride, BLKSIZE_USER_ID); return (newLevel >= myLevel) && (targetLevel > myLevel); } @@ -857,12 +930,15 @@ void SetMemberLevel::procIn(const QByteArray &binIn, uchar dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString uName = getParam("-user", args); - QString level = getParam("-level", args); - quint64 chId; - QByteArray uId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto uName = getParam("-user", args); + auto level = getParam("-level", args); + + quint64 chId; + QByteArray uId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -902,6 +978,8 @@ void SetMemberLevel::procIn(const QByteArray &binIn, uchar dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PULL, TABLE_CH_MEMBERS); @@ -910,8 +988,8 @@ void SetMemberLevel::procIn(const QByteArray &binIn, uchar dType) db.addCondition(COLUMN_CHANNEL_ID, chId); db.exec(); - int newLevel = level.toInt(); - QByteArray owner = db.getData(COLUMN_USER_ID).toByteArray(); + auto newLevel = level.toInt(); + auto owner = db.getData(COLUMN_USER_ID).toByteArray(); db.setType(Query::UPDATE, TABLE_CH_MEMBERS); db.addColumn(COLUMN_ACCESS_LEVEL, newLevel); @@ -939,12 +1017,15 @@ void SetSubAcessLevel::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString chName = getParam("-ch_name", args); - QString subName = getParam("-sub_name", args); - QString level = getParam("-level", args); - quint64 chId; - quint8 subId; + auto args = parseArgs(binIn, 6); + auto chName = getParam("-ch_name", args); + auto subName = getParam("-sub_name", args); + auto level = getParam("-level", args); + + quint64 chId; + quint8 subId; + + retCode = INVALID_PARAMS; if (chName.isEmpty()) { @@ -984,6 +1065,8 @@ void SetSubAcessLevel::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_SUB_CHANNELS); @@ -1001,8 +1084,10 @@ void OwnerOverride::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString state = getParam("-state", args); + auto args = parseArgs(binIn, 2); + auto state = getParam("-state", args); + + retCode = INVALID_PARAMS; if (state.isEmpty()) { @@ -1014,6 +1099,8 @@ void OwnerOverride::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + wr8BitToBlock(static_cast(state.toUInt()), chOwnerOverride); } } diff --git a/src/commands/cmd_ranks.cpp b/src/commands/cmd_ranks.cpp index 2d5525a..20fbfcd 100644 --- a/src/commands/cmd_ranks.cpp +++ b/src/commands/cmd_ranks.cpp @@ -49,10 +49,12 @@ void AssignCmdRank::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 6); - QString cmdName = getParam("-command", args); - QString mod = getParam("-mod", args); - QString rank = getParam("-rank", args); + auto args = parseArgs(binIn, 6); + auto cmdName = getParam("-command", args); + auto mod = getParam("-mod", args); + auto rank = getParam("-rank", args); + + retCode = INVALID_PARAMS; if (cmdName.isEmpty()) { @@ -84,6 +86,8 @@ void AssignCmdRank::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PUSH, TABLE_CMD_RANKS); @@ -101,9 +105,11 @@ void RemoveCmdRank::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString cmdName = getParam("-command", args); - QString mod = getParam("-mod", args); + auto args = parseArgs(binIn, 4); + auto cmdName = getParam("-command", args); + auto mod = getParam("-mod", args); + + retCode = INVALID_PARAMS; if (cmdName.isEmpty()) { @@ -127,6 +133,8 @@ void RemoveCmdRank::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_CMD_RANKS); diff --git a/src/commands/fs.cpp b/src/commands/fs.cpp index 28c0b71..9b04e13 100644 --- a/src/commands/fs.cpp +++ b/src/commands/fs.cpp @@ -30,7 +30,7 @@ QByteArray toFILE_INFO(const QFileInfo &info) // note: the integer data found in flags, modTime, createTime and fileSize // are formatted in little endian byte order (unsigned). - char flags = 0; + auto flags = 0x00; if (info.isFile()) flags |= IS_FILE; if (info.isDir()) flags |= IS_DIR; @@ -98,18 +98,28 @@ void DownloadFile::onTerminate() void DownloadFile::sendChunk() { - QByteArray data = file->read(LOCAL_BUFFSIZE); + auto data = file->read(LOCAL_BUFFSIZE); - dataSent += data.size(); - - emit procOut(data, GEN_FILE); - - mainTxt(QString::number(dataSent) + " / " + QString::number(len) + "\n"); - - if ((dataSent >= len) || file->atEnd()) + if (file->error() != QFile::NoError) { + retCode = EXECUTION_FAIL; + + errTxt("err: File IO failure: " + file->errorString() + ".\n"); onTerminate(); } + else + { + dataSent += data.size(); + + emit procOut(data, GEN_FILE); + + mainTxt(QString::number(dataSent) + " / " + QString::number(len) + "\n"); + + if ((dataSent >= len) || file->atEnd()) + { + onTerminate(); + } + } } void DownloadFile::procIn(const QByteArray &binIn, quint8 dType) @@ -126,10 +136,12 @@ void DownloadFile::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == GEN_FILE) { - QStringList args = parseArgs(binIn, 11); - QString path = getParam("-remote_file", args); - QString offStr = getParam("-offset", args); - QString lenStr = getParam("-len", args); + auto args = parseArgs(binIn, 11); + auto path = getParam("-remote_file", args); + auto offStr = getParam("-offset", args); + auto lenStr = getParam("-len", args); + + retCode = INVALID_PARAMS; file->setFileName(path); @@ -155,6 +167,8 @@ void DownloadFile::procIn(const QByteArray &binIn, quint8 dType) } else if (!file->open(QFile::ReadOnly)) { + retCode = EXECUTION_FAIL; + errTxt("err: Unable to open the remote file for reading. reason: " + file->errorString() + "\n"); } else @@ -162,6 +176,7 @@ void DownloadFile::procIn(const QByteArray &binIn, quint8 dType) len = lenStr.toLongLong(); ssMode = argExists("-single_step", args); paramsSet = true; + retCode = NO_ERRORS; flags |= MORE_INPUT; if ((len == 0) || (len > file->size())) @@ -192,19 +207,29 @@ void UploadFile::onTerminate() void UploadFile::wrToFile(const QByteArray &data) { - dataReceived += data.size(); + auto written = file->write(data); - file->write(data); - - mainTxt(QString::number(dataReceived) + " / " + QString::number(len) + "\n"); - - if (dataReceived >= len) + if (written == -1) { + retCode = EXECUTION_FAIL; + + errTxt("err: File IO failure: " + file->errorString() + ".\n"); onTerminate(); } - else if (ssMode) + else { - emit procOut(QByteArray(), GEN_FILE); + dataReceived += written; + + mainTxt(QString::number(dataReceived) + " / " + QString::number(len) + "\n"); + + if (dataReceived >= len) + { + onTerminate(); + } + else if (ssMode) + { + emit procOut(QByteArray(), GEN_FILE); + } } } @@ -225,6 +250,8 @@ void UploadFile::run() } else { + retCode = EXECUTION_FAIL; + errTxt("err: Unable to open the remote file for writing. reason: " + file->errorString() + "\n"); onTerminate(); } @@ -234,7 +261,7 @@ void UploadFile::procIn(const QByteArray &binIn, quint8 dType) { if (((dType == GEN_FILE) || (dType == TEXT)) && confirm) { - QString ans = fromTEXT(binIn); + auto ans = fromTEXT(binIn); if (noCaseMatch("y", ans)) { @@ -244,6 +271,8 @@ void UploadFile::procIn(const QByteArray &binIn, quint8 dType) } else if (noCaseMatch("n", ans)) { + retCode = ABORTED; + onTerminate(); } else @@ -257,10 +286,12 @@ void UploadFile::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == GEN_FILE) { - QStringList args = parseArgs(binIn, 11); - QString lenStr = getParam("-len", args); - QString offStr = getParam("-offset", args); - QString dst = getParam("-remote_file", args); + auto args = parseArgs(binIn, 11); + auto lenStr = getParam("-len", args); + auto offStr = getParam("-offset", args); + auto dst = getParam("-remote_file", args); + + retCode = INVALID_PARAMS; if (dst.isEmpty()) { @@ -289,11 +320,12 @@ void UploadFile::procIn(const QByteArray &binIn, quint8 dType) mode = QFile::ReadWrite; } - force = argExists("-force", args); - ssMode = argExists("-single_step", args); - len = lenStr.toLongLong(); - offs = offStr.toLongLong(); - flags |= MORE_INPUT; + force = argExists("-force", args); + ssMode = argExists("-single_step", args); + len = lenStr.toLongLong(); + offs = offStr.toLongLong(); + retCode = NO_ERRORS; + flags |= MORE_INPUT; file->setFileName(dst); @@ -333,6 +365,11 @@ void Delete::run() ok = QDir(path).removeRecursively(); } + if (!ok) + { + retCode = EXECUTION_FAIL; + } + if (!ok && !info.exists()) { errTxt("err: '" + path + "' already does not exists.\n"); @@ -351,7 +388,7 @@ void Delete::procIn(const QByteArray &binIn, uchar dType) { if ((flags & MORE_INPUT) && (dType == TEXT)) { - QString ans = fromTEXT(binIn); + auto ans = fromTEXT(binIn); if (noCaseMatch("y", ans)) { @@ -361,7 +398,8 @@ void Delete::procIn(const QByteArray &binIn, uchar dType) } else if (noCaseMatch("n", ans)) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else { @@ -370,9 +408,10 @@ void Delete::procIn(const QByteArray &binIn, uchar dType) } else if (dType == TEXT) { - QStringList args = parseArgs(binIn, 3); + auto args = parseArgs(binIn, 3); - path = getParam("-path", args); + path = getParam("-path", args); + retCode = INVALID_PARAMS; if (path.isEmpty()) { @@ -430,7 +469,7 @@ bool Copy::matchingVolumeMatters() bool Copy::permissionsOk(bool dstExists) { - bool ret = true; + auto ret = true; if (!QFileInfo(srcPath).isReadable()) { @@ -445,6 +484,15 @@ bool Copy::permissionsOk(bool dstExists) ret = false; } + if (ret) + { + retCode = NO_ERRORS; + } + else + { + retCode = EXECUTION_FAIL; + } + return ret; } @@ -471,7 +519,11 @@ void Copy::run() else { errTxt("err: Unable to re-create the source symlink at the destination path. writing to the path is not possible/denied.\n"); - onTerminate(); + + if (queue.isEmpty()) + { + onTerminate(); + } } } else if (QFileInfo(srcPath).isDir()) @@ -486,12 +538,20 @@ void Copy::run() if (!dst->open(QFile::WriteOnly | QFile::Truncate)) { errTxt("err: Unable to open the destination file '" + dstPath + "' for writing. reason: " + dst->errorString() + "\n"); - onTerminate(); + + if (queue.isEmpty()) + { + onTerminate(); + } } else if (!src->open(QFile::ReadOnly)) { errTxt("err: Unable to open the source file '" + srcPath + "' for reading. reason: " + src->errorString() + "\n"); - onTerminate(); + + if (queue.isEmpty()) + { + onTerminate(); + } } else { @@ -526,7 +586,7 @@ void Copy::procIn(const QByteArray &binIn, uchar dType) } else if (!queue.isEmpty()) { - QPair srcToDst = queue.takeFirst(); + auto srcToDst = queue.takeFirst(); srcPath = srcToDst.first; dstPath = srcToDst.second; @@ -535,7 +595,7 @@ void Copy::procIn(const QByteArray &binIn, uchar dType) src->setFileName(srcPath); dst->setFileName(dstPath); - bool exists = QFileInfo(dstPath).exists(); + auto exists = QFileInfo(dstPath).exists(); if (exists && !yToAll && !nToAll) { @@ -556,7 +616,7 @@ void Copy::procIn(const QByteArray &binIn, uchar dType) } else if ((dType == TEXT) && (flags & MORE_INPUT)) { - QString ans = fromTEXT(binIn); + auto ans = fromTEXT(binIn); if (noCaseMatch("y", ans)) { @@ -611,14 +671,15 @@ void Copy::procIn(const QByteArray &binIn, uchar dType) { onTerminate(); - QStringList args = parseArgs(binIn, 5); - bool force = argExists("-force", args); + auto args = parseArgs(binIn, 5); + auto force = argExists("-force", args); srcPath = getParam("-src", args); dstPath = getParam("-dst", args); oriSrcPath = srcPath; + retCode = INVALID_PARAMS; - bool dstExists = QFileInfo(dstPath).exists(); + auto dstExists = QFileInfo(dstPath).exists(); src->setFileName(srcPath); dst->setFileName(dstPath); @@ -665,6 +726,8 @@ void Move::runOnMatchingVolume() if (!QFile::rename(srcPath, dstPath)) { + retCode = EXECUTION_FAIL; + errTxt("err: Unable to do move operation. it's likely the command failed to remove the existing destination object or writing to the path is not possible/denied.\n"); onTerminate(); } @@ -685,7 +748,7 @@ void Move::preFinish() bool Move::permissionsOk(bool dstExists) { - bool ret = true; + auto ret = true; if (!QFileInfo(srcPath).isReadable() || !QFileInfo(srcPath).isWritable()) { @@ -700,6 +763,15 @@ bool Move::permissionsOk(bool dstExists) ret = false; } + if (ret) + { + retCode = NO_ERRORS; + } + else + { + retCode = EXECUTION_FAIL; + } + return ret; } @@ -707,11 +779,13 @@ void MakePath::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString path = getParam("-path", args); + auto args = parseArgs(binIn, 2); + auto path = getParam("-path", args); if (path.isEmpty()) { + retCode = INVALID_PARAMS; + errTxt("err: The path argument (-path) was not found or is empty.\n"); } else @@ -725,10 +799,10 @@ void ListFiles::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString path = getParam("-path", args); - bool infoFrame = argExists("-info_frame", args); - bool noHidden = argExists("-no_hidden", args); + auto args = parseArgs(binIn, 4); + auto path = getParam("-path", args); + auto infoFrame = argExists("-info_frame", args); + auto noHidden = argExists("-no_hidden", args); if (path.isEmpty()) { @@ -737,6 +811,8 @@ void ListFiles::procIn(const QByteArray &binIn, quint8 dType) QFileInfo pathInfo(path); + retCode = INVALID_PARAMS; + if (!pathInfo.exists()) { errTxt("err: '" + path + "' does not exists.\n"); @@ -751,6 +827,8 @@ void ListFiles::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + QDir dir(path); if (noHidden) @@ -789,12 +867,14 @@ void FileInfo::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 3); - QString path = getParam("-path", args); - bool infoFrame = argExists("-info_frame", args); + auto args = parseArgs(binIn, 3); + auto path = getParam("-path", args); + auto infoFrame = argExists("-info_frame", args); QFileInfo info(path); + retCode = INVALID_PARAMS; + if (path.isEmpty()) { errTxt("err: The path argument (-path) was not found or is empty.\n"); @@ -805,6 +885,8 @@ void FileInfo::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + if (infoFrame) { emit procOut(toFILE_INFO(info), FILE_INFO); @@ -841,8 +923,10 @@ void ChangeDir::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 3); - QString path = getParam("-path", args); + auto args = parseArgs(binIn, 3); + auto path = getParam("-path", args); + + retCode = INVALID_PARAMS; if (path.isEmpty()) { @@ -858,6 +942,8 @@ void ChangeDir::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + QDir::setCurrent(path); mainTxt(QDir::currentPath() + "\n"); @@ -931,11 +1017,12 @@ void Tree::procIn(const QByteArray &binIn, quint8 dType) } else if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString path = getParam("-path", args); + auto args = parseArgs(binIn, 4); + auto path = getParam("-path", args); infoFrames = argExists("-info_frame", args); noHidden = argExists("-no_hidden", args); + retCode = INVALID_PARAMS; if (path.isEmpty()) { @@ -958,6 +1045,8 @@ void Tree::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + printList(path); } } diff --git a/src/commands/info.cpp b/src/commands/info.cpp index b8f023b..a6f1530 100644 --- a/src/commands/info.cpp +++ b/src/commands/info.cpp @@ -65,8 +65,7 @@ void ListCommands::onIPCConnected() { for (auto&& cmdName : list) { - QByteArray frame; - QByteArray genType = QByteArray(1, 0x00); + auto genType = QByteArray(1, 0x00); if (cmdName == DownloadFile::cmdName()) { @@ -81,6 +80,8 @@ void ListCommands::onIPCConnected() genType = QByteArray(1, GEN_UPLOAD); } + QByteArray frame; + frame.append(QByteArray(2, 0x00)); frame.append(genType); frame.append(fixedToTEXT(cmdName, BLKSIZE_CMD_NAME)); diff --git a/src/commands/mods.cpp b/src/commands/mods.cpp index 84026b0..6e8cb1f 100644 --- a/src/commands/mods.cpp +++ b/src/commands/mods.cpp @@ -22,26 +22,28 @@ ListMods::ListMods(QObject *parent) : TableViewer(parent) addTableColumn(TABLE_MODULES, COLUMN_MOD_MAIN); } -UploadMod::UploadMod(QObject *parent) : CmdObject(parent) {} -DelMod::DelMod(QObject *parent) : CmdObject(parent) {} +AddMod::AddMod(QObject *parent) : CmdObject(parent) {} +DelMod::DelMod(QObject *parent) : CmdObject(parent) {} -QString ListMods::cmdName() {return "ls_mods";} -QString DelMod::cmdName() {return "rm_mod";} -QString UploadMod::cmdName() {return "add_mod";} +QString ListMods::cmdName() {return "ls_mods";} +QString DelMod::cmdName() {return "rm_mod";} +QString AddMod::cmdName() {return "add_mod";} -bool UploadMod::isExecutable(const QString &path) +bool AddMod::isExecutable(const QString &path) { QFileInfo info(expandEnvVariables(path)); return info.exists() && info.isExecutable(); } -void UploadMod::procIn(const QByteArray &binIn, quint8 dType) +void AddMod::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString path = getParam("-mod_path", args); + auto args = parseArgs(binIn, 2); + auto path = getParam("-mod_path", args); + + retCode = INVALID_PARAMS; if (path.isEmpty()) { @@ -61,6 +63,8 @@ void UploadMod::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::PUSH, TABLE_MODULES); @@ -76,8 +80,10 @@ void DelMod::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString path = getParam("-mod_path", args); + auto args = parseArgs(binIn, 2); + auto path = getParam("-mod_path", args); + + retCode = INVALID_PARAMS; if (path.isEmpty()) { @@ -93,6 +99,8 @@ void DelMod::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::DEL, TABLE_MODULES); diff --git a/src/commands/mods.h b/src/commands/mods.h index d7625ab..9c97f66 100644 --- a/src/commands/mods.h +++ b/src/commands/mods.h @@ -24,7 +24,7 @@ QString rmFileSuffix(const QString &filePath); bool validFileOnlyName(const QString &fileName); -class UploadMod : public CmdObject +class AddMod : public CmdObject { Q_OBJECT @@ -38,7 +38,7 @@ public: void procIn(const QByteArray &binIn, quint8 dType); - explicit UploadMod(QObject *parent = nullptr); + explicit AddMod(QObject *parent = nullptr); }; //------------------------------- diff --git a/src/commands/p2p.cpp b/src/commands/p2p.cpp index 5265a43..a1d3ffd 100644 --- a/src/commands/p2p.cpp +++ b/src/commands/p2p.cpp @@ -30,6 +30,8 @@ QString LsP2P::cmdName() {return "ls_p2p";} void ToPeer::procIn(const QByteArray &binIn, quint8 dType) { + retCode = INVALID_PARAMS; + if (binIn.size() >= BLKSIZE_SESSION_ID) { errTxt("err: The p2p data does not contain a session id header.\n"); @@ -40,11 +42,13 @@ void ToPeer::procIn(const QByteArray &binIn, quint8 dType) } else { - quint32 len = static_cast(binIn.size()); - QByteArray dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); - QByteArray src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); - QByteArray data = rdFromBlock(binIn.data() + BLKSIZE_SESSION_ID, len - BLKSIZE_SESSION_ID); - QByteArray typeBa = wrInt(dType, 8); + retCode = NO_ERRORS; + + auto len = static_cast(binIn.size()); + auto dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); + auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); + auto data = rdFromBlock(binIn.data() + BLKSIZE_SESSION_ID, len - BLKSIZE_SESSION_ID); + auto typeBa = wrInt(dType, 8); async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + data); } @@ -54,6 +58,8 @@ void P2PRequest::procIn(const QByteArray &binIn, quint8 dType) { if (dType == SESSION_ID) { + retCode = INVALID_PARAMS; + if (binIn.size() != BLKSIZE_SESSION_ID) { errTxt("err: The given client session id does not equal " + QString::number(BLKSIZE_SESSION_ID) + " bytes.\n"); @@ -68,9 +74,11 @@ void P2PRequest::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); - QByteArray src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); - QByteArray typeBa = wrInt(P2P_REQUEST, 8); + retCode = NO_ERRORS; + + auto dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); + auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); + auto typeBa = wrInt(P2P_REQUEST, 8); async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + createPeerInfoFrame()); } @@ -81,6 +89,8 @@ void P2POpen::procIn(const QByteArray &binIn, quint8 dType) { if (dType == SESSION_ID) { + retCode = INVALID_PARAMS; + if (binIn.size() != BLKSIZE_SESSION_ID) { errTxt("err: The given client session id does not equal " + QString::number(BLKSIZE_SESSION_ID) + " bytes.\n"); @@ -95,9 +105,11 @@ void P2POpen::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); - QByteArray src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); - QByteArray typeBa = wrInt(P2P_OPEN, 8); + retCode = NO_ERRORS; + + auto dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); + auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); + auto typeBa = wrInt(P2P_OPEN, 8); async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + dst); } @@ -108,6 +120,8 @@ void P2PClose::procIn(const QByteArray &binIn, quint8 dType) { if (dType == SESSION_ID) { + retCode = INVALID_PARAMS; + if (binIn.size() != BLKSIZE_SESSION_ID) { errTxt("err: The given client session id does not equal " + QString::number(BLKSIZE_SESSION_ID) + " bytes.\n"); @@ -119,9 +133,11 @@ void P2PClose::procIn(const QByteArray &binIn, quint8 dType) } else { - QByteArray dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); - QByteArray src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); - QByteArray typeBa = wrInt(P2P_CLOSE, 8); + retCode = NO_ERRORS; + + auto dst = rdFromBlock(binIn.data(), BLKSIZE_SESSION_ID); + auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); + auto typeBa = wrInt(P2P_CLOSE, 8); async(P2P_CLOSE, PUB_IPC, dst + src + typeBa + dst); } @@ -153,8 +169,9 @@ void LsP2P::procIn(const QByteArray &binIn, quint8 dType) if (dType == TEXT) { - QList peerIds = lsBlocks(p2pAccepted, MAX_P2P_LINKS, BLKSIZE_SESSION_ID) + - lsBlocks(p2pPending, MAX_P2P_LINKS, BLKSIZE_SESSION_ID); + auto peerIds = lsBlocks(p2pAccepted, MAX_P2P_LINKS, BLKSIZE_SESSION_ID) + + lsBlocks(p2pPending, MAX_P2P_LINKS, BLKSIZE_SESSION_ID); + QList tableData; QStringList separators; QList justLens; @@ -170,7 +187,8 @@ void LsP2P::procIn(const QByteArray &binIn, quint8 dType) for (auto&& peerId: peerIds) { - QString pending = "0"; + auto pending = "0"; + QStringList columnData; if (posOfBlock(peerId.data(), p2pPending, MAX_P2P_LINKS, BLKSIZE_SESSION_ID) != -1) diff --git a/src/commands/table_viewer.cpp b/src/commands/table_viewer.cpp index 085c669..5689e6e 100644 --- a/src/commands/table_viewer.cpp +++ b/src/commands/table_viewer.cpp @@ -96,7 +96,7 @@ void TableViewer::addWhereConds(const QStringList &userArgs) for (int i = 0; i < columns.size(); ++i) { - QString value = getParam("-" + columns[i], userArgs); + auto value = getParam("-" + columns[i], userArgs); if (!value.isEmpty()) { @@ -190,8 +190,8 @@ QList TableViewer::getColumnLens(const QList &data) void TableViewer::dispData() { - QList tableRows = toStrings(rdQuery.allData()); - QList lens = getColumnLens(columnRows + tableRows); + auto tableRows = toStrings(rdQuery.allData()); + auto lens = getColumnLens(columnRows + tableRows); for (auto&& row: columnRows + tableRows) { @@ -210,7 +210,7 @@ void TableViewer::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString text = fromTEXT(binIn).toLower(); + auto text = fromTEXT(binIn).toLower(); if (text == "y") { diff --git a/src/commands/users.cpp b/src/commands/users.cpp index aaca888..91a2701 100644 --- a/src/commands/users.cpp +++ b/src/commands/users.cpp @@ -73,10 +73,13 @@ void LockUser::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString uName = getParam("-user", args); - QString state = getParam("-state", args); - QByteArray uId; + auto args = parseArgs(binIn, 4); + auto uName = getParam("-user", args); + auto state = getParam("-state", args); + + QByteArray uId; + + retCode = INVALID_PARAMS; if (uName.isEmpty()) { @@ -104,6 +107,8 @@ void LockUser::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_USERS); @@ -128,19 +133,25 @@ void CreateUser::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString password = fromTEXT(binIn); + auto password = fromTEXT(binIn); + + QString errMsg; if (password.isEmpty()) { + retCode = ABORTED; + clear(); } - else if (!validPassword(password)) + else if (!acceptablePw(password, newName, dispName, email, &errMsg)) { - errTxt("err: Invalid password. it must be 8-200 chars long containing numbers, mixed case letters and special chars.\n\n"); + errTxt(errMsg + "\n"); privTxt("Enter a new password (leave blank to cancel): "); } else if (!createUser(newName, email, dispName, password)) { + retCode = INVALID_PARAMS; + errTxt("err: The requested User name already exists.\n"); clear(); } @@ -151,11 +162,12 @@ void CreateUser::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 6); + auto args = parseArgs(binIn, 6); dispName = getParam("-disp", args); newName = getParam("-name", args); email = getParam("-email", args); + retCode = INVALID_PARAMS; if (newName.isEmpty()) { @@ -169,6 +181,14 @@ void CreateUser::procIn(const QByteArray &binIn, quint8 dType) { errTxt("err: Invalid username. it must be 2-24 chars long and contain no spaces.\n"); } + else if (noCaseMatch(DEFAULT_ROOT_USER, newName)) + { + errTxt("err: '" + QString(DEFAULT_ROOT_USER) + "' is a reserved keyword. invalid for use as a username.\n"); + } + else if (validEmailAddr(newName)) + { + errTxt("err: Invaild username. it looks like an email address.\n"); + } else if (!validEmailAddr(email)) { errTxt("err: Invalid email address. it must contain a '@' symbol along with a vaild host address and user name that contain no spaces. it must also be less than 64 chars long.\n"); @@ -187,7 +207,8 @@ void CreateUser::procIn(const QByteArray &binIn, quint8 dType) } else { - flags |= MORE_INPUT; + retCode = NO_ERRORS; + flags |= MORE_INPUT; privTxt("Enter a new password (leave blank to cancel): "); } @@ -221,7 +242,7 @@ void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString ans = fromTEXT(binIn); + auto ans = fromTEXT(binIn); if (noCaseMatch("y", ans)) { @@ -229,7 +250,8 @@ void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) } else if (noCaseMatch("n", ans)) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } else { @@ -238,17 +260,15 @@ void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) } else { - QStringList args = parseArgs(binIn, 2); - QString uName = getParam("-name", args); + auto args = parseArgs(binIn, 2); + auto uName = getParam("-name", args); + + retCode = INVALID_PARAMS; if (uName.isEmpty()) { errTxt("err: User name argument (-name) not found or is empty.\n"); } - else if (noCaseMatch(ROOT_USER, uName)) - { - errTxt("err: Unable to delete protected user: '" + QString(ROOT_USER) + "'\n"); - } else if (!validUserName(uName)) { errTxt("err: Invalid username.\n"); @@ -257,6 +277,10 @@ void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) { errTxt("err: The requested user name does not exists.\n"); } + else if (rootUserId() == uId) + { + errTxt("err: Unable to delete root user: '" + uName + "'\n"); + } else if (isChOwner(uId)) { errTxt("err: The requested user name is the owner of one or more channels. assign new owners for these channels before attempting to delete this account.\n"); @@ -267,6 +291,8 @@ void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + if (argExists("-force", args)) { rm(); @@ -284,10 +310,13 @@ void ChangeUserRank::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString uName = getParam("-user", args); - QString rank = getParam("-rank", args); - QByteArray uId; + auto args = parseArgs(binIn, 4); + auto uName = getParam("-user", args); + auto rank = getParam("-rank", args); + + QByteArray uId; + + retCode = INVALID_PARAMS; if (uName.isEmpty()) { @@ -297,10 +326,6 @@ void ChangeUserRank::procIn(const QByteArray &binIn, quint8 dType) { errTxt("err: New rank argument (-rank) not found or is empty.\n"); } - else if (noCaseMatch(ROOT_USER, uName)) - { - errTxt("err: You are not allowed to change the rank of protected user: '" + QString(ROOT_USER) + "'\n"); - } else if (!validUserName(uName)) { errTxt("err: Invalid username.\n"); @@ -321,12 +346,18 @@ void ChangeUserRank::procIn(const QByteArray &binIn, quint8 dType) { errTxt("err: The requested user account does not exists.\n"); } + else if (rootUserId() == uId) + { + errTxt("err: You are not allowed to change the rank of root user: '" + uName + "'\n"); + } else if (!canModifyUser(uId, rd32BitFromBlock(hostRank), false)) { errTxt("err: The target user out ranks you or is equal to your own rank. access denied.\n"); } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_USERS); @@ -345,15 +376,18 @@ void ChangePassword::procIn(const QByteArray &binIn, quint8 dType) { if (flags & MORE_INPUT) { - QString password = fromTEXT(binIn); + auto password = fromTEXT(binIn); + + QString errMsg; if (password.isEmpty()) { - flags &= ~MORE_INPUT; + retCode = ABORTED; + flags &= ~MORE_INPUT; } - else if (!validPassword(password)) + else if (!acceptablePw(password, rdFromBlock(userId, BLKSIZE_USER_ID), &errMsg)) { - errTxt("err: Invalid password. it must be 8-200 chars long containing numbers, mixed case letters and special chars.\n\n"); + errTxt(errMsg + "\n"); privTxt("Enter a new password (leave blank to cancel): "); } else @@ -376,8 +410,10 @@ void ChangeUsername::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString newName = getParam("-new_name", args); + auto args = parseArgs(binIn, 2); + auto newName = getParam("-new_name", args); + + retCode = INVALID_PARAMS; if (newName.isEmpty()) { @@ -387,14 +423,24 @@ void ChangeUsername::procIn(const QByteArray &binIn, quint8 dType) { errTxt("err: Invalid username. it must be 2-24 chars long and contain no spaces.\n"); } + else if (noCaseMatch(DEFAULT_ROOT_USER, newName)) + { + errTxt("err: '" + QString(DEFAULT_ROOT_USER) + "' is a reserved keyword. invalid for use as a username.\n"); + } + else if (validEmailAddr(newName)) + { + errTxt("err: Invaild username. it looks like an email address.\n"); + } else if (userExists(newName)) { errTxt("err: The requested user name already exists.\n"); } else { - QByteArray uId = rdFromBlock(userId, BLKSIZE_USER_ID); - QByteArray newNameBa = fixedToTEXT(newName, BLKSIZE_USER_NAME); + retCode = NO_ERRORS; + + auto uId = rdFromBlock(userId, BLKSIZE_USER_ID); + auto newNameBa = fixedToTEXT(newName, BLKSIZE_USER_NAME); Query db(this); @@ -412,8 +458,10 @@ void ChangeDispName::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString name = getParam("-new_name", args).trimmed(); + auto args = parseArgs(binIn, 2); + auto name = getParam("-new_name", args).trimmed(); + + retCode = INVALID_PARAMS; if (argExists("-new_name", args)) { @@ -425,10 +473,12 @@ void ChangeDispName::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + Query db(this); - QByteArray uId = rdFromBlock(userId, BLKSIZE_USER_ID); - QByteArray newNameBa = fixedToTEXT(name, BLKSIZE_DISP_NAME); + auto uId = rdFromBlock(userId, BLKSIZE_USER_ID); + auto newNameBa = fixedToTEXT(name, BLKSIZE_DISP_NAME); db.setType(Query::UPDATE, TABLE_USERS); db.addColumn(COLUMN_DISPLAY_NAME, name); @@ -444,6 +494,8 @@ void OverWriteEmail::procArgs(const QString &uName, const QString &newEmail, boo { QByteArray uId; + retCode = INVALID_PARAMS; + if (newEmail.isEmpty()) { errTxt("err: New email address (-new_email) argument was not found or is empty.\n"); @@ -474,6 +526,8 @@ void OverWriteEmail::procArgs(const QString &uName, const QString &newEmail, boo } else { + retCode = NO_ERRORS; + Query db(this); db.setType(Query::UPDATE, TABLE_USERS); @@ -490,9 +544,9 @@ void OverWriteEmail::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString uName = getParam("-user", args); - QString newEmail = getParam("-new_email", args); + auto args = parseArgs(binIn, 4); + auto uName = getParam("-user", args); + auto newEmail = getParam("-new_email", args); procArgs(uName, newEmail, false); } @@ -502,8 +556,8 @@ void ChangeEmail::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 2); - QString newEmail = getParam("-new_email", args); + auto args = parseArgs(binIn, 2); + auto newEmail = getParam("-new_email", args); procArgs(rdStringFromBlock(userName, BLKSIZE_USER_NAME), newEmail, true); } @@ -523,10 +577,13 @@ void PasswordChangeRequest::procIn(const QByteArray &binIn, quint8 dType) { if (dType == TEXT) { - QStringList args = parseArgs(binIn, 4); - QString uName = getParam("-user", args); - QString req = getParam("-req", args); - QByteArray uId; + auto args = parseArgs(binIn, 4); + auto uName = getParam("-user", args); + auto req = getParam("-req", args); + + QByteArray uId; + + retCode = INVALID_PARAMS; if (uName.isEmpty()) { @@ -554,6 +611,8 @@ void PasswordChangeRequest::procIn(const QByteArray &binIn, quint8 dType) } else { + retCode = NO_ERRORS; + exec(uId, static_cast(req.toUInt())); } } diff --git a/src/common.cpp b/src/common.cpp index f7743a5..cf31b91 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -226,6 +226,69 @@ bool validModPath(const QString &modPath) return ret; } +bool acceptablePw(const QString &pw, const QString &uName, const QString &dispName, const QString &email, QString *errMsg) +{ + auto ret = validPassword(pw); + + if (!ret) + { + *errMsg = "err: Invalid password. it must be between 8-200 chars long containing numbers, mixed case letters and special chars.\n"; + } + else if (ret && !email.isEmpty()) + { + if (pw.contains(email, Qt::CaseInsensitive)) + { + *errMsg = "err: Invalid password. it contains your email address.\n"; ret = false; + } + } + else if (ret && !uName.isEmpty()) + { + if (pw.contains(uName, Qt::CaseInsensitive)) + { + *errMsg = "err: Invalid password. it contains your user name.\n"; ret = false; + } + } + else if (ret && !dispName.isEmpty()) + { + if (pw.contains(dispName, Qt::CaseInsensitive)) + { + *errMsg = "err: Invalid password. it contains your display name.\n"; ret = false; + } + } + + return ret; +} + +bool acceptablePw(const QString &pw, const QByteArray &uId, QString *errMsg) +{ + auto ret = false; + + if (auth(uId, pw, TABLE_USERS)) + { + *errMsg = "err: Invaild password. you cannot re-use your old password.\n"; + } + else + { + + Query db; + + db.setType(Query::PULL, TABLE_USERS); + db.addColumn(COLUMN_EMAIL); + db.addColumn(COLUMN_USERNAME); + db.addColumn(COLUMN_DISPLAY_NAME); + db.addCondition(COLUMN_USER_ID, uId); + db.exec(); + + auto email = db.getData(COLUMN_EMAIL).toString(); + auto uName = db.getData(COLUMN_USERNAME).toString(); + auto dName = db.getData(COLUMN_DISPLAY_NAME).toString(); + + ret = acceptablePw(pw, uName, dName, email, errMsg); + } + + return ret; +} + bool validPassword(const QString &pw) { bool ret = false; @@ -656,6 +719,18 @@ QString getDispName(const QByteArray &uId) return db.getData(COLUMN_DISPLAY_NAME).toString(); } +QString getUserName(const QByteArray &uId) +{ + Query db; + + db.setType(Query::PULL, TABLE_USERS); + db.addColumn(COLUMN_USERNAME); + db.addCondition(COLUMN_USER_ID, uId); + db.exec(); + + return db.getData(COLUMN_USERNAME).toString(); +} + QString getEmailForUser(const QByteArray &uId) { Query db; @@ -866,7 +941,14 @@ bool ShellIPC::connectToHost() if (!waitForConnected()) { - QTextStream(stdout) << "" << endl << "Host instance not running." << endl << endl; + if (QFileInfo(QDir::tempPath() + "/" + HOST_CONTROL_PIPE).exists()) + { + QTextStream(stdout) << "" << endl << "Permission denied." << endl << endl; + } + else + { + QTextStream(stdout) << "" << endl << "Host instance not running." << endl << endl; + } } return state() == QLocalSocket::ConnectedState; diff --git a/src/common.h b/src/common.h index 114e19d..d959816 100644 --- a/src/common.h +++ b/src/common.h @@ -130,7 +130,6 @@ enum AsyncCommands : quint16 ASYNC_PING_PEERS = 38, // internal | private ASYNC_OPEN_SUBCH = 39, // internal | private ASYNC_CLOSE_SUBCH = 40, // internal | private - ASYNC_UPDATE_BANS = 41, // internal | private ASYNC_KEEP_ALIVE = 42, // internal | private ASYNC_SET_DIR = 43, // internal | private ASYNC_DEBUG_TEXT = 44 // internal | private @@ -201,6 +200,17 @@ enum TypeID : quint8 RESUME_CMD = 29 }; +enum RetCode : quint16 +{ + NO_ERRORS = 1, // task execution completed without any issues. + ABORTED = 2, // the task aborted via user or host intervention. + INVALID_PARAMS = 3, // invalid/missing parameters prevented the task from executing. + CRASH = 4, // the command process has crashed. + FAILED_TO_START = 5, // the command process could not start. + EXECUTION_FAIL = 6, // command specific error prevented execution of the task. + CUSTOM = 7 // indicates a custom return code. +}; + enum GenFileType : quint8 { GEN_UPLOAD = 2, @@ -227,6 +237,8 @@ void serializeThread(QThread *thr); void mkPath(const QString &path); void listDir(QList > &list, const QString &srcPath, const QString &dstPath); void containsActiveCh(const char *subChs, char *actBlock); +bool acceptablePw(const QString &pw, const QByteArray &uId, QString *errMsg); +bool acceptablePw(const QString &pw, const QString &uName, const QString &dispName, const QString &email, QString *errMsg); bool containsNewLine(const QString &str); bool validModPath(const QString &modPath); bool validUserName(const QString &uName); @@ -264,6 +276,7 @@ QString fromTEXT(const QByteArray &txt); QString getUserNameForEmail(const QString &email); QString getEmailForUser(const QByteArray &uId); QString getDispName(const QByteArray &uId); +QString getUserName(const QByteArray &uId); QString boolStr(bool state); QString getParam(const QString &key, const QStringList &args); QString escapeChars(const QString &str, const QChar &escapeChr, const QChar &chr); diff --git a/src/db.cpp b/src/db.cpp index 8501862..e34d5cd 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -222,6 +222,29 @@ QByteArray getSalt(const QByteArray &uId, const QString &table) return db.getData(COLUMN_SALT).toByteArray(); } +QByteArray rootUserId() +{ + Query db; + + db.setType(Query::PULL, TABLE_SERV_SETTINGS); + db.addColumn(COLUMN_ROOT_USER); + db.exec(); + + QByteArray id = db.getData(COLUMN_ROOT_USER).toByteArray(); + + if (id.isEmpty()) + { + db.setType(Query::PULL, TABLE_USERS); + db.addColumn(COLUMN_USER_ID); + db.addCondition(COLUMN_USERNAME, DEFAULT_ROOT_USER); + db.exec(); + + id = db.getData(COLUMN_USER_ID).toByteArray(); + } + + return id; +} + bool createUser(const QString &userName, const QString &email, const QString &dispName, const QString &password) { bool ret = false; @@ -237,6 +260,7 @@ bool createUser(const QString &userName, const QString &email, const QString &di db.addColumn(COLUMN_EMAIL_VERIFIED, false); db.addColumn(COLUMN_NEED_PASS, false); db.addColumn(COLUMN_NEED_NAME, false); + db.addColumn(COLUMN_LOCKED, false); db.addColumn(COLUMN_USER_ID, newUId); db.addRandBlob(COLUMN_SALT, 128); diff --git a/src/db.h b/src/db.h index e359307..c9db53a 100644 --- a/src/db.h +++ b/src/db.h @@ -37,7 +37,7 @@ #include "shell.h" #define APP_NAME "MRCI" -#define APP_VER "2.1.3" +#define APP_VER "2.2.3" #define APP_TARGET "mrci" #ifdef Q_OS_WIN @@ -67,6 +67,7 @@ #define USERNAME_SUB "%user_name%" #define DATE_SUB "%date%" #define INTERN_MOD_NAME ":internal_mod" +#define DEFAULT_ROOT_USER "root" #define DEFAULT_CONFIRM_SUBJECT "Email Verification" #define DEFAULT_TEMP_PW_SUBJECT "Password Reset" #define DEFAULT_LISTEN_ADDRESS "0.0.0.0" @@ -93,7 +94,6 @@ Your confirmation code is as follows:\n\n\ Date requested: %date%." #define TABLE_IPHIST "ip_history" -#define TABLE_IPBANS "ban_list" #define TABLE_USERS "users" #define TABLE_SERV_SETTINGS "host_settings" #define TABLE_CMD_RANKS "command_ranks" @@ -160,6 +160,7 @@ Date requested: %date%." #define COLUMN_MAX_SUB_CH "max_sub_channels" #define COLUMN_APP_NAME "client_app" #define COLUMN_DEFAULT_PASS "default_password" +#define COLUMN_ROOT_USER "root_user" QString genPw(); QList genSequence(int min, int max, int len); @@ -172,6 +173,7 @@ QString columnType(const QString &column); quint32 initHostRank(); QByteArray getSalt(const QByteArray &uId, const QString &table); QByteArray genUniqueHash(); +QByteArray rootUserId(); bool createUser(const QString &userName, const QString &email, const QString &dispName, const QString &password); bool createTempPw(const QByteArray &uId, const QString &password); bool updatePassword(const QByteArray &uId, const QString &password, const QString &table, bool requireNewPass = false); diff --git a/src/db_setup.cpp b/src/db_setup.cpp index 99eb583..68e6295 100644 --- a/src/db_setup.cpp +++ b/src/db_setup.cpp @@ -56,17 +56,6 @@ bool setupDb(QString *errMsg) ret = query.exec(); } - if (ret) - { - query.setType(Query::CREATE_TABLE, TABLE_IPBANS); - query.addColumn(COLUMN_IPADDR); - query.addColumn(COLUMN_TIME); - query.setPrimary(COLUMN_IPADDR); - query.addUnique(COLUMN_IPADDR); - - ret = query.exec(); - } - if (ret) { query.setType(Query::CREATE_TABLE, TABLE_CMD_RANKS); @@ -136,10 +125,10 @@ bool setupDb(QString *errMsg) QByteArray uId = genUniqueHash(); query.setType(Query::PUSH, TABLE_USERS); - query.addColumn(COLUMN_USERNAME, ROOT_USER); + query.addColumn(COLUMN_USERNAME, DEFAULT_ROOT_USER); query.addColumn(COLUMN_HOST_RANK, 1); query.addColumn(COLUMN_NEED_PASS, true); - query.addColumn(COLUMN_NEED_NAME, false); + query.addColumn(COLUMN_NEED_NAME, true); query.addColumn(COLUMN_LOCKED, false); query.addColumn(COLUMN_EMAIL_VERIFIED, false); query.addColumn(COLUMN_USER_ID, uId); @@ -153,6 +142,14 @@ bool setupDb(QString *errMsg) ret = updatePassword(uId, randPw, TABLE_USERS, true); } } + else + { + query.setType(Query::UPDATE, TABLE_USERS); + query.addColumn(COLUMN_NEED_NAME, true); + query.addCondition(COLUMN_USERNAME, DEFAULT_ROOT_USER); + + ret = query.exec(); + } } if (ret) @@ -240,6 +237,7 @@ bool setupDb(QString *errMsg) query.addColumn(COLUMN_ACTIVE_UPDATE); query.addColumn(COLUMN_MAX_SUB_CH); query.addColumn(COLUMN_DEFAULT_PASS); + query.addColumn(COLUMN_ROOT_USER); ret = query.exec(); @@ -248,6 +246,8 @@ bool setupDb(QString *errMsg) randPw = genPw(); } + QByteArray rootUId = rootUserId(); + if (query.createExecuted()) { query.setType(Query::PUSH, TABLE_SERV_SETTINGS); @@ -269,6 +269,7 @@ bool setupDb(QString *errMsg) query.addColumn(COLUMN_ACTIVE_UPDATE, true); query.addColumn(COLUMN_MAX_SUB_CH, DEFAULT_MAX_SUBS); query.addColumn(COLUMN_DEFAULT_PASS, randPw); + query.addColumn(COLUMN_ROOT_USER, rootUId); ret = query.exec(); } @@ -296,6 +297,7 @@ bool setupDb(QString *errMsg) query.addColumn(COLUMN_ACTIVE_UPDATE); query.addColumn(COLUMN_MAX_SUB_CH); query.addColumn(COLUMN_DEFAULT_PASS); + query.addColumn(COLUMN_ROOT_USER); ret = query.exec(); @@ -321,6 +323,7 @@ bool setupDb(QString *errMsg) if (query.getData(COLUMN_ACTIVE_UPDATE).isNull()) defaults.addColumn(COLUMN_ACTIVE_UPDATE, true); if (query.getData(COLUMN_MAX_SUB_CH).isNull()) defaults.addColumn(COLUMN_MAX_SUB_CH, DEFAULT_MAX_SUBS); if (query.getData(COLUMN_DEFAULT_PASS).isNull()) defaults.addColumn(COLUMN_DEFAULT_PASS, randPw); + if (query.getData(COLUMN_ROOT_USER).isNull()) defaults.addColumn(COLUMN_ROOT_USER, rootUId); if (defaults.columns()) { diff --git a/src/main.cpp b/src/main.cpp index c51577b..f3d1822 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,18 +40,6 @@ void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString } } -QByteArray rootUserId() -{ - Query db; - - db.setType(Query::PULL, TABLE_USERS); - db.addColumn(COLUMN_USER_ID); - db.addCondition(COLUMN_USERNAME, ROOT_USER); - db.exec(); - - return db.getData(COLUMN_USER_ID).toByteArray(); -} - void showHelp() { QTextStream txtOut(stdout); @@ -64,8 +52,9 @@ void showHelp() txtOut << " -about : display versioning/warranty information about this application." << endl; txtOut << " -addr {ip_address:port} : set the listening address and port for TCP clients." << endl; txtOut << " -status : display status information about the host instance if it is currently running." << endl; - txtOut << " -reset_root : reset the root account password to the default password shown below." << endl; + txtOut << " -reset_root : reset the root account password to the default password." << endl; txtOut << " -host : start a new host instance. (this blocks)" << endl; + txtOut << " -default_pw : show the default password." << endl; txtOut << " -public_cmds : run the internal module to list it's public commands. for internal use only." << endl; txtOut << " -exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only." << endl; txtOut << " -user_cmds : run the internal module to list it's user commands. for internal use only." << endl; @@ -74,19 +63,19 @@ void showHelp() txtOut << " -pipe {pipe_name/path} : the named pipe used to establish a data connection with the session." << endl; txtOut << " -mem_ses {key_name} : the shared memory key for the session." << endl; txtOut << " -mem_host {key_name} : the shared memory key for the host main process." << endl << endl; - txtOut << " default password: " << defaultPw() << endl << endl; } -void soeDueToDbErr(int *retCode) +void soeDueToDbErr(int *retCode, const QString *errMsg) { *retCode = 1; - QTextStream(stderr) << "" << endl << "err: Unable to continue due to an unclean or non-existent database structure." << endl; + QTextStream(stderr) << "" << endl << "err: Stop error." << endl; + QTextStream(stderr) << " what happened: " << endl << *errMsg << endl << endl; } int shellToHost(const QStringList &args, QCoreApplication &app) { - int ret = 0; + auto ret = 0; auto *ipc = new ShellIPC(args, &app); QObject::connect(ipc, SIGNAL(closeInstance()), &app, SLOT(quit())); @@ -109,28 +98,19 @@ int main(int argc, char *argv[]) serializeThread(app.thread()); - QString workDir = expandEnvVariables(qEnvironmentVariable(ENV_WORK_DIR, DEFAULT_WORK_DIR)); + auto workDir = expandEnvVariables(qEnvironmentVariable(ENV_WORK_DIR, DEFAULT_WORK_DIR)); + auto args = QCoreApplication::arguments(); + auto ret = 0; QDir::setCurrent(workDir); QCoreApplication::setApplicationName(APP_NAME); QCoreApplication::setApplicationVersion(APP_VER); - QString err; - QStringList args = QCoreApplication::arguments(); - bool dbFail = false; - int ret = 0; - - if (!setupDb(&err)) - { - QTextStream(stderr) << "" << endl << "err: Database setup error, the host will not be able to start without a solid database structure." << endl; - QTextStream(stderr) << " what happened: " << endl << err << endl; - - dbFail = true; - } + QString err; qInstallMessageHandler(msgHandler); - //args.append("-host"); // debug + //args.append("-default_pw"); // debug if (args.contains("-help", Qt::CaseInsensitive)) { @@ -142,18 +122,23 @@ int main(int argc, char *argv[]) QTextStream(stdout) << "Based on QT " << QT_VERSION_STR << " " << 8 * QT_POINTER_SIZE << "bit" << endl << endl; QTextStream(stdout) << "The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE" << endl; QTextStream(stdout) << "WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE." << endl << endl; - QTextStream(stdout) << " default password: " << defaultPw() << endl << endl; + + } + else if (args.contains("-default_pw", Qt::CaseInsensitive)) + { + QTextStream(stdout) << "" << endl << " Root User : " << getUserName(rootUserId()) << endl; + QTextStream(stdout) << " Default Password: " << defaultPw() << endl << endl; } else if (args.contains("-addr", Qt::CaseInsensitive)) { - QString params = getParam("-addr", args); - QStringList addr = params.split(':'); + auto params = getParam("-addr", args); + auto addr = params.split(':'); ret = 128; - if (dbFail) + if (!setupDb(&err)) { - soeDueToDbErr(&ret); + soeDueToDbErr(&ret, &err); } else if (addr.size() != 2) { @@ -194,9 +179,9 @@ int main(int argc, char *argv[]) args.contains("-exempt_cmds", Qt::CaseInsensitive) || args.contains("-user_cmds", Qt::CaseInsensitive)) { - if (dbFail) + if (!setupDb(&err)) { - soeDueToDbErr(&ret); + soeDueToDbErr(&ret, &err); } else { @@ -210,9 +195,9 @@ int main(int argc, char *argv[]) } else if (args.contains("-host", Qt::CaseInsensitive)) { - if (dbFail) + if (!setupDb(&err)) { - soeDueToDbErr(&ret); + soeDueToDbErr(&ret, &err); } else { @@ -230,13 +215,22 @@ int main(int argc, char *argv[]) } else if (args.contains("-reset_root", Qt::CaseInsensitive)) { - if (dbFail) + if (!setupDb(&err)) { - soeDueToDbErr(&ret); + soeDueToDbErr(&ret, &err); } else { - updatePassword(rootUserId(), defaultPw(), TABLE_USERS, true); + auto uId = rootUserId(); + + Query db(&app); + + db.setType(Query::UPDATE, TABLE_USERS); + db.addColumn(COLUMN_LOCKED, false); + db.addCondition(COLUMN_USER_ID, uId); + db.exec(); + + updatePassword(uId, defaultPw(), TABLE_USERS, true); } } else diff --git a/src/module.cpp b/src/module.cpp index 64df637..cf63fed 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -46,9 +46,6 @@ QStringList Module::userCmdList() ret << CloseHost::cmdName(); ret << RestartHost::cmdName(); - ret << ListBans::cmdName(); - ret << BanIP::cmdName(); - ret << UnBanIP::cmdName(); ret << Cast::cmdName(); ret << OpenSubChannel::cmdName(); ret << CloseSubChannel::cmdName(); @@ -57,7 +54,7 @@ QStringList Module::userCmdList() ret << IPHist::cmdName(); ret << ListMods::cmdName(); ret << DelMod::cmdName(); - ret << UploadMod::cmdName(); + ret << AddMod::cmdName(); ret << ListUsers::cmdName(); ret << CreateUser::cmdName(); ret << RecoverAcct::cmdName(); @@ -171,9 +168,6 @@ bool Module::runCmd(const QString &name) if (noCaseMatch(name, CloseHost::cmdName())) new CloseHost(this); else if (noCaseMatch(name, RestartHost::cmdName())) new RestartHost(this); else if (noCaseMatch(name, Auth::cmdName())) new Auth(this); - else if (noCaseMatch(name, ListBans::cmdName())) new ListBans(this); - else if (noCaseMatch(name, BanIP::cmdName())) new BanIP(this); - else if (noCaseMatch(name, UnBanIP::cmdName())) new UnBanIP(this); else if (noCaseMatch(name, Cast::cmdName())) new Cast(this); else if (noCaseMatch(name, OpenSubChannel::cmdName())) new OpenSubChannel(this); else if (noCaseMatch(name, CloseSubChannel::cmdName())) new CloseSubChannel(this); @@ -182,7 +176,7 @@ bool Module::runCmd(const QString &name) else if (noCaseMatch(name, IPHist::cmdName())) new IPHist(this); else if (noCaseMatch(name, ListMods::cmdName())) new ListMods(this); else if (noCaseMatch(name, DelMod::cmdName())) new DelMod(this); - else if (noCaseMatch(name, UploadMod::cmdName())) new UploadMod(this); + else if (noCaseMatch(name, AddMod::cmdName())) new AddMod(this); else if (noCaseMatch(name, ListUsers::cmdName())) new ListUsers(this); else if (noCaseMatch(name, CreateUser::cmdName())) new CreateUser(this); else if (noCaseMatch(name, RecoverAcct::cmdName())) new RecoverAcct(this); diff --git a/src/module.h b/src/module.h index 4eca296..a1ff81f 100644 --- a/src/module.h +++ b/src/module.h @@ -20,7 +20,6 @@ #include "common.h" #include "cmd_object.h" #include "commands/admin.h" -#include "commands/bans.h" #include "commands/cast.h" #include "commands/info.h" #include "commands/mods.h" diff --git a/src/session.cpp b/src/session.cpp index 1e14970..c09516d 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -18,9 +18,9 @@ QByteArray wrFrame(quint32 cmdId, const QByteArray &data, uchar dType) { - QByteArray typeBa = wrInt(dType, 8); - QByteArray cmdBa = wrInt(cmdId, 32); - QByteArray sizeBa = wrInt(data.size(), MAX_FRAME_BITS); + auto typeBa = wrInt(dType, 8); + auto cmdBa = wrInt(cmdId, 32); + auto sizeBa = wrInt(data.size(), MAX_FRAME_BITS); return typeBa + cmdBa + sizeBa + data; } @@ -55,8 +55,8 @@ void Session::init() QByteArray Session::genSessionId() { - QByteArray serial = genSerialNumber().toUtf8(); - QByteArray sysId = QSysInfo::machineUniqueId(); + auto serial = genSerialNumber().toUtf8(); + auto sysId = QSysInfo::machineUniqueId(); QCryptographicHash hasher(QCryptographicHash::Sha3_224); @@ -106,9 +106,9 @@ void Session::addIpAction(const QString &action) { Query db(this); - QString ip = rdStringFromBlock(clientIp, BLKSIZE_CLIENT_IP); - QString app = rdStringFromBlock(appName, BLKSIZE_APP_NAME); - QByteArray id = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); + auto ip = rdStringFromBlock(clientIp, BLKSIZE_CLIENT_IP); + auto app = rdStringFromBlock(appName, BLKSIZE_APP_NAME); + auto id = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); db.setType(Query::PUSH, TABLE_IPHIST); db.addColumn(COLUMN_IPADDR, ip); @@ -594,10 +594,6 @@ void Session::privAsyncDataIn(quint16 cmdId, const QByteArray &data) { emit setMaxSessions(static_cast(rdInt(data))); } - else if (cmdId == ASYNC_UPDATE_BANS) - { - emit updateBanList(); - } else if (cmdId == ASYNC_PING_PEERS) { castPingForPeers(); diff --git a/src/session.h b/src/session.h index 181e50c..97dad6b 100644 --- a/src/session.h +++ b/src/session.h @@ -118,7 +118,6 @@ signals: void ended(); void closeServer(); void resServer(); - void updateBanList(); void killMods(); }; diff --git a/src/tcp_server.cpp b/src/tcp_server.cpp index 8b98dbc..0ce9a8a 100644 --- a/src/tcp_server.cpp +++ b/src/tcp_server.cpp @@ -62,7 +62,7 @@ void TCPServer::closedPipeConnection() bool TCPServer::createPipe() { - bool ret = controlPipe->listen(HOST_CONTROL_PIPE); + auto ret = controlPipe->listen(HOST_CONTROL_PIPE); controlPipePath = controlPipe->fullServerName(); @@ -94,9 +94,9 @@ bool TCPServer::start() maxSessions = db.getData(COLUMN_MAXSESSIONS).toUInt(); - bool ret = false; - QString addr = db.getData(COLUMN_IPADDR).toString(); - quint16 port = static_cast(db.getData(COLUMN_PORT).toUInt()); + auto ret = false; + auto addr = db.getData(COLUMN_IPADDR).toString(); + auto port = static_cast(db.getData(COLUMN_PORT).toUInt()); if (!createPipe()) { @@ -115,8 +115,6 @@ bool TCPServer::start() } else { - updateBanList(); - ret = true; flags |= ACCEPTING; } @@ -200,7 +198,7 @@ bool TCPServer::servOverloaded() void TCPServer::procPipeIn() { - QStringList args = parseArgs(controlSocket->readAll(), -1); + auto args = parseArgs(controlSocket->readAll(), -1); if (args.contains("-stop", Qt::CaseInsensitive)) { @@ -235,22 +233,6 @@ void TCPServer::procPipeIn() } } -void TCPServer::updateBanList() -{ - banList.clear(); - - Query db(this); - - db.setType(Query::PULL, TABLE_IPBANS); - db.addColumn(COLUMN_IPADDR); - db.exec(); - - for (int i = 0; i < db.rows(); ++i) - { - banList.append(db.getData(COLUMN_IPADDR, i).toString()); - } -} - void TCPServer::setMaxSessions(quint32 value) { Query db(this); @@ -278,48 +260,40 @@ void TCPServer::incomingConnection(qintptr socketDescriptor) { resumeAccepting(); - if (banList.contains(soc->peerAddress().toString(), Qt::CaseInsensitive)) - { - soc->deleteLater(); - } - else - { - auto buffSize = static_cast(qPow(2, MAX_FRAME_BITS) - 1) + (MAX_FRAME_BITS / 8) + 4; - // max_data_size_per_frame + size_of_size_bytes + size_of_cmd_id + auto buffSize = static_cast(qPow(2, MAX_FRAME_BITS) - 1) + (MAX_FRAME_BITS / 8) + 4; + // max_data_size_per_frame + size_of_size_bytes + size_of_cmd_id - soc->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, buffSize); - soc->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption, buffSize); + soc->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, buffSize); + soc->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption, buffSize); - auto *ses = new Session(hostKey, soc, nullptr); - auto *thr = new QThread(nullptr); + auto *ses = new Session(hostKey, soc, nullptr); + auto *thr = new QThread(nullptr); - connect(thr, &QThread::finished, soc, &QSslSocket::deleteLater); - connect(thr, &QThread::finished, ses, &QSslSocket::deleteLater); - connect(thr, &QThread::finished, thr, &QSslSocket::deleteLater); - connect(thr, &QThread::started, ses, &Session::init); + connect(thr, &QThread::finished, soc, &QSslSocket::deleteLater); + connect(thr, &QThread::finished, ses, &QSslSocket::deleteLater); + connect(thr, &QThread::finished, thr, &QSslSocket::deleteLater); + connect(thr, &QThread::started, ses, &Session::init); - connect(ses, &Session::ended, this, &TCPServer::sessionEnded); - connect(ses, &Session::ended, thr, &QThread::quit); - connect(ses, &Session::connectPeers, this, &TCPServer::connectPeers); - connect(ses, &Session::closeServer, this, &TCPServer::closeServer); - connect(ses, &Session::resServer, this, &TCPServer::resServer); - connect(ses, &Session::setMaxSessions, this, &TCPServer::setMaxSessions); - connect(ses, &Session::updateBanList, this, &TCPServer::updateBanList); + connect(ses, &Session::ended, this, &TCPServer::sessionEnded); + connect(ses, &Session::ended, thr, &QThread::quit); + connect(ses, &Session::connectPeers, this, &TCPServer::connectPeers); + connect(ses, &Session::closeServer, this, &TCPServer::closeServer); + connect(ses, &Session::resServer, this, &TCPServer::resServer); + connect(ses, &Session::setMaxSessions, this, &TCPServer::setMaxSessions); - connect(this, &TCPServer::connectPeers, ses, &Session::connectToPeer); - connect(this, &TCPServer::endAllSessions, ses, &Session::endSession); + connect(this, &TCPServer::connectPeers, ses, &Session::connectToPeer); + connect(this, &TCPServer::endAllSessions, ses, &Session::endSession); - serializeThread(thr); + serializeThread(thr); - ses->moveToThread(thr); - soc->moveToThread(thr); - thr->start(); + ses->moveToThread(thr); + soc->moveToThread(thr); + thr->start(); - hostSharedMem->lock(); + hostSharedMem->lock(); - wr32BitToBlock((rd32BitFromBlock(hostLoad) + 1), hostLoad); + wr32BitToBlock((rd32BitFromBlock(hostLoad) + 1), hostLoad); - hostSharedMem->unlock(); - } + hostSharedMem->unlock(); } } diff --git a/src/tcp_server.h b/src/tcp_server.h index 7a0fc97..e38120f 100644 --- a/src/tcp_server.h +++ b/src/tcp_server.h @@ -34,7 +34,6 @@ private: QLocalServer *controlPipe; QLocalSocket *controlSocket; char *hostLoad; - QStringList banList; QString controlPipePath; QString hostKey; quint32 maxSessions; @@ -50,7 +49,6 @@ private slots: void newPipeConnection(); void closedPipeConnection(); void sessionEnded(); - void updateBanList(); void setMaxSessions(quint32 value); public slots: