Skip to content

Commit 1a74cbb

Browse files
authored
Merge pull request #6 from La-404-Devinci/fix/jwt-tabs-typo
Fix/jwt tabs typo
2 parents 5468337 + 1997172 commit 1a74cbb

File tree

22 files changed

+763
-172
lines changed

22 files changed

+763
-172
lines changed

.github/workflows/lint.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
on:
2+
pull_request:
3+
branches:
4+
- master
5+
- main
6+
- features/*
7+
- feature/*
8+
- fix/*
9+
10+
jobs:
11+
lint:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v2
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v2
18+
with:
19+
node-version: "20"
20+
- name: Install dependencies (Backend)
21+
run: cd ./backend && npm install
22+
- name: Lint (Backend)
23+
run: cd ./backend && npm run lint
24+
- name: Install dependencies (Frontend)
25+
run: cd ./frontend && npm install
26+
- name: Lint (Frontend)
27+
run: cd ./frontend && npm run lint

backend/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PORT=3000

backend/.eslintrc.json

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,19 @@
33
"es2021": true,
44
"node": true
55
},
6-
"extends": [
7-
"eslint:recommended",
8-
"plugin:@typescript-eslint/recommended"
9-
],
6+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
107
"parser": "@typescript-eslint/parser",
118
"parserOptions": {
129
"ecmaVersion": "latest",
1310
"sourceType": "module"
1411
},
15-
"plugins": [
16-
"@typescript-eslint"
17-
],
12+
"plugins": ["@typescript-eslint"],
1813
"rules": {
19-
"indent": [
20-
"error",
21-
4
22-
],
23-
"linebreak-style": [
24-
"error",
25-
"unix"
26-
],
27-
"quotes": [
28-
"error",
29-
"double"
30-
],
31-
"semi": [
32-
"error",
33-
"always"
34-
]
14+
"indent": ["error", 4],
15+
"linebreak-style": ["error", "unix"],
16+
"quotes": ["error", "double"],
17+
"semi": ["error", "always"],
18+
"no-unused-vars": "off",
19+
"@typescript-eslint/no-unused-vars": ["warn"]
3520
}
3621
}

backend/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ dist
33
out
44
build
55
.env
6-
.*.local.env
6+
.*.local.env
7+
index.js

backend/auth/tokenUtils.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import Token from "../models/Token";
2+
import * as jwt from "jsonwebtoken";
3+
4+
/**
5+
* Generate a JWT token
6+
*
7+
* @param data The data to be encoded in the token
8+
* @param exp The expiration time of the token in seconds
9+
* @returns The generated JWT token
10+
*/
11+
const generateJwtToken = (data: Token, exp: number): string => {
12+
const secret: string = process.env.JWT_SECRET ?? "";
13+
const token = jwt.sign(data, secret, { expiresIn: exp });
14+
return token;
15+
};
16+
17+
/**
18+
* Check if a JWT token is valid
19+
*
20+
* @param token The token to be verified
21+
* @param targetEmail The email to be verified
22+
* @returns The decoded token
23+
*/
24+
const verifyJwtToken = (token: string, targetEmail: string): Token | null => {
25+
try {
26+
const secret: string = process.env.JWT_SECRET ?? "";
27+
const decodedToken = jwt.verify(token, secret) as jwt.JwtPayload;
28+
if (decodedToken.devinciEmail === targetEmail) {
29+
return decodedToken as Token;
30+
}
31+
return null;
32+
} catch (error) {
33+
return null;
34+
}
35+
};
36+
37+
/**
38+
* Generate an authorization token (valid for 15 minutes)
39+
*
40+
* @param devinciEmail The email of the user
41+
* @returns The generated authorization token
42+
*/
43+
const generateAuthorizationToken = (devinciEmail: string): string => {
44+
const authorizationExpiration = 60 * 15; // 15 minutes
45+
return generateJwtToken({ devinciEmail, type: "authorization" }, authorizationExpiration);
46+
};
47+
48+
/**
49+
* Generate an authentication token (valid for 14 days)
50+
*
51+
* @param devinciEmail The email of the user
52+
* @returns The generated authentication token
53+
*/
54+
const generateAuthenticationToken = (devinciEmail: string): string => {
55+
const authenticationExpiration = 60 * 60 * 24 * 14; // 14 days
56+
return generateJwtToken({ devinciEmail, type: "authentication" }, authenticationExpiration);
57+
};
58+
59+
/**
60+
* Check if a JWT token is valid
61+
*
62+
* @param token The token to be verified
63+
* @param targetEmail The email to be verified
64+
* @returns Whether the token is valid
65+
*/
66+
const verifyAuthorizationToken = (token: string, targetEmail: string): boolean => {
67+
const decodedToken = verifyJwtToken(token, targetEmail);
68+
if (decodedToken === null) return false;
69+
return decodedToken.type === "authorization";
70+
};
71+
72+
/**
73+
* Check if a JWT token is valid
74+
*
75+
* @param token The token to be verified
76+
* @param targetEmail The email to be verified
77+
* @returns Whether the token is valid
78+
*/
79+
const verifyAuthenticationToken = (token: string, targetEmail: string): boolean => {
80+
const decodedToken = verifyJwtToken(token, targetEmail);
81+
if (decodedToken === null) return false;
82+
return decodedToken.type === "authentication";
83+
};
84+
85+
export { generateAuthorizationToken, generateAuthenticationToken, verifyAuthorizationToken, verifyAuthenticationToken };

