/// API endpoints for authentication-related functions, like registration and login. module auth.api; import handy_httpd; import handy_httpd.components.optional; import slf4d; import auth.model; import auth.dao; import auth.dto; import auth.service; void postLogin(ref HttpRequestContext ctx) { LoginCredentials loginCredentials; try { loginCredentials = LoginCredentials.parse(ctx.request.readBodyAsJson()); } 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; ctx.response.writeBodyString(TokenResponse(token).toJson(), "application/json"); } void postRegister(ref HttpRequestContext ctx) { RegistrationData registrationData; try { registrationData = RegistrationData.parse(ctx.request.readBodyAsJson()); } 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); }