litelist/litelist-api/source/endpoints/auth.d

88 lines
3.1 KiB
D

/**
* API endpoints related to authentication.
*/
module endpoints.auth;
import handy_httpd;
import slf4d;
import std.json;
import std.typecons;
import auth;
import data.user;
void handleLogin(ref HttpRequestContext ctx) {
JSONValue loginData = ctx.request.readBodyAsJson();
if ("username" !in loginData.object || "password" !in loginData.object) {
ctx.response.setStatus(HttpStatus.BAD_REQUEST);
ctx.response.writeBodyString("Invalid login request data. Expected username and password.");
return;
}
string username = loginData.object["username"].str;
infoF!"Got login request for user \"%s\"."(username);
string password = loginData.object["password"].str;
Nullable!User userNullable = userDataSource.getUser(username);
if (userNullable.isNull) {
infoF!"User \"%s\" doesn't exist."(username);
sendUnauthenticatedResponse(ctx.response);
return;
}
User user = userNullable.get();
import botan.passhash.bcrypt : checkBcrypt;
if (!checkBcrypt(password, user.passwordHash)) {
sendUnauthenticatedResponse(ctx.response);
return;
}
JSONValue resp = JSONValue(string[string].init);
resp.object["token"] = generateToken(user, loadTokenSecret());
ctx.response.writeBodyString(resp.toString(), "application/json");
}
void renewToken(ref HttpRequestContext ctx) {
if (!validateAuthenticatedRequest(ctx, loadTokenSecret())) return;
AuthContext auth = AuthContextHolder.getOrThrow();
JSONValue resp = JSONValue(string[string].init);
resp.object["token"] = generateToken(auth.user, loadTokenSecret());
ctx.response.writeBodyString(resp.toString(), "application/json");
}
void createNewUser(ref HttpRequestContext ctx) {
JSONValue userData = ctx.request.readBodyAsJson();
string username = userData.object["username"].str;
string email = userData.object["email"].str;
string password = userData.object["password"].str;
if (!userDataSource.getUser(username).isNull) {
ctx.response.setStatus(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(password, rng, 12);
userDataSource.createUser(username, email, passwordHash);
infoF!"Created new user: %s, %s"(username, email);
}
void getMyUser(ref HttpRequestContext ctx) {
if (!validateAuthenticatedRequest(ctx, loadTokenSecret())) return;
AuthContext auth = AuthContextHolder.getOrThrow();
JSONValue resp = JSONValue(string[string].init);
resp.object["username"] = JSONValue(auth.user.username);
resp.object["email"] = JSONValue(auth.user.email);
ctx.response.writeBodyString(resp.toString(), "application/json");
}
void deleteMyUser(ref HttpRequestContext ctx) {
if (!validateAuthenticatedRequest(ctx, loadTokenSecret())) return;
AuthContext auth = AuthContextHolder.getOrThrow();
userDataSource.deleteUser(auth.user.username);
}