backend/controllers/Account.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import type express from "express";
2+
3+
class AccountController {
4+
/**
5+
* Send a magic link to the user's email
6+
* @server HTTP
7+
*
8+
* @param req The Express request object
9+
* @param res The Express response object
10+
*/
11+
public static async sendMagicLink(req: express.Request, res: express.Response) {
12+
// TODO: Send a magic link containing the AUTHORIZATION token to the user's email
13+
/**
14+
* VALIDATION
15+
* * Validate the user email (must be a Devinci email)
16+
*
17+
* PROCESS
18+
* * Generate an AUTHORIZATION token
19+
* * Send the magic link to the user's email
20+
*
21+
* RESPONSE
22+
* * Send a success message
23+
* * Send an error message if the email is invalid
24+
*/
25+
}
26+
27+
/**
28+
* Log the user
29+
* @server HTTP
30+
*
31+
* @param req The Express request object
32+
* @param res The Express response object
33+
*/
34+
public static async login(req: express.Request, res: express.Response) {
35+
// TODO: Log the user
36+
/**
37+
* VALIDATION
38+
* * Validate AUTHORIZATION token
39+
*
40+
* PROCESS
41+
* * Generate an AUTHENTICATION token
42+
*
43+
* RESPONSE
44+
* * Send the AUTHENTICATION token
45+
* * Send an error message if the AUTHORIZATION token is invalid
46+
* * Send an error message if the AUTHORIZATION token is expired
47+
*/
48+
}
49+
50+
// Admin routes
51+
/**
52+
* Mute/unmute a user
53+
* @server HTTP
54+
*
55+
* @param req The Express request object
56+
* @param res The Express response object
57+
*/
58+
public static async muteUser(req: express.Request, res: express.Response) {
59+
// TODO: Mute/unmute a user
60+
/**
61+
* VALIDATION
62+
* * Check if the user is an admin
63+
* * Validate the user ID
64+
*
65+
* PROCESS
66+
* * Mute/unmute the user
67+
*
68+
* RESPONSE
69+
* * Send a success message
70+
* * Send an error message if the user ID is invalid
71+
*/
72+
}
73+
74+
/**
75+
* Ban/unban a user
76+
* @server HTTP
77+
*
78+
* @param req The Express request object
79+
* @param res The Express response object
80+
*/
81+
public static async banUser(req: express.Request, res: express.Response) {
82+
// TODO: Ban/unban a user
83+
/**
84+
* VALIDATION
85+
* * Check if the user is an admin
86+
* * Validate the user ID
87+
*
88+
* PROCESS
89+
* * Ban/unban the user
90+
*
91+
* RESPONSE
92+
* * Send a success message
93+
* * Send an error message if the user ID is invalid
94+
*/
95+
}
96+
}
97+
98+
export default AccountController;

0 commit comments

Comments
 (0)