Compare commits
5 次程式碼提交
8d685dc581
...
3d0fce590b
作者 | SHA1 | 提交日期 | |
---|---|---|---|
3d0fce590b | |||
1082f8ac5a | |||
8b044d712b | |||
5037a17fba | |||
164b2c19ee |
@ -42,11 +42,12 @@ std::vector<char> Authenticator::pbkdf5(std::string password, const std::vector<
|
||||
unsigned char hash[32];
|
||||
const EVP_MD *sha256 = EVP_sha256();
|
||||
const unsigned char *rawsalt = reinterpret_cast<const unsigned char *>(salt.data());
|
||||
int ret = PKCS5_PBKDF2_HMAC(password.c_str(), password.size(), rawsalt, salt.size(), 300000, sha256, sizeof(hash), hash);
|
||||
int ret =
|
||||
PKCS5_PBKDF2_HMAC(password.c_str(), password.size(), rawsalt, salt.size(), 300000, sha256, sizeof(hash), hash);
|
||||
if(ret != 1)
|
||||
{
|
||||
Logger::error() << "Authenticator: pbkdf5: Failed to create hash";
|
||||
return { };
|
||||
return {};
|
||||
}
|
||||
std::vector<char> result;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <variant>
|
||||
#include "database/userdao.h"
|
||||
|
||||
#define AUTH_DEFAULT_SALT_SIZE 32
|
||||
enum AuthenticationError
|
||||
{
|
||||
UserNotFound,
|
||||
|
220
cli.cpp
Normal file
220
cli.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
|
||||
#include "cli.h"
|
||||
#include "utils.h"
|
||||
#include "random.h"
|
||||
#include "authenticator.h"
|
||||
#include "config.h"
|
||||
#include "logger.h"
|
||||
|
||||
CLIHandler::CLIHandler(Config &config, Database &db)
|
||||
{
|
||||
this->db = &db;
|
||||
this->conf = &config;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_add(const std::vector<std::string> &args)
|
||||
{
|
||||
std::string username = args.at(0);
|
||||
std::string password = args.at(1);
|
||||
|
||||
auto userDao = db->createUserDao();
|
||||
|
||||
Permissions perms = this->conf->handlersConfig.anon_permissions;
|
||||
int p = perms.getPermissions();
|
||||
p |= PERM_CAN_CREATE | PERM_CAN_SEARCH | PERM_CAN_EDIT;
|
||||
Permissions newPermissions = Permissions{p};
|
||||
|
||||
Random r;
|
||||
User user;
|
||||
user.enabled = true;
|
||||
user.login = username;
|
||||
user.salt = r.getRandom(AUTH_DEFAULT_SALT_SIZE);
|
||||
user.permissions = newPermissions;
|
||||
|
||||
Authenticator auth{*userDao};
|
||||
std::vector<char> hashResult = auth.hash(password, user.salt);
|
||||
if(hashResult.empty())
|
||||
{
|
||||
return {false, "Error during hashing - Got empty hash"};
|
||||
}
|
||||
user.password = hashResult;
|
||||
|
||||
try
|
||||
{
|
||||
userDao->save(user);
|
||||
}
|
||||
catch(std::runtime_error &e)
|
||||
{
|
||||
return {false, "Exception: " + std::string(e.what())};
|
||||
}
|
||||
return {true, ""};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_change_pw(const std::vector<std::string> &args)
|
||||
{
|
||||
std::string username = args.at(0);
|
||||
std::string password = args.at(1);
|
||||
|
||||
auto userDao = db->createUserDao();
|
||||
|
||||
auto user = userDao->find(username);
|
||||
if(user)
|
||||
{
|
||||
Random r;
|
||||
Authenticator auth{*userDao};
|
||||
user->salt = r.getRandom(AUTH_DEFAULT_SALT_SIZE);
|
||||
user->password = auth.hash(password, user->salt);
|
||||
if(user->password.empty())
|
||||
{
|
||||
return {false, "Error during hashing - Got empty hash"};
|
||||
}
|
||||
|
||||
userDao->save(*user);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {false, "User not found"};
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_rename(const std::vector<std::string> &args)
|
||||
{
|
||||
|
||||
return {true, ""};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_set_perms(const std::vector<std::string> &args)
|
||||
{
|
||||
auto userDao = this->db->createUserDao();
|
||||
std::string username = args.at(0);
|
||||
std::string permission_string = args.at(1);
|
||||
|
||||
Permissions perms{permission_string};
|
||||
|
||||
auto user = userDao->find(username);
|
||||
if(user)
|
||||
{
|
||||
user->permissions = perms;
|
||||
userDao->save(*user);
|
||||
user_show({username});
|
||||
return {true, ""};
|
||||
}
|
||||
|
||||
return {false, "User not found"};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_list(const std::vector<std::string> &args)
|
||||
{
|
||||
auto userDao = this->db->createUserDao();
|
||||
QueryOption o;
|
||||
auto result = userDao->list(o);
|
||||
std::stringstream stream;
|
||||
for(User &u : result)
|
||||
{
|
||||
stream << u.login << "\t" << std::string(u.enabled ? "enabled" : "disabled") << "\t" << u.permissions.toString()
|
||||
<< std::endl;
|
||||
}
|
||||
return {true, stream.str()};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::user_show(const std::vector<std::string> &args)
|
||||
{
|
||||
std::string username = args.at(0);
|
||||
auto userDao = this->db->createUserDao();
|
||||
auto user = userDao->find(username);
|
||||
std::stringstream stream;
|
||||
if(user)
|
||||
{
|
||||
stream << "Username: " << user->login << std::endl;
|
||||
|
||||
stream << "Enabled: " << std::string(user->enabled ? "yes" : "no") << std::endl;
|
||||
stream << "Permissions (general): " << user->permissions.toString() << std::endl;
|
||||
return {true, stream.str()};
|
||||
}
|
||||
return {false, "User not found"};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::attach(const std::vector<std::string> &args)
|
||||
{
|
||||
/* TODO: consider authentication */
|
||||
pid_t pid = getpid();
|
||||
return {true, "Hi, I am pid: " + std::to_string(pid)};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::cli_help(const std::vector<std::string> &args)
|
||||
{
|
||||
std::string command;
|
||||
if(args.size() > 0)
|
||||
command = args[0];
|
||||
std::stringstream stream;
|
||||
for(struct cmd &cmd : cmds)
|
||||
{
|
||||
if(command != "" && cmd.name != command)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stream << cmd.name << " - " << cmd.helptext << std::endl;
|
||||
for(struct cmd &subCmd : cmd.subCommands)
|
||||
{
|
||||
stream << "\t" << subCmd.name << " " << subCmd.helptext << std::endl;
|
||||
}
|
||||
stream << std::endl;
|
||||
}
|
||||
return {true, stream.str()};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::processCommand(const std::vector<CLIHandler::cmd> &commands, std::string cmd,
|
||||
const std::vector<std::string> &args)
|
||||
{
|
||||
auto c = std::find_if(commands.begin(), commands.end(),
|
||||
[&cmd](const struct CLIHandler::cmd &a) { return a.name == cmd; });
|
||||
if(c == commands.end())
|
||||
{
|
||||
std::cout << "No such command: " << cmd << std::endl;
|
||||
return cli_help({});
|
||||
}
|
||||
|
||||
if(!c->subCommands.empty() && args.size() >= c->required_args)
|
||||
{
|
||||
std::string newcmd = args[0];
|
||||
std::vector<std::string> newargs = args;
|
||||
newargs.erase(newargs.begin());
|
||||
return processCommand(c->subCommands, newcmd, newargs);
|
||||
}
|
||||
if(args.size() < c->required_args)
|
||||
{
|
||||
return {false, "not enough parameters passed"};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return c->func(this, args);
|
||||
}
|
||||
catch(std::runtime_error &e)
|
||||
{
|
||||
return {false, "Exception: " + std::string(e.what())};
|
||||
}
|
||||
return {false, ""};
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIHandler::processCommand(std::string cmd, const std::vector<std::string> &args)
|
||||
{
|
||||
return processCommand(this->cmds, cmd, args);
|
||||
}
|
||||
|
||||
std::pair<std::string, std::vector<std::string>> CLIHandler::splitCommand(std::string input)
|
||||
{
|
||||
input = utils::trim(input);
|
||||
std::vector<std::string> splitted = utils::split(input, "\\s+");
|
||||
if(splitted.empty())
|
||||
{
|
||||
return {" ", splitted};
|
||||
}
|
||||
std::string cmd = splitted[0];
|
||||
splitted.erase(splitted.begin());
|
||||
return {cmd, splitted};
|
||||
}
|
66
cli.h
Normal file
66
cli.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "database/database.h"
|
||||
#include "config.h"
|
||||
|
||||
class CLIHandler
|
||||
{
|
||||
struct cmd
|
||||
{
|
||||
std::string name;
|
||||
std::string helptext;
|
||||
unsigned int required_args;
|
||||
std::vector<cmd> subCommands;
|
||||
std::function<std::pair<bool, std::string>(CLIHandler *, const std::vector<std::string> &)> func;
|
||||
};
|
||||
|
||||
private:
|
||||
Database *db;
|
||||
Config *conf;
|
||||
|
||||
protected:
|
||||
std::pair<bool, std::string> attach(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> cli_help(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_add(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_change_pw(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_rename(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_set_perms(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_list(const std::vector<std::string> &args);
|
||||
std::pair<bool, std::string> user_show(const std::vector<std::string> &args);
|
||||
|
||||
std::vector<struct cmd> cmds{
|
||||
{{"user",
|
||||
"user operations on the database",
|
||||
1,
|
||||
{{{"add", "[user] [password] - creates a user", 2, {}, &CLIHandler::user_add},
|
||||
{"changepw", "[user] [password] - changes the password of user", 2, {}, &CLIHandler::user_change_pw},
|
||||
{"rename", "[user] [new name] - renames a user", 2, {}, &CLIHandler::user_rename},
|
||||
{"setperms", "[user] [perms] - sets the permissions of the user", 2, {}, &CLIHandler::user_set_perms},
|
||||
{"list", "- lists users", 0, {}, &CLIHandler::user_list},
|
||||
{"show", "[user] - show detailed information about user", 1, {}, &CLIHandler::user_show}}},
|
||||
&CLIHandler::cli_help},
|
||||
{"exit",
|
||||
"exit cli",
|
||||
0,
|
||||
{},
|
||||
[](CLIHandler *, const std::vector<std::string> &args) -> std::pair<bool, std::string>
|
||||
{
|
||||
exit(EXIT_SUCCESS);
|
||||
return {true, ""};
|
||||
}},
|
||||
{"help", "print this help", 0, {}, &CLIHandler::cli_help},
|
||||
{"attach", "attach to running instance", 0, {}, &CLIHandler::attach}}};
|
||||
|
||||
std::pair<bool, std::string> processCommand(const std::vector<CLIHandler::cmd> &commands, std::string cmd,
|
||||
const std::vector<std::string> &args);
|
||||
|
||||
public:
|
||||
CLIHandler(Config &config, Database &d);
|
||||
std::pair<bool, std::string> processCommand(std::string cmd, const std::vector<std::string> &args);
|
||||
static std::pair<std::string, std::vector<std::string>> splitCommand(std::string input);
|
||||
};
|
||||
|
||||
#endif // CLI_H
|
137
cliconsole.cpp
Normal file
137
cliconsole.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "cliconsole.h"
|
||||
|
||||
CLIConsole::CLIConsole(CLIHandler &cliHandler, std::string socketPath)
|
||||
{
|
||||
this->handler = &cliHandler;
|
||||
this->socketPath = socketPath;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> CLIConsole::send(std::string input)
|
||||
{
|
||||
ssize_t ret =
|
||||
sendto(this->sock, input.c_str(), input.size(), 0, (const sockaddr *)&this->server, sizeof(this->server));
|
||||
if((size_t)ret != input.size())
|
||||
{
|
||||
return {false, "sendto failed: " + std::to_string(ret) + " " + std::string(strerror(errno))};
|
||||
}
|
||||
char buffer[1024] = {0};
|
||||
ret = recvfrom(this->sock, buffer, sizeof(buffer) - 1, 0, NULL, NULL);
|
||||
if(ret == -1)
|
||||
{
|
||||
return {false, "recvfrom failed: " + std::string(strerror(errno))};
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
std::string_view view = buffer;
|
||||
if(view[0] == '1')
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
view.remove_prefix(1);
|
||||
std::string msg = std::string{view};
|
||||
|
||||
return {success, msg};
|
||||
}
|
||||
|
||||
void CLIConsole::attach()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
std::cout << "Already attached" << std::endl;
|
||||
return;
|
||||
}
|
||||
if(socketPath.size() > sizeof(this->server.sun_path) - 1)
|
||||
{
|
||||
std::cout << "Socket path too long" << std::endl;
|
||||
return;
|
||||
}
|
||||
memset(&this->server, 0, sizeof(this->server));
|
||||
this->server.sun_family = AF_UNIX;
|
||||
memcpy(&this->server.sun_path, socketPath.c_str(), socketPath.size());
|
||||
this->server.sun_path[socketPath.size()] = 0;
|
||||
|
||||
int s = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if(s == -1)
|
||||
{
|
||||
std::cout << "Failed to create socket" << strerror(errno) << std::endl;
|
||||
return;
|
||||
}
|
||||
this->sock = s;
|
||||
|
||||
struct sockaddr_un client;
|
||||
client.sun_family = AF_UNIX;
|
||||
client.sun_path[0] = '\0';
|
||||
|
||||
int ret = bind(this->sock, (struct sockaddr *)&client, sizeof(client));
|
||||
if(ret != 0)
|
||||
{
|
||||
std::cout << "bind() failed: " << strerror(errno) << std::endl;
|
||||
return;
|
||||
}
|
||||
auto result = this->send("attach");
|
||||
if(result.first)
|
||||
{
|
||||
std::cout << "Attached successfully: " << result.second << std::endl;
|
||||
this->attached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Attached unsuccessfully: " << result.second << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CLIConsole::startInteractive()
|
||||
{
|
||||
std::cout << "qswiki CLI" << std::endl;
|
||||
std::cout << "not attached - use 'attach' to connect to running instance" << std::endl;
|
||||
|
||||
while(true)
|
||||
{
|
||||
std::string input;
|
||||
std::cout << "> ";
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if(std::cin.bad() || std::cin.eof())
|
||||
{
|
||||
std::cout << "Exiting" << std::endl;
|
||||
return;
|
||||
}
|
||||
if(input.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pair = CLIHandler::splitCommand(input);
|
||||
if(pair.first == "exit")
|
||||
{
|
||||
std::cout << "Exiting CLI";
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if(pair.first == "attach")
|
||||
{
|
||||
attach();
|
||||
continue;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> result;
|
||||
if(!attached)
|
||||
{
|
||||
result = handler->processCommand(pair.first, pair.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this->send(input);
|
||||
}
|
||||
|
||||
if(!result.second.empty())
|
||||
{
|
||||
std::cout << result.second << std::endl;
|
||||
}
|
||||
if(!result.first)
|
||||
{
|
||||
std::cout << "Command failed" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
27
cliconsole.h
Normal file
27
cliconsole.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef CLICONSOLE_H
|
||||
#define CLICONSOLE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include "cli.h"
|
||||
|
||||
class CLIConsole
|
||||
{
|
||||
private:
|
||||
struct sockaddr_un server;
|
||||
int sock;
|
||||
CLIHandler *handler;
|
||||
std::string socketPath;
|
||||
bool attached = false;
|
||||
std::pair<bool, std::string> send(std::string input);
|
||||
void attach();
|
||||
|
||||
public:
|
||||
CLIConsole(CLIHandler &cliHandler, std::string socketPath);
|
||||
void startInteractive();
|
||||
};
|
||||
|
||||
#endif // CLICONSOLE_H
|
77
cliserver.cpp
Normal file
77
cliserver.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include "cliserver.h"
|
||||
#include "logger.h"
|
||||
CLIServer::CLIServer(CLIHandler &handler)
|
||||
{
|
||||
this->handler = &handler;
|
||||
}
|
||||
|
||||
bool CLIServer::detachServer(std::string socketpath)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
const int max_socket_length = sizeof(name.sun_path) - 1;
|
||||
if(socketpath.size() > max_socket_length)
|
||||
{
|
||||
perror("socket path too long");
|
||||
return false;
|
||||
}
|
||||
int s = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if(s == -1)
|
||||
{
|
||||
perror("socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&name, 0, sizeof(name));
|
||||
name.sun_family = AF_UNIX;
|
||||
memcpy(&name.sun_path, socketpath.c_str(), socketpath.size());
|
||||
|
||||
unlink(socketpath.c_str());
|
||||
int ret = bind(s, (const struct sockaddr *)&name, sizeof(name));
|
||||
if(ret == -1)
|
||||
{
|
||||
perror("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto worker = [=]
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
char buffer[1024] = {0};
|
||||
struct sockaddr_un peer;
|
||||
socklen_t peerlen = sizeof(peer);
|
||||
|
||||
int ret = recvfrom(s, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &peerlen);
|
||||
if(ret == -1)
|
||||
{
|
||||
Logger::error() << "Error during recvfrom in CLI server: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string input{buffer};
|
||||
|
||||
auto pair = CLIHandler::splitCommand(input);
|
||||
|
||||
auto result = handler->processCommand(pair.first, pair.second);
|
||||
char resultCode = '0';
|
||||
if(result.first)
|
||||
{
|
||||
resultCode = '1';
|
||||
}
|
||||
std::string resultString;
|
||||
resultString += resultCode;
|
||||
resultString += result.second;
|
||||
ret = sendto(s, resultString.c_str(), resultString.size(), 0, (struct sockaddr *)&peer, peerlen);
|
||||
if(ret == -1)
|
||||
{
|
||||
Logger::error() << "Error during sendto in CLI server: " << strerror(errno);
|
||||
}
|
||||
}
|
||||
};
|
||||
std::thread t1{worker};
|
||||
t1.detach();
|
||||
return true;
|
||||
}
|
16
cliserver.h
Normal file
16
cliserver.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CLISERVER_H
|
||||
#define CLISERVER_H
|
||||
#include <thread>
|
||||
#include "cli.h"
|
||||
|
||||
class CLIServer
|
||||
{
|
||||
private:
|
||||
CLIHandler *handler = nullptr;
|
||||
|
||||
public:
|
||||
CLIServer(CLIHandler &handler);
|
||||
bool detachServer(std::string socketpath);
|
||||
};
|
||||
|
||||
#endif // CLISERVER_H
|
@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "../user.h"
|
||||
#include "queryoption.h"
|
||||
class UserDao
|
||||
{
|
||||
public:
|
||||
@ -10,6 +11,7 @@ class UserDao
|
||||
virtual bool exists(std::string username) = 0;
|
||||
virtual std::optional<User> find(std::string username) = 0;
|
||||
virtual std::optional<User> find(int id) = 0;
|
||||
virtual std::vector<User> list(QueryOption o) = 0;
|
||||
virtual void deleteUser(std::string username) = 0;
|
||||
virtual void save(const User &u) = 0;
|
||||
virtual ~UserDao(){};
|
||||
|
@ -23,6 +23,7 @@ SOFTWARE.
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include "userdaosqlite.h"
|
||||
#include "sqlitequeryoption.h"
|
||||
|
||||
UserDaoSqlite::UserDaoSqlite()
|
||||
{
|
||||
@ -82,6 +83,39 @@ std::optional<User> UserDaoSqlite::find(int id)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<User> UserDaoSqlite::list(QueryOption o)
|
||||
{
|
||||
std::vector<User> result;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
std::string queryOption = SqliteQueryOption(o).setOrderByColumn("username").setPrependWhere(true).build();
|
||||
std::string query = "SELECT username, password, salt, permissions, enabled FROM user " + queryOption;
|
||||
|
||||
*db << query >>
|
||||
[&](std::string username, std::vector<char> pw, std::vector<char> salt, int permisisons, bool enabled)
|
||||
{
|
||||
User tmp;
|
||||
tmp.login = username;
|
||||
tmp.password = pw;
|
||||
tmp.salt = salt;
|
||||
tmp.permissions = Permissions{permisisons};
|
||||
tmp.enabled = enabled;
|
||||
result.push_back(tmp);
|
||||
};
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UserDaoSqlite::deleteUser(std::string username)
|
||||
{
|
||||
// What to do with the contributions of the user?
|
||||
|
@ -13,6 +13,7 @@ class UserDaoSqlite : public UserDao, protected SqliteDao
|
||||
std::optional<User> find(std::string username);
|
||||
std::optional<User> find(int id);
|
||||
|
||||
std::vector<User> list(QueryOption o);
|
||||
void deleteUser(std::string username);
|
||||
void save(const User &u);
|
||||
using SqliteDao::SqliteDao;
|
||||
|
@ -15,19 +15,20 @@ Response HandlerUserSettings::handleRequest(const Request &r)
|
||||
|
||||
if(newpassword != newpasswordconfirm)
|
||||
{
|
||||
//TODO: is not nice, users has to hit the back button...
|
||||
// TODO: is not nice, users has to hit the back button...
|
||||
return this->errorResponse("Passwords don't match", "The entered new passwords don't match");
|
||||
}
|
||||
auto userDao = this->database->createUserDao();
|
||||
Authenticator authenticator(*userDao);
|
||||
|
||||
std::variant<User, AuthenticationError> authresult = authenticator.authenticate(this->userSession->user.login, oldpassword);
|
||||
std::variant<User, AuthenticationError> authresult =
|
||||
authenticator.authenticate(this->userSession->user.login, oldpassword);
|
||||
if(std::holds_alternative<AuthenticationError>(authresult))
|
||||
{
|
||||
return this->errorResponse("Invalid current password", "The old password you entered is invalid");
|
||||
}
|
||||
Random r;
|
||||
std::vector<char> salt = r.getRandom(23);
|
||||
std::vector<char> salt = r.getRandom(AUTH_DEFAULT_SALT_SIZE);
|
||||
User user = std::get<User>(authresult);
|
||||
user.salt = salt;
|
||||
user.password = authenticator.hash(newpassword, user.salt);
|
||||
|
@ -20,6 +20,17 @@ SOFTWARE.
|
||||
*/
|
||||
#include "permissions.h"
|
||||
|
||||
static const std::map<std::string, int> permmap = {{"can_read", PERM_CAN_READ},
|
||||
{"can_edit", PERM_CAN_EDIT},
|
||||
{"can_page_history", PERM_CAN_PAGE_HISTORY},
|
||||
{"can_global_history", PERM_CAN_GLOBAL_HISTORY},
|
||||
{"can_delete", PERM_CAN_DELETE},
|
||||
{"can_see_page_list", PERM_CAN_SEE_PAGE_LIST},
|
||||
{"can_create", PERM_CAN_CREATE},
|
||||
{"can_see_category_list", PERM_CAN_SEE_CATEGORY_LIST},
|
||||
{"can_see_links_here", PERM_CAN_SEE_LINKS_HERE},
|
||||
{"can_search", PERM_CAN_SEARCH}};
|
||||
|
||||
Permissions::Permissions(int permissions)
|
||||
{
|
||||
this->permissions = permissions;
|
||||
@ -36,3 +47,20 @@ Permissions::Permissions(const std::string &str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Permissions::toString(int perms)
|
||||
{
|
||||
std::string result;
|
||||
for(auto pair : permmap)
|
||||
{
|
||||
if(pair.second & perms)
|
||||
{
|
||||
result += pair.first + ",";
|
||||
}
|
||||
}
|
||||
if(result.size() > 0)
|
||||
{
|
||||
result.pop_back();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -14,20 +14,12 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class Permissions
|
||||
|
||||
{
|
||||
private:
|
||||
int permissions = 0;
|
||||
const std::map<std::string, int> permmap = {{"can_read", PERM_CAN_READ},
|
||||
{"can_edit", PERM_CAN_EDIT},
|
||||
{"can_page_history", PERM_CAN_PAGE_HISTORY},
|
||||
{"can_global_history", PERM_CAN_GLOBAL_HISTORY},
|
||||
{"can_delete", PERM_CAN_DELETE},
|
||||
{"can_see_page_list", PERM_CAN_SEE_PAGE_LIST},
|
||||
{"can_create", PERM_CAN_CREATE},
|
||||
{"can_see_category_list", PERM_CAN_SEE_CATEGORY_LIST},
|
||||
{"can_see_links_here", PERM_CAN_SEE_LINKS_HERE},
|
||||
{"can_search", PERM_CAN_SEARCH}};
|
||||
|
||||
public:
|
||||
Permissions()
|
||||
@ -102,6 +94,13 @@ class Permissions
|
||||
{
|
||||
return this->permissions & PERM_CAN_SEE_PAGE_LIST;
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
return Permissions::toString(this->permissions);
|
||||
}
|
||||
|
||||
static std::string toString(int perms);
|
||||
};
|
||||
|
||||
#endif // PERMISSIONS_H
|
||||
|
61
qswiki.cpp
61
qswiki.cpp
@ -25,6 +25,7 @@ SOFTWARE.
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <filesystem>
|
||||
#include <getopt.h>
|
||||
#include "gateway/gatewayinterface.h"
|
||||
#include "gateway/gatewayfactory.h"
|
||||
#include "handlers/handlerfactory.h"
|
||||
@ -37,6 +38,10 @@ SOFTWARE.
|
||||
#include "requestworker.h"
|
||||
#include "cache/fscache.h"
|
||||
#include "sandbox/sandboxfactory.h"
|
||||
#include "cli.h"
|
||||
#include "cliconsole.h"
|
||||
#include "cliserver.h"
|
||||
|
||||
void sigterm_handler(int arg)
|
||||
{
|
||||
// TODO: proper shutdown.
|
||||
@ -56,6 +61,10 @@ void setup_signal_handlers()
|
||||
}
|
||||
}
|
||||
|
||||
#define OPT_PRINT_VERSION 23
|
||||
|
||||
static struct option long_options[] = {{"cli", no_argument, 0, 'c'}, {"version", no_argument, 0, OPT_PRINT_VERSION}};
|
||||
|
||||
std::unique_ptr<ICache> createCache(const ConfigVariableResolver &resolver)
|
||||
{
|
||||
|
||||
@ -63,13 +72,48 @@ std::unique_ptr<ICache> createCache(const ConfigVariableResolver &resolver)
|
||||
|
||||
return std::make_unique<FsCache>(path);
|
||||
}
|
||||
|
||||
std::string get_version_string()
|
||||
{
|
||||
return "master";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
char *configfilepath = NULL;
|
||||
int option;
|
||||
int option_index;
|
||||
bool cli_mode = false;
|
||||
|
||||
if(geteuid() == 0)
|
||||
{
|
||||
std::cerr << "Do not run this as root!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
while((option = getopt_long(argc, argv, "cv", long_options, &option_index)) != -1)
|
||||
{
|
||||
switch(option)
|
||||
{
|
||||
case 'c':
|
||||
cli_mode = true;
|
||||
break;
|
||||
case OPT_PRINT_VERSION:
|
||||
std::cout << get_version_string() << std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(optind == argc)
|
||||
{
|
||||
std::cerr << "Missing config path" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
configfilepath = argv[optind++];
|
||||
|
||||
auto sandbox = createSandbox();
|
||||
// TODO: do we want to keep it mandatory or configurable?
|
||||
if(!sandbox->supported())
|
||||
@ -82,7 +126,7 @@ int main(int argc, char **argv)
|
||||
std::cerr << "no path to config file provided" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string configpath = std::filesystem::absolute(argv[1]).string();
|
||||
std::string configpath = std::filesystem::absolute(configfilepath).string();
|
||||
if(!sandbox->enableForInit())
|
||||
{
|
||||
Logger::error() << "Sandboxing for init mode could not be activated.";
|
||||
@ -113,6 +157,21 @@ int main(int argc, char **argv)
|
||||
Logger::setStream(&logstream);
|
||||
|
||||
auto database = createDatabase(config);
|
||||
std::string socketPath = config.configVarResolver.getConfig("socketpath");
|
||||
CLIHandler cliHandler(config, *database);
|
||||
|
||||
if(cli_mode)
|
||||
{
|
||||
CLIConsole console{cliHandler, socketPath};
|
||||
console.startInteractive();
|
||||
return 0;
|
||||
}
|
||||
CLIServer cliServer{cliHandler};
|
||||
if(!cliServer.detachServer(socketPath))
|
||||
{
|
||||
Logger::error() << "Error: Failed to detach unix socket server";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: quite ugly, anon-handling must be rethought
|
||||
auto userdao = database->createUserDao();
|
||||
|
17
utils.cpp
17
utils.cpp
@ -181,3 +181,20 @@ std::string utils::toISODate(time_t t)
|
||||
}
|
||||
return std::string{result};
|
||||
}
|
||||
|
||||
std::string utils::trim(const std::string &str)
|
||||
{
|
||||
std::string_view chars = " \t\n\r";
|
||||
std::string_view view = str;
|
||||
auto n = view.find_first_not_of(chars);
|
||||
if(n != std::string_view::npos)
|
||||
{
|
||||
view.remove_prefix(n);
|
||||
}
|
||||
n = view.find_last_not_of(chars);
|
||||
if(n != std::string_view::npos)
|
||||
{
|
||||
view.remove_suffix(view.size() - n - 1);
|
||||
}
|
||||
return std::string{view};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user