better api
This commit is contained in:
+20
-17
@@ -4,8 +4,8 @@ import {IUser} from "../db/models/user";
|
||||
import {JwtAuthenticator} from "../utils/jwtAuthenticator";
|
||||
import crypto from "crypto";
|
||||
import {PasswordUtils} from "../utils/passwordUtils";
|
||||
import { asyncHandler } from "./middleware/asyncHandler";
|
||||
import { validateBody, v } from "./middleware/validate";
|
||||
import {asyncHandler} from "./middleware/asyncHandler";
|
||||
import {validateBody, v} from "./middleware/validate";
|
||||
import {ok, badRequest, unauthorized, created, conflict, notFound} from "./utils/responses";
|
||||
|
||||
export class RestAuth {
|
||||
@@ -15,24 +15,27 @@ export class RestAuth {
|
||||
router.post(
|
||||
"/register",
|
||||
validateBody({
|
||||
username: { required: true, validator: v.isString({ nonEmpty: true, min: 3 }) },
|
||||
password: { required: true, validator: v.isString({ nonEmpty: true, min: 8 }) },
|
||||
timezone: { required: true, validator: v.isString({ nonEmpty: true }) },
|
||||
location: { required: true, validator: v.isString({ nonEmpty: true }) },
|
||||
username: {required: true, validator: v.isString({nonEmpty: true, min: 3})},
|
||||
password: {required: true, validator: v.isString({nonEmpty: true, min: 8})},
|
||||
timezone: {required: true, validator: v.isString({nonEmpty: true})},
|
||||
location: {required: true, validator: v.isString({nonEmpty: true})},
|
||||
}),
|
||||
asyncHandler(async (req, res) => {
|
||||
const { username, password, timezone, location } = req.body as {
|
||||
const {username, password, timezone, location} = req.body as {
|
||||
username: string; password: string; timezone: string; location: string;
|
||||
};
|
||||
const userService = await UserService.create();
|
||||
|
||||
if (await userService.existsUserByName(username)) {
|
||||
return conflict(res, "Username already exists");
|
||||
return conflict(res, "Username already exists", {field: "username", code: "USERNAME_TAKEN"});
|
||||
}
|
||||
|
||||
const passwordValidation = PasswordUtils.validatePassword(password);
|
||||
if (!passwordValidation.valid) {
|
||||
return badRequest(res, passwordValidation.message ?? "Invalid password");
|
||||
return badRequest(res, passwordValidation.message ?? "Invalid password", {
|
||||
field: "password",
|
||||
code: "INVALID_PASSWORD_FORMAT"
|
||||
});
|
||||
}
|
||||
|
||||
const hashedPassword = await PasswordUtils.hashPassword(password);
|
||||
@@ -50,28 +53,28 @@ export class RestAuth {
|
||||
};
|
||||
|
||||
const result = await userService.createUser(newUser);
|
||||
return created(res, {user: result });
|
||||
return created(res, {user: result});
|
||||
})
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/login",
|
||||
validateBody({
|
||||
username: { required: true, validator: v.isString({ nonEmpty: true }) },
|
||||
password: { required: true, validator: v.isString({ nonEmpty: true }) },
|
||||
username: {required: true, validator: v.isString({nonEmpty: true})},
|
||||
password: {required: true, validator: v.isString({nonEmpty: true})},
|
||||
}),
|
||||
asyncHandler(async (req, res) => {
|
||||
const { username, password } = req.body as { username: string; password: string };
|
||||
const {username, password} = req.body as { username: string; password: string };
|
||||
const userService = await UserService.create();
|
||||
const user = await userService.getUserAuthByName(username);
|
||||
|
||||
if (!user) {
|
||||
return notFound(res, "User not found");
|
||||
return notFound(res, "User not found", {field: "username", code: "INVALID_USER"});
|
||||
}
|
||||
|
||||
const isValid = await PasswordUtils.comparePassword(password, user.password!);
|
||||
if (!isValid) {
|
||||
return unauthorized(res, "Invalid password");
|
||||
return unauthorized(res, "Invalid password", {field: "password", code: "INVALID_PASSWORD"});
|
||||
}
|
||||
|
||||
const jwtToken = new JwtAuthenticator(process.env.SECRET_KEY!)
|
||||
@@ -88,7 +91,7 @@ export class RestAuth {
|
||||
maxAge: 24 * 60 * 60 * 1000
|
||||
});
|
||||
|
||||
return ok(res, { token: jwtToken });
|
||||
return ok(res, {token: jwtToken});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -96,7 +99,7 @@ export class RestAuth {
|
||||
"/logout",
|
||||
asyncHandler(async (req, res) => {
|
||||
res.clearCookie('auth-token');
|
||||
return ok(res, { message: "Successfully logged out" });
|
||||
return ok(res, {message: "Successfully logged out"});
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -103,6 +103,8 @@ describe("RestAuth", () => {
|
||||
const response = await request(app).post("/auth/register").send(validRegistrationData).expect(409);
|
||||
expect(response.body.ok).toBe(false);
|
||||
expect(response.body.data.message).toBe("Username already exists");
|
||||
expect(response.body.data.details.field).toBe("username");
|
||||
expect(response.body.data.details.code).toBe("USERNAME_TAKEN");
|
||||
});
|
||||
|
||||
it("should return bad request for invalid password", async () => {
|
||||
@@ -115,6 +117,9 @@ describe("RestAuth", () => {
|
||||
expect(response.body.ok).toBe(false);
|
||||
expect(response.body.data.message).toBe("Password is not valid.");
|
||||
expect(mockPasswordUtils.hashPassword).not.toHaveBeenCalled();
|
||||
expect(response.body.data.details.field).toBe("password");
|
||||
expect(response.body.data.details.code).toBe("INVALID_PASSWORD_FORMAT");
|
||||
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -221,6 +226,9 @@ describe("RestAuth", () => {
|
||||
const response = await request(app).post("/auth/login").send(validLoginData).expect(404);
|
||||
expect(response.body.ok).toBe(false);
|
||||
expect(response.body.data.message).toBe("User not found");
|
||||
expect(response.body.data.details.field).toBe("username")
|
||||
expect(response.body.data.details.code).toBe("INVALID_USER")
|
||||
|
||||
});
|
||||
|
||||
it("should return unauthorized for invalid password", async () => {
|
||||
@@ -230,6 +238,8 @@ describe("RestAuth", () => {
|
||||
const response = await request(app).post("/auth/login").send(validLoginData).expect(401);
|
||||
expect(response.body.ok).toBe(false);
|
||||
expect(response.body.data.message).toBe("Invalid password");
|
||||
expect(response.body.data.details.field).toBe("password")
|
||||
expect(response.body.data.details.code).toBe("INVALID_PASSWORD")
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
Reference in New Issue
Block a user