feat(auth): basic token validation for login + minor improvements on utils
This commit is contained in:
@@ -10,6 +10,7 @@ if (config.enableCors) {
|
||||
app.use(cors());
|
||||
}
|
||||
|
||||
app.use(express.json());
|
||||
// Global middleware
|
||||
app.use((req, _res, next) => {
|
||||
console.log(`LOG: new ${req.method} request for ${req.url}`);
|
||||
|
||||
1
back-express/src/routes/auth/auth.constants.ts
Normal file
1
back-express/src/routes/auth/auth.constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const AUTH_KEY_SIZE = 30;
|
||||
@@ -1,5 +1,33 @@
|
||||
import { Router } from "express";
|
||||
import { userService } from "../users/users.routes";
|
||||
import { AuthService } from "./auth.service";
|
||||
import { ResponseError } from "../../utils/response/response-error.model";
|
||||
|
||||
export const authRoutes = Router();
|
||||
|
||||
authRoutes.get("/signIn", async (req, res) => {});
|
||||
const authService = new AuthService(userService);
|
||||
|
||||
authRoutes.post("/login", async (req, res) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(400);
|
||||
res.send(new ResponseError(400));
|
||||
}
|
||||
const token = await authService.signIn(
|
||||
req.body.username,
|
||||
req.body.password,
|
||||
);
|
||||
if (token) {
|
||||
res.status(200);
|
||||
res.send(token);
|
||||
} else {
|
||||
res.status(401);
|
||||
res.send(new ResponseError(401));
|
||||
}
|
||||
} catch (e) {
|
||||
res.status(500);
|
||||
res.send(e);
|
||||
}
|
||||
});
|
||||
|
||||
export { authService };
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
import { sign, verify } from "jsonwebtoken";
|
||||
import UserService from "../users/users.service";
|
||||
|
||||
const secret_key = "asdf";
|
||||
import UsersService from "../users/users.service";
|
||||
import { compare } from "bcrypt";
|
||||
import { generateRandomString } from "./auth.utils";
|
||||
import { AUTH_KEY_SIZE } from "./auth.constants";
|
||||
|
||||
export class AuthService {
|
||||
constructor(private usersService: UserService) {}
|
||||
private secret_key: string;
|
||||
constructor(private usersService: UsersService) {
|
||||
this.secret_key = generateRandomString(AUTH_KEY_SIZE);
|
||||
}
|
||||
|
||||
async signIn(username: string, password: string) {
|
||||
console.log("__LOGIN", { username, password });
|
||||
const user = await this.usersService.getUserByUsername(username);
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isSamePasswd = await compare(`${password}`, `${user?.password}`);
|
||||
|
||||
if (!isSamePasswd) return null;
|
||||
|
||||
const payload = {
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
@@ -20,7 +29,7 @@ export class AuthService {
|
||||
picture: user.picture,
|
||||
};
|
||||
|
||||
const token = sign(payload, secret_key, { expiresIn: "1h" });
|
||||
const token = sign(payload, this.secret_key, { expiresIn: "1h" });
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -28,8 +37,9 @@ export class AuthService {
|
||||
const token = jwt.split(".")[1];
|
||||
if (!token) return false;
|
||||
try {
|
||||
const payload = verify(token, secret_key);
|
||||
return payload.username;
|
||||
const payload = verify(token, this.secret_key);
|
||||
if (payload instanceof Object) return payload.username;
|
||||
else return payload;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
6
back-express/src/routes/auth/auth.utils.ts
Normal file
6
back-express/src/routes/auth/auth.utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
function generateRandomString(size: number) {
|
||||
const value = Math.random() * Math.pow(10, size);
|
||||
return btoa(value.toString());
|
||||
}
|
||||
|
||||
export { generateRandomString };
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import UserService from "./users.service";
|
||||
import UsersService from "./users.service";
|
||||
import { sanitize_user } from "./users.utils";
|
||||
import { ResponseSuccess } from "../../utils/response/response-success.model";
|
||||
import { ResponseError } from "../../utils/response/response-error.model";
|
||||
|
||||
export const userRoutes = Router();
|
||||
|
||||
const userService = new UserService();
|
||||
const userService = new UsersService();
|
||||
|
||||
//TODO: block access to NON-admins or simply comment
|
||||
userRoutes.get("/", async (_, res) => {
|
||||
@@ -35,3 +35,5 @@ userRoutes.get("/:username", async (req, res) => {
|
||||
res.send(e);
|
||||
}
|
||||
});
|
||||
|
||||
export { userService };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { db_query } from "../../db";
|
||||
import { User } from "./users.types";
|
||||
|
||||
class UserService {
|
||||
class UsersService {
|
||||
constructor() {}
|
||||
|
||||
async getAllUsers(): Promise<User[]> {
|
||||
@@ -18,4 +18,4 @@ class UserService {
|
||||
}
|
||||
}
|
||||
|
||||
export default UserService;
|
||||
export default UsersService;
|
||||
|
||||
@@ -1,14 +1,33 @@
|
||||
type BasicError = {
|
||||
code: string | number;
|
||||
number?: number;
|
||||
detail?: string;
|
||||
status?: number;
|
||||
suggestion?: string;
|
||||
};
|
||||
|
||||
const code_error_mapping: Record<number, BasicError> = {
|
||||
400: {
|
||||
code: "BAD REQUEST",
|
||||
status: 400,
|
||||
},
|
||||
401: {
|
||||
code: "Unauthorized",
|
||||
status: 401,
|
||||
},
|
||||
};
|
||||
|
||||
export class ResponseError extends Error {
|
||||
public error: BasicError | number;
|
||||
constructor(
|
||||
public error: {
|
||||
code: string | number;
|
||||
number?: number;
|
||||
detail?: string;
|
||||
status?: number;
|
||||
suggestion?: string;
|
||||
},
|
||||
error: BasicError | number,
|
||||
public timestamp: number = Date.now(),
|
||||
) {
|
||||
super();
|
||||
if (error instanceof Object) {
|
||||
this.error = error;
|
||||
} else {
|
||||
this.error = code_error_mapping[error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user