Skip to content

Commit

Permalink
login and register
Browse files Browse the repository at this point in the history
  • Loading branch information
Brendon committed Nov 17, 2024
1 parent 19173dd commit 2763968
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 28 deletions.
18 changes: 6 additions & 12 deletions include/Auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,16 @@ class UserAlreadyExistsException : public AuthException {
// User model
struct User {
std::string id;
std::string username;
std::string email;
std::string passwordHash;
std::string role;
std::string createdAt;

// Constructor for creating a new user
User(const std::string& username,
const std::string& email,
// Updated constructor
User(const std::string& email,
const std::string& passwordHash,
const std::string& role = "user")
: username(username)
, email(email)
: email(email)
, passwordHash(passwordHash)
, role(role) {}

Expand Down Expand Up @@ -75,9 +72,8 @@ class AuthService {
~AuthService() = default;

// User registration and login
std::string registerUser(const std::string& username,
const std::string& email,
const std::string& password);
std::string registerUser(const std::string& email,
const std::string& password);

std::string loginUser(const std::string& email,
const std::string& password);
Expand All @@ -97,7 +93,7 @@ class AuthService {

private:
DatabaseManager& dbManager;
const std::string collection_name = "users";
const std::string collection_name = "Users";
const int JWT_EXPIRATION_HOURS = 24;
const std::string JWT_SECRET = "your-secret-key"; // In production, load from env variables

Expand All @@ -112,11 +108,9 @@ class AuthService {
// User validation
bool isValidEmail(const std::string& email);
bool isValidPassword(const std::string& password);
bool isValidUsername(const std::string& username);

// Database operations
std::vector<std::pair<std::string, std::string>> createUserDocument(
const std::string& username,
const std::string& email,
const std::string& passwordHash,
const std::string& role = "user"
Expand Down
4 changes: 4 additions & 0 deletions include/RouteController.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "Healthcare.h"
#include "Outreach.h"
#include "Shelter.h"
#include "Auth.h"

class RouteController {
private:
Expand Down Expand Up @@ -68,6 +69,9 @@ class RouteController {
void getAllHealthcareServices(const crow::request& req, crow::response& res);
void updateHealthcareService(const crow::request& req, crow::response& res);
void deleteHealthcareService(const crow::request& req, crow::response& res);

void registerUser(const crow::request& req, crow::response& res);
void loginUser(const crow::request& req, crow::response& res);
};

#endif
19 changes: 3 additions & 16 deletions src/Auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ AuthService::AuthService(DatabaseManager& dbManager) : dbManager(dbManager) {}
AuthService::AuthService() : dbManager(DatabaseManager::getInstance()) {}

// Registration
std::string AuthService::registerUser(const std::string& username,
const std::string& email,
std::string AuthService::registerUser(const std::string& email,
const std::string& password) {
// Validate input
if (!isValidEmail(email)) {
Expand All @@ -22,9 +21,6 @@ std::string AuthService::registerUser(const std::string& username,
if (!isValidPassword(password)) {
throw AuthException("Password does not meet requirements");
}
if (!isValidUsername(username)) {
throw AuthException("Invalid username format");
}

// Check if user already exists
if (findUserByEmail(email)) {
Expand All @@ -33,7 +29,7 @@ std::string AuthService::registerUser(const std::string& username,

// Hash password and create user
std::string hashedPassword = hashPassword(password);
auto userDoc = createUserDocument(username, email, hashedPassword);
auto userDoc = createUserDocument(email, hashedPassword);

try {
dbManager.insertResource(collection_name, userDoc);
Expand All @@ -48,7 +44,7 @@ std::string AuthService::registerUser(const std::string& username,
}

auto userView = result[0].view();
User newUser(username, email, hashedPassword);
User newUser(email, hashedPassword);
newUser.id = userView["_id"].get_oid().value.to_string();
return generateJWT(newUser);
} catch (const std::exception& e) {
Expand Down Expand Up @@ -141,7 +137,6 @@ std::optional<User> AuthService::findUserByEmail(const std::string& email) {
User user;
user.id = userDoc["_id"].get_oid().value.to_string();
user.email = userDoc["email"].get_utf8().value.to_string();
user.username = userDoc["username"].get_utf8().value.to_string();
user.passwordHash = userDoc["passwordHash"].get_utf8().value.to_string();
user.role = userDoc["role"].get_utf8().value.to_string();
user.createdAt = userDoc["createdAt"].get_utf8().value.to_string();
Expand All @@ -161,12 +156,6 @@ bool AuthService::isValidPassword(const std::string& password) {
return std::regex_match(password, pattern);
}

bool AuthService::isValidUsername(const std::string& username) {
// 3-20 characters, alphanumeric and underscore
const std::regex pattern(R"(^[a-zA-Z0-9_]{3,20}$)");
return std::regex_match(username, pattern);
}

// Utility Methods
int64_t AuthService::getCurrentTimestamp() {
return std::chrono::duration_cast<std::chrono::seconds>(
Expand All @@ -179,13 +168,11 @@ int64_t AuthService::getExpirationTimestamp() {
}

std::vector<std::pair<std::string, std::string>> AuthService::createUserDocument(
const std::string& username,
const std::string& email,
const std::string& passwordHash,
const std::string& role
) {
std::vector<std::pair<std::string, std::string>> content;
content.push_back({"username", username});
content.push_back({"email", email});
content.push_back({"passwordHash", passwordHash});
content.push_back({"role", role});
Expand Down
80 changes: 80 additions & 0 deletions src/RouteController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,74 @@ void RouteController::deleteHealthcareService(const crow::request& req,
}
}

void RouteController::registerUser(const crow::request& req, crow::response& res) {
try {
auto resource = bsoncxx::from_json(req.body);

// Validate required fields
if (!resource["email"] || !resource["password"]) {
res.code = 400;
res.write("Missing required fields: email and password");
res.end();
return;
}

std::string email = resource["email"].get_utf8().value.to_string();
std::string password = resource["password"].get_utf8().value.to_string();

AuthService& authService = AuthService::getInstance();
std::string token = authService.registerUser(email, password);

res.code = 201;
res.write(token);
res.end();
} catch (const UserAlreadyExistsException& e) {
res.code = 409;
res.write(e.what());
res.end();
} catch (const AuthException& e) {
res.code = 400;
res.write(e.what());
res.end();
} catch (const std::exception& e) {
res = handleException(e);
}
}

void RouteController::loginUser(const crow::request& req, crow::response& res) {
try {
auto resource = bsoncxx::from_json(req.body);

// Validate required fields
if (!resource["email"] || !resource["password"]) {
res.code = 400;
res.write("Missing required fields: email and password");
res.end();
return;
}

std::string email = resource["email"].get_utf8().value.to_string();
std::string password = resource["password"].get_utf8().value.to_string();

AuthService& authService = AuthService::getInstance();
std::string token = authService.loginUser(email, password);

res.code = 200;
res.write(token);
res.end();
} catch (const InvalidCredentialsException& e) {
res.code = 401;
res.write(e.what());
res.end();
} catch (const AuthException& e) {
res.code = 400;
res.write(e.what());
res.end();
} catch (const std::exception& e) {
res = handleException(e);
}
}

void RouteController::initRoutes(crow::SimpleApp& app) {
CROW_ROUTE(app, "/").methods(crow::HTTPMethod::GET)(
[this](const crow::request& req, crow::response& res) { index(res); });
Expand Down Expand Up @@ -976,4 +1044,16 @@ void RouteController::initRoutes(crow::SimpleApp& app) {
[this](const crow::request& req, crow::response& res) {
deleteHealthcareService(req, res);
});

CROW_ROUTE(app, "/auth/register")
.methods(crow::HTTPMethod::POST)
([this](const crow::request& req, crow::response& res) {
registerUser(req, res);
});

CROW_ROUTE(app, "/auth/login")
.methods(crow::HTTPMethod::POST)
([this](const crow::request& req, crow::response& res) {
loginUser(req, res);
});
}
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ int main(int argc, char* argv[]) {
dbManager.createCollection("Outreach");
dbManager.createCollection("Shelter");
dbManager.createCollection("Counseling");
dbManager.createCollection("Users");

crow::SimpleApp app;

Expand Down

0 comments on commit 2763968

Please sign in to comment.