added user authentication and updated README.md

This commit is contained in:
kdeng00
2019-09-24 22:29:09 -04:00
parent e936c2da17
commit 1b8c28e67b
11 changed files with 492 additions and 258 deletions
+33 -32
View File
@@ -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.
@@ -73,7 +73,7 @@ From the Application page, copy the client id and client secret. These values wi
<h1 align="center">
<img src="Images/Configuration/api_cred.png" width=100%>
</h1>
Enter the information in the corresponding ``authcredentials.json`` file
Enter the information in the corresponding ``authcredentials.json`` file
```Json
{
"domain": "somedomain.auth0.com",
@@ -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
+44 -29
View File
@@ -11,44 +11,59 @@
#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:
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p)
{ }
LoginController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
:oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
public:
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p)
{ }
LoginController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
:oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController)
#include OATPP_CODEGEN_BEGIN(ApiController)
ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
OATPP_LOGI("icarus", "logging in");
ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
OATPP_LOGI("icarus", "logging in");
manager::TokenManager tok;
auto token = tok.retrieveToken(m_bConf);
manager::UserManager usrMgr(m_bConf);
auto user = manager::UserManager::userDtoConv(usr);
auto logRes = dto::LoginResultDto::createShared();
logRes->id = 0; // TODO: change this later on to something meaningful
logRes->username = usr->username->c_str();
logRes->token = token.accessToken.c_str();
logRes->token_type = token.tokenType.c_str();
logRes->expiration = token.expiration;
logRes->message = "Successful";
return createDtoResponse(Status::CODE_200, logRes);
if (!usrMgr.doesUserExist(user)) {
std::cout << "user does not exist" << std::endl;
return createResponse(Status::CODE_401, "invalid credentials");
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string exe_path;
model::BinaryPath m_bConf;
};
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 or remove it
logRes->username = usr->username->c_str();
logRes->token = token.accessToken.c_str();
logRes->token_type = token.tokenType.c_str();
logRes->expiration = token.expiration;
logRes->message = "Successful";
return createDtoResponse(Status::CODE_200, logRes);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string exe_path;
model::BinaryPath m_bConf;
};
}
#endif
+37 -22
View File
@@ -7,36 +7,51 @@
#include "database/BaseRepository.h"
#include "model/Models.h"
#include "type/SaltFilter.h"
#include "type/UserFilter.h"
namespace database {
class UserRepository : BaseRepository {
public:
UserRepository(const model::BinaryPath&);
class UserRepository : BaseRepository {
public:
UserRepository(const model::BinaryPath&);
model::User retrieveUserRecord(model::User&, type::UserFilter);
model::User retrieveUserRecord(model::User&, type::UserFilter);
model::PassSec retrieverUserSaltRecord(model::PassSec&, type::SaltFilter);
void saveUserRecord(const model::User&);
private:
struct UserLengths;
struct UserLengths
{
unsigned long firstnameLength;
unsigned long lastnameLength;
unsigned long phoneLength;
unsigned long emailLength;
unsigned long usernameLength;
unsigned long passwordLength;
};
bool doesUserRecordExist(const model::User&, type::UserFilter);
std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&, std::shared_ptr<UserLengths>);
std::shared_ptr<MYSQL_BIND> valueBind(model::User&, std::tuple<char*, char*, char*, char*, char*, char*>&);
std::shared_ptr<UserLengths> fetchUserLengths(const model::User&);
void saveUserRecord(const model::User&);
void saveUserSalt(const model::PassSec&);
private:
struct UserLengths;
struct SaltLengths;
std::tuple<char*, char*, char*, char*, char*, char*> fetchUV();
model::User parseRecord(MYSQL_STMT*);
struct UserLengths
{
unsigned long firstnameLength;
unsigned long lastnameLength;
unsigned long phoneLength;
unsigned long emailLength;
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*);
};
}
+13 -11
View File
@@ -6,20 +6,22 @@
#include "dto/LoginResultDto.hpp"
#include "model/Models.h"
namespace manager
namespace manager {
class UserManager
{
class UserManager
{
public:
UserManager(const model::BinaryPath&);
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:
model::BinaryPath m_bConf;
};
void printUser(const model::User&);
void registerUser(model::User&);
static model::User userDtoConv(dto::UserDto::ObjectWrapper&);
private:
model::BinaryPath m_bConf;
};
}
#endif
+135 -134
View File
@@ -4,162 +4,163 @@
#include <string>
#include <vector>
namespace model
namespace model {
struct Song
{
struct Song
Song() = default;
Song(const int id) : id(id) { }
int id;
std::string title;
std::string artist;
std::string album;
std::string genre;
int year;
int duration;
int track;
int disc;
std::string songPath;
std::vector<unsigned char> data;
int coverArtId;
int artistId;
int albumId;
int genreId;
int yearId;
};
struct Artist
{
Artist() = default;
Artist(const Song& song)
{
Song() = default;
Song(const int id) : id(id) { }
id = song.artistId;
artist = song.artist;
}
Artist(const int id) : id(id) { }
int id;
std::string title;
std::string artist;
std::string album;
std::string genre;
int year;
int duration;
int track;
int disc;
std::string songPath;
std::vector<unsigned char> data;
int coverArtId;
int artistId;
int albumId;
int genreId;
int yearId;
};
int id;
std::string artist;
};
struct Artist
struct Album
{
Album() = default;
Album(const Song& song)
{
Artist() = default;
Artist(const Song& song)
{
id = song.artistId;
artist = song.artist;
}
Artist(const int id) : id(id) { }
id = song.albumId;
title = song.album;
year = song.year;
}
Album(const int id) : id(id) { }
int id;
std::string artist;
};
int id;
std::string title;
int year;
std::vector<Song> songs;
};
struct Album
struct Genre
{
Genre() = default;
Genre(const Song& song)
{
Album() = default;
Album(const Song& song)
{
id = song.albumId;
title = song.album;
year = song.year;
}
Album(const int id) : id(id) { }
id = song.genreId;
category = song.genre;
}
Genre(const int id) : id(id) { }
int id;
std::string title;
int year;
std::vector<Song> songs;
};
int id;
std::string category;
struct Genre
};
struct Year
{
Year() = default;
Year(const Song& song)
{
Genre() = default;
Genre(const Song& song)
{
id = song.genreId;
category = song.genre;
}
Genre(const int id) : id(id) { }
id = song.yearId;
year = song.year;
}
Year(const int id) : id(id) { }
int id;
std::string category;
int id;
int year;
};
};
struct Year
struct Cover
{
Cover() = default;
Cover(const Song& song)
{
Year() = default;
Year(const Song& song)
{
id = song.yearId;
year = song.year;
}
Year(const int id) : id(id) { }
id = song.coverArtId;
songTitle = song.title;
}
Cover(const int id) : id(id) { }
int id;
int year;
};
int id;
std::string songTitle;
std::string imagePath;
// Not being used but it should be
std::vector<unsigned char> data;
};
struct Cover
{
Cover() = default;
Cover(const Song& song)
{
id = song.coverArtId;
songTitle = song.title;
}
Cover(const int id) : id(id) { }
struct LoginResult
{
int userId;
std::string username;
std::string accessToken;
std::string tokenType;
std::string message;
int expiration;
};
int id;
std::string songTitle;
std::string imagePath;
// Not being used but it should be
std::vector<unsigned char> data;
};
struct User
{
int id;
std::string firstname;
std::string lastname;
std::string email;
std::string phone;
std::string username;
std::string password;
};
struct LoginResult
{
int userId;
std::string username;
std::string accessToken;
std::string tokenType;
std::string message;
int expiration;
};
struct PassSec
{
int id;
std::string hashPassword;
std::string salt;
int userId;
};
struct User
{
int id;
std::string firstname;
std::string lastname;
std::string email;
std::string phone;
std::string username;
std::string password;
};
struct AuthCredentials
{
std::string domain;
std::string apiIdentifier;
std::string clientId;
std::string clientSecret;
std::string uri;
std::string endpoint;
};
struct PassSec
{
std::string hashPassword;
std::string salt;
};
struct DatabaseConnection
{
std::string server;
std::string username;
std::string password;
std::string database;
};
struct AuthCredentials
{
std::string domain;
std::string apiIdentifier;
std::string clientId;
std::string clientSecret;
std::string uri;
std::string endpoint;
};
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) { }
struct DatabaseConnection
{
std::string server;
std::string username;
std::string password;
std::string database;
};
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;
};
std::string path;
};
}
#endif
+2 -1
View File
@@ -5,7 +5,8 @@ namespace type {
enum class SaltFilter
{
id = 0,
salt
salt,
userId
};
}
+11 -12
View File
@@ -6,22 +6,21 @@
#include "model/Models.h"
namespace utility
namespace utility {
class MetadataRetriever
{
class MetadataRetriever
{
public:
model::Song retrieveMetadata(std::string&);
public:
model::Song retrieveMetadata(std::string&);
model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyCoverArt(const model::Song&, model::Cover&);
model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyCoverArt(const model::Song&, model::Cover&);
bool songContainsCoverArt(const model::Song&);
bool songContainsCoverArt(const model::Song&);
void updateMetadata(model::Song&, const model::Song&);
private:
};
void updateMetadata(model::Song&, const model::Song&);
private:
};
}
#endif
+8 -6
View File
@@ -6,12 +6,14 @@
#include "model/Models.h"
namespace utility {
class PasswordEncryption {
public:
model::PassSec hashPassword(const model::User&);
private:
int saltSize();
};
class PasswordEncryption {
public:
model::PassSec hashPassword(const model::User&);
bool isPasswordValid(const model::User&, const model::PassSec&);
private:
int saltSize();
};
}
#endif
+159
View File
@@ -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
View File
@@ -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;
}
}
+11
View File
@@ -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;