password hash cheching
This commit is contained in:
parent
99a9fd507e
commit
534c282226
25 changed files with 390 additions and 84 deletions
|
@ -10,21 +10,17 @@
|
|||
|
||||
#include "statement.h"
|
||||
#include "transaction.h"
|
||||
#include "database/exceptions.h"
|
||||
|
||||
constexpr const char* versionQuery = "SELECT value FROM system WHERE `key` = 'version'";
|
||||
constexpr const char* updateQuery = "UPDATE system SET `value` = ? WHERE `key` = 'version'";
|
||||
constexpr const char* registerQuery = "INSERT INTO accounts (`login`, `type`, `password`) VALUES (?, 1, ?)";
|
||||
constexpr const char* lastIdQuery = "SELECT LAST_INSERT_ID() AS id";
|
||||
constexpr const char* assignRoleQuery = "INSERT INTO roleBindings (`account`, `role`) SELECT ?, roles.id FROM roles WHERE roles.name = ?";
|
||||
constexpr const char* selectHash = "SELECT password FROM accounts where login = ?";
|
||||
|
||||
static const std::filesystem::path buildSQLPath = "database";
|
||||
|
||||
struct ResDeleter {
|
||||
void operator () (MYSQL_RES* res) {
|
||||
mysql_free_result(res);
|
||||
}
|
||||
};
|
||||
|
||||
MySQL::MySQL():
|
||||
DBInterface(Type::mysql),
|
||||
connection(),
|
||||
|
@ -231,7 +227,11 @@ unsigned int MySQL::registerAccount(const std::string& login, const std::string&
|
|||
std::string h = hash;
|
||||
addAcc.bind(l.data(), MYSQL_TYPE_STRING);
|
||||
addAcc.bind(h.data(), MYSQL_TYPE_STRING);
|
||||
addAcc.execute();
|
||||
try {
|
||||
addAcc.execute();
|
||||
} catch (const Duplicate& dup) {
|
||||
throw DuplicateLogin(dup.what());
|
||||
}
|
||||
|
||||
unsigned int id = lastInsertedId();
|
||||
static std::string defaultRole("default");
|
||||
|
@ -245,6 +245,24 @@ unsigned int MySQL::registerAccount(const std::string& login, const std::string&
|
|||
return id;
|
||||
}
|
||||
|
||||
std::string MySQL::getAccountHash(const std::string& login) {
|
||||
std::string l = login;
|
||||
MYSQL* con = &connection;
|
||||
|
||||
Statement getHash(con, selectHash);
|
||||
getHash.bind(l.data(), MYSQL_TYPE_STRING);
|
||||
getHash.execute();
|
||||
|
||||
std::vector<std::vector<std::string>> result = getHash.fetchResult();
|
||||
if (result.empty())
|
||||
throw NoLogin("Couldn't find login " + l);
|
||||
|
||||
if (result[0].empty())
|
||||
throw std::runtime_error("Error with the query \"selectHash\"");
|
||||
|
||||
return result[0][0];
|
||||
}
|
||||
|
||||
unsigned int MySQL::lastInsertedId() {
|
||||
MYSQL* con = &connection;
|
||||
int result = mysql_query(con, lastIdQuery);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
class MySQL : public DBInterface {
|
||||
class Statement;
|
||||
class Transaction;
|
||||
|
||||
|
||||
public:
|
||||
MySQL();
|
||||
~MySQL() override;
|
||||
|
@ -29,6 +31,7 @@ public:
|
|||
void setVersion(uint8_t version) override;
|
||||
|
||||
unsigned int registerAccount(const std::string& login, const std::string& hash) override;
|
||||
std::string getAccountHash(const std::string& login) override;
|
||||
|
||||
private:
|
||||
void executeFile(const std::filesystem::path& relativePath);
|
||||
|
@ -40,4 +43,10 @@ protected:
|
|||
std::string login;
|
||||
std::string password;
|
||||
std::string database;
|
||||
|
||||
struct ResDeleter {
|
||||
void operator () (MYSQL_RES* res) {
|
||||
mysql_free_result(res);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
#include "mysqld_error.h"
|
||||
|
||||
#include "database/exceptions.h"
|
||||
|
||||
static uint64_t TIME_LENGTH = sizeof(MYSQL_TIME);
|
||||
|
||||
MySQL::Statement::Statement(MYSQL* connection, const char* statement):
|
||||
|
@ -44,11 +48,68 @@ void MySQL::Statement::bind(void* value, enum_field_types type, bool usigned) {
|
|||
}
|
||||
|
||||
void MySQL::Statement::execute() {
|
||||
int result = mysql_stmt_bind_param(stmt.get(), param.data());
|
||||
MYSQL_STMT* raw = stmt.get();
|
||||
int result = mysql_stmt_bind_param(raw, param.data());
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Error binding statement: ") + mysql_stmt_error(stmt.get()));
|
||||
throw std::runtime_error(std::string("Error binding statement: ") + mysql_stmt_error(raw));
|
||||
|
||||
result = mysql_stmt_execute(stmt.get());
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Error executing statement: ") + mysql_stmt_error(stmt.get()));
|
||||
result = mysql_stmt_execute(raw);
|
||||
if (result != 0) {
|
||||
int errcode = mysql_stmt_errno(raw);
|
||||
std::string text = mysql_stmt_error(raw);
|
||||
switch (errcode) {
|
||||
case ER_DUP_ENTRY:
|
||||
throw Duplicate("Error executing statement: " + text);
|
||||
default:
|
||||
throw std::runtime_error("Error executing statement: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> MySQL::Statement::fetchResult() {
|
||||
MYSQL_STMT* raw = stmt.get();
|
||||
if (mysql_stmt_store_result(raw) != 0)
|
||||
throw std::runtime_error(std::string("Error fetching statement result: ") + mysql_stmt_error(raw)); //TODO not sure if it's valid here
|
||||
|
||||
MYSQL_RES* meta = mysql_stmt_result_metadata(raw);
|
||||
if (meta == nullptr)
|
||||
throw std::runtime_error(std::string("Error fetching statement result: ") + mysql_stmt_error(raw)); //TODO not sure if it's valid here
|
||||
|
||||
std::unique_ptr<MYSQL_RES, ResDeleter> mt(meta);
|
||||
unsigned int numColumns = mysql_num_fields(meta);
|
||||
MYSQL_BIND bind[numColumns];
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
std::vector<std::string> line(numColumns);
|
||||
std::vector<long unsigned int> lengths(numColumns);
|
||||
for (unsigned int i = 0; i < numColumns; ++i) {
|
||||
MYSQL_FIELD *field = mysql_fetch_field_direct(meta, i);
|
||||
|
||||
switch (field->type) {
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported data fetching statement result " + std::to_string(field->type));
|
||||
}
|
||||
line[i].resize(field->length);
|
||||
bind[i].buffer_type = field->type;
|
||||
bind[i].buffer = line[i].data();
|
||||
bind[i].buffer_length = field->length;
|
||||
bind[i].length = &lengths[i];
|
||||
}
|
||||
|
||||
if (mysql_stmt_bind_result(raw, bind) != 0)
|
||||
throw std::runtime_error(std::string("Error binding on fetching statement result: ") + mysql_stmt_error(raw));
|
||||
|
||||
std::vector<std::vector<std::string>> result;
|
||||
while (mysql_stmt_fetch(raw) == 0) {
|
||||
std::vector<std::string>& row = result.emplace_back(numColumns);
|
||||
for (unsigned int i = 0; i < numColumns; ++i)
|
||||
row[i] = std::string(line[i].data(), lengths[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ public:
|
|||
|
||||
void bind(void* value, enum_field_types type, bool usigned = false);
|
||||
void execute();
|
||||
std::vector<std::vector<std::string>> fetchResult();
|
||||
|
||||
private:
|
||||
std::unique_ptr<MYSQL_STMT, STMTDeleter> stmt;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "transaction.h"
|
||||
|
||||
MySQL::Transaction::Transaction(MYSQL* connection):
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mysql.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue