mirror of
https://github.com/Ravinou/borgwarehouse
synced 2026-03-14 14:25:46 +01:00
refactor: ⚡ tokenManager API
This commit is contained in:
parent
e4dc585fe5
commit
11aa62a548
4 changed files with 307 additions and 236 deletions
|
|
@ -1,229 +0,0 @@
|
|||
//Lib
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { authOptions } from '../auth/[...nextauth]';
|
||||
import { getServerSession } from 'next-auth/next';
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method == 'POST') {
|
||||
//Verify that the user is logged in.
|
||||
const session = await getServerSession(req, res, authOptions);
|
||||
if (!session) {
|
||||
res.status(401).json({ message: 'You must be logged in.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//The data we expect to receive
|
||||
let { name, token, creation, expiration, permissions } = req.body;
|
||||
|
||||
//Read the users file
|
||||
//Find the absolute path of the json directory
|
||||
const jsonDirectory = path.join(process.cwd(), '/config');
|
||||
let usersList = await fs.readFile(jsonDirectory + '/users.json', 'utf8');
|
||||
//Parse the usersList
|
||||
usersList = JSON.parse(usersList);
|
||||
|
||||
//1 : We check that we receive data for each variable.
|
||||
if (!name || !token || !creation || !permissions) {
|
||||
res.status(400).json({ message: 'A field is missing.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//Control the data
|
||||
const nameRegex = new RegExp('^[a-zA-Z0-9_-]{1,25}$');
|
||||
if (!nameRegex.test(name)) {
|
||||
res.status(400).json({ message: 'Your token name is not valid' });
|
||||
return;
|
||||
}
|
||||
|
||||
//2 : Verify that the user of the session exists
|
||||
const userIndex = usersList.map((user) => user.username).indexOf(session.user.name);
|
||||
if (userIndex === -1) {
|
||||
res.status(400).json({ message: 'User is incorrect.' });
|
||||
return;
|
||||
}
|
||||
const user = usersList[userIndex];
|
||||
|
||||
//3 : Check that the tokenName or tokenValue already exists
|
||||
const tokenExists =
|
||||
user.tokens && user.tokens.some((existingToken) => existingToken.name === name);
|
||||
if (tokenExists) {
|
||||
res.status(400).json({
|
||||
message: 'A token with this name already exists.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//4 : Add the new token
|
||||
try {
|
||||
let newUsersList = usersList.map((user) =>
|
||||
user.username == session.user.name
|
||||
? {
|
||||
...user,
|
||||
tokens: [
|
||||
...(user.tokens || []),
|
||||
{
|
||||
name,
|
||||
token,
|
||||
creation,
|
||||
expiration,
|
||||
permissions,
|
||||
},
|
||||
],
|
||||
}
|
||||
: user
|
||||
);
|
||||
//Stringify the new users list
|
||||
newUsersList = JSON.stringify(newUsersList);
|
||||
//Write the new JSON
|
||||
await fs.writeFile(jsonDirectory + '/users.json', newUsersList, (err) => {
|
||||
if (err) console.log(err);
|
||||
});
|
||||
res.status(200).json({ message: 'Successful API send' });
|
||||
} catch (error) {
|
||||
//Log for backend
|
||||
console.log(error);
|
||||
//Log for frontend
|
||||
if (error.code == 'ENOENT') {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'No such file or directory',
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'API error, contact the administrator',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (req.method == 'GET') {
|
||||
//Verify that the user is logged in.
|
||||
const session = await getServerSession(req, res, authOptions);
|
||||
if (!session) {
|
||||
res.status(401).json({ message: 'You must be logged in.' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
//Read the users file
|
||||
//Find the absolute path of the json directory
|
||||
const jsonDirectory = path.join(process.cwd(), '/config');
|
||||
let usersList = await fs.readFile(jsonDirectory + '/users.json', 'utf8');
|
||||
//Parse the usersList
|
||||
usersList = JSON.parse(usersList);
|
||||
|
||||
//Verify that the user of the session exists
|
||||
const userIndex = usersList.map((user) => user.username).indexOf(session.user.name);
|
||||
if (userIndex === -1) {
|
||||
res.status(400).json({
|
||||
message: 'User is incorrect. Please, logout to update your session.',
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
//Send the token list without tokens
|
||||
res.status(200).json([
|
||||
...(usersList[userIndex].tokens && Array.isArray(usersList[userIndex].tokens)
|
||||
? usersList[userIndex].tokens.map((token) => ({
|
||||
name: token.name,
|
||||
creation: token.creation,
|
||||
expiration: token.expiration,
|
||||
permissions: token.permissions,
|
||||
}))
|
||||
: []),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
//Log for backend
|
||||
console.log(error);
|
||||
//Log for frontend
|
||||
if (error.code == 'ENOENT') {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'No such file or directory',
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'API error, contact the administrator',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (req.method == 'DELETE') {
|
||||
//Verify that the user is logged in.
|
||||
const session = await getServerSession(req, res, authOptions);
|
||||
if (!session) {
|
||||
res.status(401).json({ message: 'You must be logged in.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//The data we expect to receive
|
||||
let { name } = req.body;
|
||||
|
||||
//Read the users file
|
||||
//Find the absolute path of the json directory
|
||||
const jsonDirectory = path.join(process.cwd(), '/config');
|
||||
let usersList = await fs.readFile(jsonDirectory + '/users.json', 'utf8');
|
||||
//Parse the usersList
|
||||
usersList = JSON.parse(usersList);
|
||||
|
||||
//1 : We check that we receive data for each variable.
|
||||
if (!name) {
|
||||
res.status(400).json({ message: 'A field is missing.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//2 : Verify that the user of the session exists
|
||||
const userIndex = usersList.map((user) => user.username).indexOf(session.user.name);
|
||||
if (userIndex === -1) {
|
||||
res.status(400).json({ message: 'User is incorrect.' });
|
||||
return;
|
||||
}
|
||||
const user = usersList[userIndex];
|
||||
|
||||
//Control the data
|
||||
const tokenExists = user.tokens.some((existingToken) => existingToken.name === name);
|
||||
if (!tokenExists) {
|
||||
res.status(400).json({ message: 'Token not found.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//3 : Delete the token object if it exists
|
||||
try {
|
||||
let newUsersList = usersList.map((user) =>
|
||||
user.username == session.user.name
|
||||
? {
|
||||
...user,
|
||||
tokens: user.tokens.filter((token) => token.name != name),
|
||||
}
|
||||
: user
|
||||
);
|
||||
//Stringify the new users list
|
||||
newUsersList = JSON.stringify(newUsersList);
|
||||
//Write the new JSON
|
||||
await fs.writeFile(jsonDirectory + '/users.json', newUsersList, (err) => {
|
||||
if (err) console.log(err);
|
||||
});
|
||||
res.status(200).json({ message: 'Successful API send' });
|
||||
} catch (error) {
|
||||
//Log for backend
|
||||
console.log(error);
|
||||
//Log for frontend
|
||||
if (error.code == 'ENOENT') {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'No such file or directory',
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
status: 500,
|
||||
message: 'API error, contact the administrator',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ message: 'Bad request on API' });
|
||||
}
|
||||
}
|
||||
142
pages/api/account/tokenManager.ts
Normal file
142
pages/api/account/tokenManager.ts
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import { authOptions } from '../auth/[...nextauth]';
|
||||
import { getServerSession } from 'next-auth/next';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { IntegrationTokenType, TokenPermissionsType } from '~/types/api/integration.types';
|
||||
import ApiResponse from '~/helpers/functions/apiResponse';
|
||||
import { getUsersList, updateUsersList } from '~/helpers/functions';
|
||||
import { getUnixTime } from 'date-fns';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { BorgWarehouseApiResponse } from '~/types/api/error.types';
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest & { body: Partial<IntegrationTokenType> },
|
||||
res: NextApiResponse<
|
||||
BorgWarehouseApiResponse | { token: string } | Omit<IntegrationTokenType, 'token'>[]
|
||||
>
|
||||
) {
|
||||
// Auth
|
||||
const session = await getServerSession(req, res, authOptions);
|
||||
if (!session) {
|
||||
return ApiResponse.unauthorized(res);
|
||||
}
|
||||
|
||||
if (req.method == 'POST') {
|
||||
try {
|
||||
validateRequestBody(req);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return ApiResponse.badRequest(res, error.message);
|
||||
}
|
||||
return ApiResponse.badRequest(res, 'Invalid request data');
|
||||
}
|
||||
|
||||
try {
|
||||
const { name, permissions } = req.body as IntegrationTokenType;
|
||||
|
||||
const usersList = await getUsersList();
|
||||
const user = usersList.find((u) => u.username === session.user.name);
|
||||
if (!user) {
|
||||
return ApiResponse.unauthorized(res);
|
||||
}
|
||||
|
||||
const isTokenNameAlreadyExists = user.tokens?.some((t) => t.name === name);
|
||||
if (isTokenNameAlreadyExists) {
|
||||
return ApiResponse.badRequest(res, 'Token name already exists');
|
||||
}
|
||||
|
||||
const newToken: IntegrationTokenType = {
|
||||
token: uuidv4(),
|
||||
name,
|
||||
permissions,
|
||||
creation: getUnixTime(new Date()),
|
||||
};
|
||||
|
||||
const updatedUsersList = usersList.map((u) => {
|
||||
if (u.username === user.username) {
|
||||
u.tokens = u.tokens ? [...u.tokens, newToken] : [newToken];
|
||||
}
|
||||
return u;
|
||||
});
|
||||
|
||||
await updateUsersList(updatedUsersList);
|
||||
return res.status(200).json({ token: newToken.token });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ApiResponse.serverError(res);
|
||||
}
|
||||
} else if (req.method == 'GET') {
|
||||
try {
|
||||
const usersList = await getUsersList();
|
||||
const user = usersList.find((u) => u.username === session.user.name);
|
||||
if (!user) {
|
||||
return ApiResponse.unauthorized(res);
|
||||
}
|
||||
// Send the token list without the token value
|
||||
const tokenList: Omit<IntegrationTokenType, 'token'>[] =
|
||||
user.tokens?.map((t) => ({
|
||||
name: t.name,
|
||||
creation: t.creation,
|
||||
permissions: t.permissions,
|
||||
})) || [];
|
||||
|
||||
return res.status(200).json(tokenList);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ApiResponse.serverError(res);
|
||||
}
|
||||
} else if (req.method == 'DELETE') {
|
||||
try {
|
||||
const usersList = await getUsersList();
|
||||
const user = usersList.find((u) => u.username === session.user.name);
|
||||
if (!user) {
|
||||
return ApiResponse.unauthorized(res);
|
||||
}
|
||||
|
||||
let { name } = req.body;
|
||||
if (!name) {
|
||||
return ApiResponse.badRequest(res, 'Missing token name');
|
||||
}
|
||||
|
||||
const isTokenNameExists = user.tokens?.some((t) => t.name === name);
|
||||
if (!isTokenNameExists) {
|
||||
return ApiResponse.badRequest(res, 'Token name not found');
|
||||
}
|
||||
|
||||
const updatedUsersList = usersList.map((u) => {
|
||||
if (u.username === user.username) {
|
||||
u.tokens = u.tokens?.filter((t) => t.name !== name);
|
||||
}
|
||||
return u;
|
||||
});
|
||||
|
||||
await updateUsersList(updatedUsersList);
|
||||
return ApiResponse.success(res, 'Token deleted');
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ApiResponse.serverError;
|
||||
}
|
||||
} else {
|
||||
return ApiResponse.methodNotAllowed(res);
|
||||
}
|
||||
}
|
||||
|
||||
const validateRequestBody = (
|
||||
req: NextApiRequest & { body: { name: string; permissions: TokenPermissionsType } }
|
||||
) => {
|
||||
const { name, permissions } = req.body as { name: string; permissions: TokenPermissionsType };
|
||||
if (!name || !permissions) {
|
||||
throw new Error('Missing required fields');
|
||||
}
|
||||
if (
|
||||
typeof permissions.create !== 'boolean' ||
|
||||
typeof permissions.read !== 'boolean' ||
|
||||
typeof permissions.update !== 'boolean' ||
|
||||
typeof permissions.delete !== 'boolean'
|
||||
) {
|
||||
throw new Error('Invalid permissions');
|
||||
}
|
||||
const nameRegex = new RegExp('^[a-zA-Z0-9_-]{1,25}$');
|
||||
if (!nameRegex.test(name)) {
|
||||
throw new Error('Your token name is not valid');
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue