added user authentication and updated README.md
This commit is contained in:
@@ -43,10 +43,10 @@ Create the API and enter an approrpiate name and identified. For the identified,
|
||||
Replace [domain] with the domain name of the created tenant. This can be found in the Default App from the Application menu. Replace [identifier] with the identifer root name in the appsettings environment file. Not the friendly name but the root name of the identifier, omitting the http protocol and the *api* path.
|
||||
|
||||
```Json
|
||||
"Auth0": {
|
||||
"Domain": "[domain].auth0.com",
|
||||
"ApiIdentifier": "https://[identifier]/api"
|
||||
},
|
||||
"domain": "[domain].auth0.com",
|
||||
"api_identifier": "https://[identifier]/api",
|
||||
"client_id": "iamunique",
|
||||
"client_secret": "Icankeepasecret"
|
||||
```
|
||||
|
||||
For the sake of this section, I will not go over configuring the API to accept the signing algorithm since it has already been configured in the [Startip](Startup.cs).cs file. Click on permissions to create the permissions for the API.
|
||||
@@ -88,10 +88,10 @@ Enter the information in the corresponding ``authcredentials.json`` file
|
||||
For the purposes of properly uploading, downloading, updating, deleting, and streaming songs the API filesystem paths must be configured. For that purpose you have to open the ``paths.json`` file. What is meant by this is that the `root_music_path` directory where all music will be stored must exist. The `cover_root_path`, `archive_root_path`, and `temp_root_path` paths must exist and be accessible. An example on a Linux system:
|
||||
```Json
|
||||
{
|
||||
"root_music_path": "/home/dev/null/music/",
|
||||
"temp_root_path": "/home/dev/null/music/temp/",
|
||||
"cover_root_path": "/home/dev/null/music/coverArt/",
|
||||
"archive_root_path": "/home/dev/null/music/archive/"
|
||||
"root_music_path": "/dev/null/music/",
|
||||
"temp_root_path": "/dev/null/music/temp/",
|
||||
"cover_root_path": "/dev/null/music/coverArt/",
|
||||
"archive_root_path": "/dev/null/music/archive/"
|
||||
}
|
||||
```
|
||||
* `root_music_path` - Where music will be stored in the following convention: *`Artist/Album/Songs`*
|
||||
@@ -104,55 +104,56 @@ For the purposes of properly uploading, downloading, updating, deleting, and str
|
||||
|
||||
### Database connection string
|
||||
|
||||
In order for Database functionality to be operable, there must be a valid connection string and credentials with appropriate permissions. **At the moment there is only support for MySQL**. Depending on your environment `Release` or `Debug` you will need to edit the appsettings.json or appsettings.Development.json accordingly. An example of the fields to change are below:
|
||||
In order for Database functionality to be operable, there must be a valid connection string and MySQL credentials with appropriate permissions. **At the moment there is only support for MySQL**. Edit the database.json file accordingly. An example of the fields to change are below:
|
||||
```Json
|
||||
{
|
||||
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=localhost;Database=my_db;Uid=admin;Pwd=toughpassword;"
|
||||
}
|
||||
"server": "localhost",
|
||||
"database": "my_db",
|
||||
"username": "admin",
|
||||
"password": "toughpassword"
|
||||
|
||||
}
|
||||
```
|
||||
* Server - The address or domain name of the MySQL server
|
||||
* Database - The database name
|
||||
* Uid - Username
|
||||
* Password - Self-explanatory
|
||||
* server - The address or domain name of the MySQL server
|
||||
* database - The database name
|
||||
* user - Username
|
||||
* password - Self-explanatory
|
||||
|
||||
The only requirement of the User is that the user should have full permissions to the database as well as permissions to create a database. Other than that, that is all that is required.
|
||||
|
||||
### Migrations
|
||||
### Database
|
||||
|
||||
Prior to starting the API, the Migrations must be applied. There are 6 tables with migrations being applied and thy are:
|
||||
* Users
|
||||
Prior to starting the API, the database must be created. The following tables are required:
|
||||
* User
|
||||
* Song
|
||||
* Album
|
||||
* Artist
|
||||
* Year
|
||||
* Genre
|
||||
* CoverArt
|
||||
|
||||
There is a script for Linux systems to apply these migrations, it can be found in the [Scripts/Migrations/Linux](https://github.com/amazing-username/Icarus/blob/master/Scripts/Migrations/Linux/AddUpdate.sh) directory. Just merely execute:
|
||||
There is a MySQL script to create these tables, it can be found in the [Scripts/MySQL/](https://github.com/amazing-username/Icarus/blob/master/Scripts/MySQL/create_database.sql) directory. Just merely execute:
|
||||
```shell
|
||||
scripts/Migrations/Linux/AddUpdate.sh
|
||||
mysql -u ** -p < Scripts/MySQL/create_database.sql
|
||||
```
|
||||
Or you can manually add the migrations like so for each migration:
|
||||
```shell
|
||||
dotnet ef migrations Add [Migration] --context [Migration]Context
|
||||
```
|
||||
Then update the migrations to the database like so<sup>*</sup>:
|
||||
```shell
|
||||
dotnet ef database update --context [Migration]Context
|
||||
```
|
||||
From this point the database has been successfully configured. Metadata and song filesystem locations can be saved.
|
||||
|
||||
<sup>*</sup> Will only need to execute this for UserContext and SongContext because the Song table has relational constraints with Album, Artist, Year, and Genre.
|
||||
From this point the database has been successfully created. Metadata and song filesystem locations can be saved.
|
||||
|
||||
|
||||
## Building and Running
|
||||
```
|
||||
git clone --recursive https://github.com/kdeng00/icarus
|
||||
cd 3rdparty/libbcrypt/
|
||||
make
|
||||
cp bcrypt.a libbcrypt.a
|
||||
cp bcrypt.o libbcrypt.o
|
||||
cd ../..
|
||||
mkdir build
|
||||
cd build
|
||||
conan install ..
|
||||
cmake ..
|
||||
make
|
||||
bin/icarus
|
||||
```
|
||||
Runs the server on localhost port 5002
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
#include "dto/LoginResultDto.hpp"
|
||||
#include "manager/TokenManager.h"
|
||||
#include "manager/UserManager.h"
|
||||
#include "model/Models.h"
|
||||
|
||||
namespace controller
|
||||
namespace controller {
|
||||
class LoginController : public oatpp::web::server::api::ApiController
|
||||
{
|
||||
class LoginController : public oatpp::web::server::api::ApiController
|
||||
{
|
||||
public:
|
||||
public:
|
||||
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
|
||||
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p)
|
||||
{ }
|
||||
@@ -31,11 +31,26 @@ namespace controller
|
||||
ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
|
||||
OATPP_LOGI("icarus", "logging in");
|
||||
|
||||
manager::UserManager usrMgr(m_bConf);
|
||||
auto user = manager::UserManager::userDtoConv(usr);
|
||||
|
||||
if (!usrMgr.doesUserExist(user)) {
|
||||
std::cout << "user does not exist" << std::endl;
|
||||
return createResponse(Status::CODE_401, "invalid credentials");
|
||||
}
|
||||
|
||||
std::cout << "user exists" << std::endl;
|
||||
|
||||
if (!usrMgr.validatePassword(user)) {
|
||||
std::cout << "password is not valid" << std::endl;
|
||||
return createResponse(Status::CODE_401, "invalid credentials");
|
||||
}
|
||||
|
||||
manager::TokenManager tok;
|
||||
auto token = tok.retrieveToken(m_bConf);
|
||||
|
||||
auto logRes = dto::LoginResultDto::createShared();
|
||||
logRes->id = 0; // TODO: change this later on to something meaningful
|
||||
logRes->id = 0; // TODO: change this later on to something meaningful or remove it
|
||||
logRes->username = usr->username->c_str();
|
||||
logRes->token = token.accessToken.c_str();
|
||||
logRes->token_type = token.tokenType.c_str();
|
||||
@@ -46,9 +61,9 @@ namespace controller
|
||||
}
|
||||
|
||||
#include OATPP_CODEGEN_END(ApiController)
|
||||
private:
|
||||
private:
|
||||
std::string exe_path;
|
||||
model::BinaryPath m_bConf;
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,18 +7,25 @@
|
||||
|
||||
#include "database/BaseRepository.h"
|
||||
#include "model/Models.h"
|
||||
#include "type/SaltFilter.h"
|
||||
#include "type/UserFilter.h"
|
||||
|
||||
namespace database {
|
||||
class UserRepository : BaseRepository {
|
||||
public:
|
||||
class UserRepository : BaseRepository {
|
||||
public:
|
||||
UserRepository(const model::BinaryPath&);
|
||||
|
||||
model::User retrieveUserRecord(model::User&, type::UserFilter);
|
||||
model::PassSec retrieverUserSaltRecord(model::PassSec&, type::SaltFilter);
|
||||
|
||||
bool doesUserRecordExist(const model::User&, type::UserFilter);
|
||||
|
||||
void saveUserRecord(const model::User&);
|
||||
private:
|
||||
void saveUserSalt(const model::PassSec&);
|
||||
private:
|
||||
struct UserLengths;
|
||||
struct SaltLengths;
|
||||
|
||||
struct UserLengths
|
||||
{
|
||||
unsigned long firstnameLength;
|
||||
@@ -28,15 +35,23 @@ namespace database {
|
||||
unsigned long usernameLength;
|
||||
unsigned long passwordLength;
|
||||
};
|
||||
struct SaltLengths
|
||||
{
|
||||
unsigned long saltLength;
|
||||
};
|
||||
|
||||
std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&, std::shared_ptr<UserLengths>);
|
||||
std::shared_ptr<MYSQL_BIND> insertSaltValues(const model::PassSec&, std::shared_ptr<SaltLengths>);
|
||||
std::shared_ptr<MYSQL_BIND> valueBind(model::User&, std::tuple<char*, char*, char*, char*, char*, char*>&);
|
||||
std::shared_ptr<MYSQL_BIND> saltValueBind(model::PassSec&, char*);
|
||||
std::shared_ptr<UserLengths> fetchUserLengths(const model::User&);
|
||||
std::shared_ptr<SaltLengths> fetchSaltLengths(const model::PassSec&);
|
||||
|
||||
std::tuple<char*, char*, char*, char*, char*, char*> fetchUV();
|
||||
|
||||
model::User parseRecord(MYSQL_STMT*);
|
||||
};
|
||||
model::PassSec parseSaltRecord(MYSQL_STMT*);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,20 +6,22 @@
|
||||
#include "dto/LoginResultDto.hpp"
|
||||
#include "model/Models.h"
|
||||
|
||||
namespace manager
|
||||
namespace manager {
|
||||
class UserManager
|
||||
{
|
||||
class UserManager
|
||||
{
|
||||
public:
|
||||
public:
|
||||
UserManager(const model::BinaryPath&);
|
||||
|
||||
model::User userDtoConv(dto::UserDto::ObjectWrapper&);
|
||||
bool doesUserExist(const model::User&);
|
||||
bool validatePassword(const model::User&);
|
||||
|
||||
void printUser(const model::User&);
|
||||
void registerUser(model::User&);
|
||||
private:
|
||||
|
||||
static model::User userDtoConv(dto::UserDto::ObjectWrapper&);
|
||||
private:
|
||||
model::BinaryPath m_bConf;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+38
-37
@@ -4,10 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace model
|
||||
namespace model {
|
||||
struct Song
|
||||
{
|
||||
struct Song
|
||||
{
|
||||
Song() = default;
|
||||
Song(const int id) : id(id) { }
|
||||
|
||||
@@ -27,10 +26,10 @@ namespace model
|
||||
int albumId;
|
||||
int genreId;
|
||||
int yearId;
|
||||
};
|
||||
};
|
||||
|
||||
struct Artist
|
||||
{
|
||||
struct Artist
|
||||
{
|
||||
Artist() = default;
|
||||
Artist(const Song& song)
|
||||
{
|
||||
@@ -41,10 +40,10 @@ namespace model
|
||||
|
||||
int id;
|
||||
std::string artist;
|
||||
};
|
||||
};
|
||||
|
||||
struct Album
|
||||
{
|
||||
struct Album
|
||||
{
|
||||
Album() = default;
|
||||
Album(const Song& song)
|
||||
{
|
||||
@@ -58,10 +57,10 @@ namespace model
|
||||
std::string title;
|
||||
int year;
|
||||
std::vector<Song> songs;
|
||||
};
|
||||
};
|
||||
|
||||
struct Genre
|
||||
{
|
||||
struct Genre
|
||||
{
|
||||
Genre() = default;
|
||||
Genre(const Song& song)
|
||||
{
|
||||
@@ -73,10 +72,10 @@ namespace model
|
||||
int id;
|
||||
std::string category;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
struct Year
|
||||
{
|
||||
struct Year
|
||||
{
|
||||
Year() = default;
|
||||
Year(const Song& song)
|
||||
{
|
||||
@@ -87,10 +86,10 @@ namespace model
|
||||
|
||||
int id;
|
||||
int year;
|
||||
};
|
||||
};
|
||||
|
||||
struct Cover
|
||||
{
|
||||
struct Cover
|
||||
{
|
||||
Cover() = default;
|
||||
Cover(const Song& song)
|
||||
{
|
||||
@@ -104,20 +103,20 @@ namespace model
|
||||
std::string imagePath;
|
||||
// Not being used but it should be
|
||||
std::vector<unsigned char> data;
|
||||
};
|
||||
};
|
||||
|
||||
struct LoginResult
|
||||
{
|
||||
struct LoginResult
|
||||
{
|
||||
int userId;
|
||||
std::string username;
|
||||
std::string accessToken;
|
||||
std::string tokenType;
|
||||
std::string message;
|
||||
int expiration;
|
||||
};
|
||||
};
|
||||
|
||||
struct User
|
||||
{
|
||||
struct User
|
||||
{
|
||||
int id;
|
||||
std::string firstname;
|
||||
std::string lastname;
|
||||
@@ -125,41 +124,43 @@ namespace model
|
||||
std::string phone;
|
||||
std::string username;
|
||||
std::string password;
|
||||
};
|
||||
};
|
||||
|
||||
struct PassSec
|
||||
{
|
||||
struct PassSec
|
||||
{
|
||||
int id;
|
||||
std::string hashPassword;
|
||||
std::string salt;
|
||||
};
|
||||
int userId;
|
||||
};
|
||||
|
||||
struct AuthCredentials
|
||||
{
|
||||
struct AuthCredentials
|
||||
{
|
||||
std::string domain;
|
||||
std::string apiIdentifier;
|
||||
std::string clientId;
|
||||
std::string clientSecret;
|
||||
std::string uri;
|
||||
std::string endpoint;
|
||||
};
|
||||
};
|
||||
|
||||
struct DatabaseConnection
|
||||
{
|
||||
struct DatabaseConnection
|
||||
{
|
||||
std::string server;
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string database;
|
||||
};
|
||||
};
|
||||
|
||||
struct BinaryPath
|
||||
{
|
||||
struct BinaryPath
|
||||
{
|
||||
BinaryPath() = default;
|
||||
BinaryPath(const char *p) : path(std::move(p)) { }
|
||||
BinaryPath(std::string& p) : path(p) { }
|
||||
BinaryPath(const std::string& p) : path(p) { }
|
||||
|
||||
std::string path;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,8 @@ namespace type {
|
||||
enum class SaltFilter
|
||||
{
|
||||
id = 0,
|
||||
salt
|
||||
salt,
|
||||
userId
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
|
||||
#include "model/Models.h"
|
||||
|
||||
namespace utility
|
||||
namespace utility {
|
||||
class MetadataRetriever
|
||||
{
|
||||
class MetadataRetriever
|
||||
{
|
||||
public:
|
||||
public:
|
||||
model::Song retrieveMetadata(std::string&);
|
||||
|
||||
model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&);
|
||||
@@ -20,8 +19,8 @@ namespace utility
|
||||
bool songContainsCoverArt(const model::Song&);
|
||||
|
||||
void updateMetadata(model::Song&, const model::Song&);
|
||||
private:
|
||||
};
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
#include "model/Models.h"
|
||||
|
||||
namespace utility {
|
||||
class PasswordEncryption {
|
||||
public:
|
||||
class PasswordEncryption {
|
||||
public:
|
||||
model::PassSec hashPassword(const model::User&);
|
||||
private:
|
||||
|
||||
bool isPasswordValid(const model::User&, const model::PassSec&);
|
||||
private:
|
||||
int saltSize();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,6 +38,8 @@ model::User UserRepository::retrieveUserRecord(model::User& user,
|
||||
break;
|
||||
}
|
||||
|
||||
qry << " LIMIT 1";
|
||||
|
||||
const auto query = qry.str();
|
||||
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||
status = mysql_stmt_bind_param(stmt, params);
|
||||
@@ -51,7 +53,86 @@ model::User UserRepository::retrieveUserRecord(model::User& user,
|
||||
return user;
|
||||
}
|
||||
|
||||
model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec, type::SaltFilter filter)
|
||||
{
|
||||
std::stringstream qry;
|
||||
auto conn = setupMysqlConnection();
|
||||
auto stmt = mysql_stmt_init(conn);
|
||||
|
||||
qry << "SELECT * FROM Salt WHERE ";
|
||||
|
||||
MYSQL_BIND params[1];
|
||||
std::memset(params, 0, sizeof(params));
|
||||
|
||||
switch (filter) {
|
||||
case type::SaltFilter::userId:
|
||||
qry << "UserId = ?";
|
||||
|
||||
params[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
params[0].buffer = (char*)&userSec.userId;
|
||||
params[0].length = 0;
|
||||
params[0].is_null = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qry << " LIMIT 1";
|
||||
|
||||
const auto query = qry.str();
|
||||
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||
status = mysql_stmt_bind_param(stmt, params);
|
||||
status = mysql_stmt_execute(stmt);
|
||||
|
||||
userSec = parseSaltRecord(stmt);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
mysql_close(conn);
|
||||
|
||||
return userSec;
|
||||
}
|
||||
|
||||
|
||||
bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter)
|
||||
{
|
||||
std::stringstream qry;
|
||||
auto conn = setupMysqlConnection();
|
||||
auto stmt = mysql_stmt_init(conn);
|
||||
|
||||
qry << "SELECT * FROM User WHERE ";
|
||||
|
||||
MYSQL_BIND params[1];
|
||||
std::memset(params, 0, sizeof(params));
|
||||
|
||||
auto userLength = user.username.size();
|
||||
switch (filter) {
|
||||
case type::UserFilter::username:
|
||||
qry << "Username = ?";
|
||||
|
||||
params[0].buffer_type = MYSQL_TYPE_STRING;
|
||||
params[0].buffer = (char*)user.username.c_str();
|
||||
params[0].length = &userLength;
|
||||
params[0].is_null = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qry << " LIMIT 1";
|
||||
|
||||
const auto query = qry.str();
|
||||
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||
status = mysql_stmt_bind_param(stmt, params);
|
||||
status = mysql_stmt_execute(stmt);
|
||||
|
||||
mysql_stmt_store_result(stmt);
|
||||
const auto rowCount = mysql_stmt_num_rows(stmt);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
mysql_close(conn);
|
||||
|
||||
return (rowCount > 0) ? true : false;
|
||||
}
|
||||
void UserRepository::saveUserRecord(const model::User& user)
|
||||
{
|
||||
std::cout << "inserting user record" << std::endl;
|
||||
@@ -75,6 +156,28 @@ void UserRepository::saveUserRecord(const model::User& user)
|
||||
mysql_close(conn);
|
||||
}
|
||||
|
||||
void UserRepository::saveUserSalt(const model::PassSec& userSec)
|
||||
{
|
||||
std::cout << "inserting user salt record" << std::endl;
|
||||
auto conn = setupMysqlConnection();
|
||||
auto stmt = mysql_stmt_init(conn);
|
||||
|
||||
std::stringstream qry;
|
||||
qry << "INSERT INTO Salt(Salt, UserId) VALUES(?,?)";
|
||||
|
||||
const auto query = qry.str();
|
||||
|
||||
auto sizes = fetchSaltLengths(userSec);
|
||||
auto values = insertSaltValues(userSec, sizes);
|
||||
|
||||
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||
status = mysql_stmt_bind_param(stmt, values.get());
|
||||
status = mysql_stmt_execute(stmt);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
mysql_close(conn);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user,
|
||||
std::shared_ptr<UserRepository::UserLengths> lengths)
|
||||
@@ -114,6 +217,22 @@ std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User&
|
||||
return values;
|
||||
}
|
||||
|
||||
std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec,
|
||||
std::shared_ptr<UserRepository::SaltLengths> lengths)
|
||||
{
|
||||
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
|
||||
|
||||
values.get()[0].buffer_type = MYSQL_TYPE_STRING;
|
||||
values.get()[0].buffer = (char*)passSec.hashPassword.c_str();
|
||||
values.get()[0].length = &(lengths->saltLength);
|
||||
|
||||
values.get()[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
values.get()[1].buffer = (char*)&passSec.userId;
|
||||
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user,
|
||||
std::tuple<char*, char*, char*, char*, char*, char*>& us)
|
||||
{
|
||||
@@ -150,6 +269,24 @@ std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user,
|
||||
return values;
|
||||
}
|
||||
|
||||
std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSalt, char *salt)
|
||||
{
|
||||
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND)));
|
||||
constexpr auto strLen = 1024;
|
||||
|
||||
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
values.get()[0].buffer = (char*)&userSalt.id;
|
||||
|
||||
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
|
||||
values.get()[1].buffer = (char*)salt;
|
||||
values.get()[1].buffer_length = strLen;
|
||||
|
||||
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
|
||||
values.get()[2].buffer = (char*)&userSalt.userId;
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(const model::User& user)
|
||||
{
|
||||
auto userLen = std::make_shared<UserLengths>();
|
||||
@@ -163,6 +300,14 @@ std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(co
|
||||
return userLen;
|
||||
}
|
||||
|
||||
std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(const model::PassSec& passSec)
|
||||
{
|
||||
auto saltLen = std::make_shared<SaltLengths>();
|
||||
saltLen->saltLength = passSec.salt.size();
|
||||
|
||||
return saltLen;
|
||||
}
|
||||
|
||||
|
||||
std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV()
|
||||
{
|
||||
@@ -195,4 +340,18 @@ model::User UserRepository::parseRecord(MYSQL_STMT *stmt)
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt)
|
||||
{
|
||||
model::PassSec userSalt;
|
||||
char saltKey[1024];
|
||||
|
||||
auto bindedValues = saltValueBind(userSalt, saltKey);
|
||||
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
|
||||
status = mysql_stmt_fetch(stmt);
|
||||
|
||||
userSalt.salt = saltKey;
|
||||
|
||||
return userSalt;
|
||||
}
|
||||
}
|
||||
|
||||
+39
-11
@@ -2,26 +2,35 @@
|
||||
|
||||
#include "database/UserRepository.h"
|
||||
#include "type/UserFilter.h"
|
||||
#include "type/SaltFilter.h"
|
||||
#include "utility/MetadataRetriever.h"
|
||||
#include "utility/PasswordEncryption.h"
|
||||
|
||||
namespace manager {
|
||||
UserManager::UserManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
|
||||
|
||||
|
||||
model::User UserManager::userDtoConv(dto::UserDto::ObjectWrapper& userDto)
|
||||
bool UserManager::doesUserExist(const model::User& user)
|
||||
{
|
||||
model::User user;
|
||||
database::UserRepository userRepo(m_bConf);
|
||||
|
||||
user.id = (userDto->userId.getPtr() == nullptr) ? 0 : userDto->userId->getValue();
|
||||
user.firstname = (userDto->firstname == nullptr) ? "" : userDto->firstname->c_str();
|
||||
user.lastname = (userDto->lastname == nullptr) ? "" : userDto->lastname->c_str();
|
||||
user.phone = (userDto->phone == nullptr) ? "" : userDto->phone->c_str();
|
||||
user.email = (userDto->email == nullptr) ? "" : userDto->email->c_str();
|
||||
user.username = (userDto->username == nullptr) ? "" : userDto->username->c_str();
|
||||
user.password = (userDto->password == nullptr) ? "" : userDto->password->c_str();
|
||||
return userRepo.doesUserRecordExist(user, type::UserFilter::username);
|
||||
}
|
||||
|
||||
return user;
|
||||
bool UserManager::validatePassword(const model::User& user)
|
||||
{
|
||||
database::UserRepository userRepo(m_bConf);
|
||||
model::User usr;
|
||||
usr.username = user.username;
|
||||
usr = userRepo.retrieveUserRecord(usr, type::UserFilter::username);
|
||||
|
||||
model::PassSec userSec;
|
||||
userSec.userId = usr.id;
|
||||
userSec = userRepo.retrieverUserSaltRecord(userSec, type::SaltFilter::userId);
|
||||
userSec.hashPassword = usr.password;
|
||||
|
||||
utility::PasswordEncryption passEnc;
|
||||
|
||||
return passEnc.isPasswordValid(user, userSec);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +62,26 @@ void UserManager::registerUser(model::User& user)
|
||||
|
||||
std::cout << usr.username << std::endl;
|
||||
usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username);
|
||||
hashed.hashPassword = usr.password;
|
||||
hashed.userId = usr.id;
|
||||
|
||||
usrRepo.saveUserSalt(hashed);
|
||||
printUser(usr);
|
||||
}
|
||||
|
||||
|
||||
model::User UserManager::userDtoConv(dto::UserDto::ObjectWrapper& userDto)
|
||||
{
|
||||
model::User user;
|
||||
|
||||
user.id = (userDto->userId.getPtr() == nullptr) ? 0 : userDto->userId->getValue();
|
||||
user.firstname = (userDto->firstname == nullptr) ? "" : userDto->firstname->c_str();
|
||||
user.lastname = (userDto->lastname == nullptr) ? "" : userDto->lastname->c_str();
|
||||
user.phone = (userDto->phone == nullptr) ? "" : userDto->phone->c_str();
|
||||
user.email = (userDto->email == nullptr) ? "" : userDto->email->c_str();
|
||||
user.username = (userDto->username == nullptr) ? "" : userDto->username->c_str();
|
||||
user.password = (userDto->password == nullptr) ? "" : userDto->password->c_str();
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,17 @@ model::PassSec PasswordEncryption::hashPassword(const model::User& user)
|
||||
return passSec;
|
||||
}
|
||||
|
||||
|
||||
bool PasswordEncryption::isPasswordValid(const model::User& user, const model::PassSec& userSalt)
|
||||
{
|
||||
std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]);
|
||||
|
||||
bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get());
|
||||
|
||||
return (userSalt.hashPassword.compare(passwordHashed.get()) == 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
int PasswordEncryption::saltSize()
|
||||
{
|
||||
constexpr auto size = 10000;
|
||||
|
||||
Reference in New Issue
Block a user