111 lines
3.1 KiB
C++
111 lines
3.1 KiB
C++
#include "loginDb.hpp"
|
|
#include "databasepool.h"
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <iostream>
|
|
|
|
extern "C" {
|
|
#include "monocypher.h"
|
|
}
|
|
using namespace sqlite_orm;
|
|
|
|
namespace login {
|
|
|
|
constexpr uint32_t SALT_SIZE = 16;
|
|
constexpr uint32_t PASSWORD_HASH_SIZE = 32;
|
|
|
|
static std::vector<char> getPasswordHash(const std::vector<char>& salt, const std::string password){
|
|
std::vector<char> password_hash;
|
|
password_hash.resize(PASSWORD_HASH_SIZE);
|
|
|
|
crypto_argon2_config config = {
|
|
.algorithm = CRYPTO_ARGON2_I, /* Argon2i */
|
|
.nb_blocks = 100000, /* 100 megabytes */
|
|
.nb_passes = 3, /* 3 iterations */
|
|
.nb_lanes = 1 /* Single-threaded */
|
|
};
|
|
crypto_argon2_inputs inputs = {
|
|
.pass = (uint8_t*)(password.data()), /* User password */
|
|
.salt = (uint8_t*)salt.data(), /* Salt for the password */
|
|
.pass_size = static_cast<uint32_t>(password.size()), /* Password length */
|
|
.salt_size = 16
|
|
};
|
|
crypto_argon2_extras extras = {0}; /* Extra parameters unused */
|
|
|
|
void *work_area = malloc((size_t)config.nb_blocks * 1024);
|
|
crypto_argon2((uint8_t*)password_hash.data(), PASSWORD_HASH_SIZE, work_area,
|
|
config, inputs, extras);
|
|
free(work_area);
|
|
return password_hash;
|
|
}
|
|
|
|
static void createPasswordHash(User& user, const std::string password){
|
|
user.salt.resize(SALT_SIZE);
|
|
user.password_hash.resize(PASSWORD_HASH_SIZE);
|
|
|
|
arc4random_buf(user.salt.data(), SALT_SIZE);
|
|
user.password_hash = getPasswordHash(user.salt, password);
|
|
}
|
|
|
|
static bool verifyUser(const User& user, std::string const& password)
|
|
{
|
|
const auto hash = getPasswordHash(user.salt, password);
|
|
return crypto_verify32((uint8_t*)hash.data(), (uint8_t*)user.password_hash.data()) == 0;
|
|
}
|
|
|
|
int createUser(const std::string& username, const std::string& password){
|
|
if (username.empty() || password.empty())
|
|
return -1;
|
|
|
|
int64_t id;
|
|
auto db = dbpool.acquire();
|
|
|
|
for (auto &u : db->get_all<login::User>()) {
|
|
if (u.username == username){
|
|
std::cout << "WTF" << std::endl;
|
|
};
|
|
}
|
|
|
|
auto user = db->get_optional<login::User>(
|
|
where(c(&login::User::username) == username)
|
|
);
|
|
|
|
if (user.has_value()) {
|
|
id = user.value().id;
|
|
} else {
|
|
User usr = newUser(username);
|
|
createPasswordHash(usr, password);
|
|
id = db->insert(usr);
|
|
}
|
|
dbpool.release(db);
|
|
return id;
|
|
}
|
|
|
|
std::optional<User> getUser(const std::string& username){
|
|
auto db = dbpool.acquire();
|
|
auto user = db->get_all<login::User>(
|
|
where(c(&login::User::username) == username)
|
|
);
|
|
dbpool.release(db);
|
|
|
|
if(user.size() > 0){
|
|
return user[0];
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
std::optional<User> getVerifiedUser(const std::string& username, const std::string& password){
|
|
auto user = getUser(username);
|
|
if (!user.has_value())
|
|
return {};
|
|
|
|
if (verifyUser(*user, password)){
|
|
return user;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
} |