finnow/finnow-api/source/auth/api.d

79 lines
2.7 KiB
D

/// API endpoints for authentication-related functions, like registration and login.
module auth.api;
import handy_httpd;
import handy_httpd.components.optional;
import slf4d;
import asdf;
import auth.model;
import auth.data;
import auth.service;
import auth.data_impl_fs;
void postLogin(ref HttpRequestContext ctx) {
LoginCredentials loginCredentials;
try {
loginCredentials = deserialize!(LoginCredentials)(ctx.request.readBodyAsString());
} catch (Exception e) {
ctx.response.status = HttpStatus.BAD_REQUEST;
}
if (!validateUsername(loginCredentials.username)) {
ctx.response.status = HttpStatus.UNAUTHORIZED;
return;
}
UserRepository userRepo = new FileSystemUserRepository();
Optional!User optionalUser = userRepo.findByUsername(loginCredentials.username);
if (optionalUser.isNull) {
ctx.response.status = HttpStatus.UNAUTHORIZED;
return;
}
import botan.passhash.bcrypt : checkBcrypt;
if (!checkBcrypt(loginCredentials.password, optionalUser.value.passwordHash)) {
ctx.response.status = HttpStatus.UNAUTHORIZED;
return;
}
string token = generateAccessToken(optionalUser.value);
ctx.response.status = HttpStatus.OK;
TokenResponse resp = TokenResponse(token);
ctx.response.writeBodyString(serializeToJson(resp), "application/json");
}
void postRegister(ref HttpRequestContext ctx) {
RegistrationData registrationData;
try {
registrationData = deserialize!(RegistrationData)(ctx.request.readBodyAsString());
} catch (Exception e) {
ctx.response.status = HttpStatus.BAD_REQUEST;
return;
}
if (!validateUsername(registrationData.username)) {
ctx.response.status = HttpStatus.BAD_REQUEST;
ctx.response.writeBodyString("Invalid username.");
return;
}
if (!validatePassword(registrationData.password)) {
ctx.response.status = HttpStatus.BAD_REQUEST;
ctx.response.writeBodyString("Invalid password.");
return;
}
UserRepository userRepo = new FileSystemUserRepository();
if (!userRepo.findByUsername(registrationData.username).isNull) {
ctx.response.status = HttpStatus.BAD_REQUEST;
ctx.response.writeBodyString("Username is taken.");
return;
}
import botan.passhash.bcrypt : generateBcrypt;
import botan.rng.auto_rng;
RandomNumberGenerator rng = new AutoSeededRNG();
string passwordHash = generateBcrypt(registrationData.password, rng, 12);
userRepo.createUser(registrationData.username, passwordHash);
infoF!"Created user: %s"(registrationData.username);
}
void getMyUser(ref HttpRequestContext ctx) {
AuthContext auth = getAuthContext(ctx);
ctx.response.writeBodyString(auth.user.username);
}