diff --git a/.gitignore b/.gitignore index 7595311..9c567ce 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules/ .DS_Store .env* sas/ +sasjs_root/ tmp/ build/ sasjsbuild/ diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 923115f..eba92d4 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -323,6 +323,8 @@ components: type: boolean isAdmin: type: boolean + autoExec: + type: string required: - id - displayName @@ -352,6 +354,10 @@ components: type: boolean description: 'Account should be active or not, defaults to true' example: 'true' + autoExec: + type: string + description: 'User-specific auto-exec code' + example: '' required: - displayName - username @@ -989,6 +995,7 @@ paths: application/json: schema: $ref: '#/components/schemas/UserDetailsResponse' + description: 'Only Admin or user itself will get user autoExec code.' summary: 'Get user properties - such as group memberships, userName, displayName.' tags: - User diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 80d1837..d4b18fd 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -1,7 +1,6 @@ import express from 'express' import { Request, Security, Route, Tags, Post, Body } from 'tsoa' import { ExecuteReturnJson, ExecutionController } from './internal' -import { PreProgramVars } from '../types' import { ExecuteReturnJsonResponse } from '.' import { getPreProgramVariables, parseLogToArray } from '../utils' @@ -30,14 +29,18 @@ export class CodeController { } } -const executeSASCode = async (req: any, { code }: ExecuteSASCodePayload) => { +const executeSASCode = async ( + req: express.Request, + { code }: ExecuteSASCodePayload +) => { + const { user } = req try { const { webout, log, httpHeaders } = (await new ExecutionController().executeProgram( code, getPreProgramVariables(req), { ...req.query, _debug: 131 }, - undefined, + { userAutoExec: user?.autoExec }, true )) as ExecuteReturnJson diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 4d4df15..9de586f 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -119,6 +119,10 @@ filename _webout "${weboutPath}" mod; /* dynamic user-provided vars */ ${preProgramVarStatments} +/* user auto exec starts */ +${otherArgs?.userAutoExec} +/* user auto exec ends */ + /* actual job code */ ${program}` diff --git a/api/src/controllers/internal/FileUploadController.ts b/api/src/controllers/internal/FileUploadController.ts index 762d3ee..9593b68 100644 --- a/api/src/controllers/internal/FileUploadController.ts +++ b/api/src/controllers/internal/FileUploadController.ts @@ -1,14 +1,15 @@ +import { Request, RequestHandler } from 'express' import multer from 'multer' import { uuidv4 } from '@sasjs/utils' import { getSessionController } from '.' export class FileUploadController { private storage = multer.diskStorage({ - destination: function (req: any, file: any, cb: any) { + destination: function (req: Request, file: any, cb: any) { //Sending the intercepted files to the sessions subfolder - cb(null, req.sasSession.path) + cb(null, req.sasSession?.path) }, - filename: function (req: any, file: any, cb: any) { + filename: function (req: Request, file: any, cb: any) { //req_file prefix + unique hash added to sas request files cb(null, `req_file_${uuidv4().replace(/-/gm, '')}`) } @@ -18,7 +19,7 @@ export class FileUploadController { //It will intercept request and generate unique uuid to be used as a subfolder name //that will store the files uploaded - public preUploadMiddleware = async (req: any, res: any, next: any) => { + public preUploadMiddleware: RequestHandler = async (req, res, next) => { let session const sessionController = getSessionController() diff --git a/api/src/controllers/session.ts b/api/src/controllers/session.ts index 92a977a..0a3562a 100644 --- a/api/src/controllers/session.ts +++ b/api/src/controllers/session.ts @@ -23,8 +23,8 @@ export class SessionController { } } -const session = (req: any) => ({ - id: req.user.userId, - username: req.user.username, - displayName: req.user.displayName +const session = (req: express.Request) => ({ + id: req.user!.userId, + username: req.user!.username, + displayName: req.user!.displayName }) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index b938629..6a5d378 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -26,6 +26,7 @@ import { makeFilesNamesMap, parseLogToArray } from '../utils' +import { MulterFile } from '../types/Upload' interface ExecuteReturnJsonPayload { /** @@ -167,7 +168,7 @@ const executeReturnRaw = async ( } const executeReturnJson = async ( - req: any, + req: express.Request, _program: string ): Promise => { const sasCodePath = @@ -175,7 +176,9 @@ const executeReturnJson = async ( .join(getFilesFolder(), _program) .replace(new RegExp('/', 'g'), path.sep) + '.sas' - const filesNamesMap = req.files?.length ? makeFilesNamesMap(req.files) : null + const filesNamesMap = req.files?.length + ? makeFilesNamesMap(req.files as MulterFile[]) + : null try { const { webout, log, httpHeaders } = diff --git a/api/src/controllers/user.ts b/api/src/controllers/user.ts index 9aa66b9..9a875c7 100644 --- a/api/src/controllers/user.ts +++ b/api/src/controllers/user.ts @@ -1,3 +1,4 @@ +import express from 'express' import { Security, Route, @@ -10,7 +11,8 @@ import { Patch, Delete, Body, - Hidden + Hidden, + Request } from 'tsoa' import User, { UserPayload } from '../model/User' @@ -27,6 +29,7 @@ interface UserDetailsResponse { username: string isActive: boolean isAdmin: boolean + autoExec?: string } @Security('bearerAuth') @@ -73,13 +76,19 @@ export class UserController { } /** + * Only Admin or user itself will get user autoExec code. * @summary Get user properties - such as group memberships, userName, displayName. * @param userId The user's identifier * @example userId 1234 */ @Get('{userId}') - public async getUser(@Path() userId: number): Promise { - return getUser(userId) + public async getUser( + @Request() req: express.Request, + @Path() userId: number + ): Promise { + const { user } = req + const getAutoExec = user!.isAdmin || user!.userId == userId + return getUser(userId, getAutoExec) } /** @@ -123,7 +132,7 @@ const getAllUsers = async (): Promise => .exec() const createUser = async (data: UserPayload): Promise => { - const { displayName, username, password, isAdmin, isActive } = data + const { displayName, username, password, isAdmin, isActive, autoExec } = data // Checking if user is already in the database const usernameExist = await User.findOne({ username }) @@ -138,7 +147,8 @@ const createUser = async (data: UserPayload): Promise => { username, password: hashPassword, isAdmin, - isActive + isActive, + autoExec }) const savedUser = await user.save() @@ -148,38 +158,42 @@ const createUser = async (data: UserPayload): Promise => { displayName: savedUser.displayName, username: savedUser.username, isActive: savedUser.isActive, - isAdmin: savedUser.isAdmin + isAdmin: savedUser.isAdmin, + autoExec: savedUser.autoExec } } -const getUser = async (id: number): Promise => { +const getUser = async ( + id: number, + getAutoExec: boolean +): Promise => { const user = await User.findOne({ id }) - .select({ - _id: 0, - id: 1, - username: 1, - displayName: 1, - isAdmin: 1, - isActive: 1 - }) - .exec() + if (!user) throw new Error('User is not found.') - return user + return { + id: user.id, + displayName: user.displayName, + username: user.username, + isActive: user.isActive, + isAdmin: user.isAdmin, + autoExec: getAutoExec ? user.autoExec : undefined + } } const updateUser = async ( id: number, - data: UserPayload + data: Partial ): Promise => { - const { displayName, username, password, isAdmin, isActive } = data + const { displayName, username, password, isAdmin, isActive, autoExec } = data - const params: any = { displayName, isAdmin, isActive } + const params: any = { displayName, isAdmin, isActive, autoExec } if (username) { // Checking if user is already in the database const usernameExist = await User.findOne({ username }) - if (usernameExist?.id != id) throw new Error('Username already exists.') + if (usernameExist && usernameExist.id != id) + throw new Error('Username already exists.') params.username = username } @@ -189,18 +203,17 @@ const updateUser = async ( } const updatedUser = await User.findOneAndUpdate({ id }, params, { new: true }) - .select({ - _id: 0, - id: 1, - username: 1, - displayName: 1, - isAdmin: 1, - isActive: 1 - }) - .exec() - if (!updatedUser) throw new Error('Unable to update user') - return updatedUser + if (!updatedUser) throw new Error(`Unable to find user with id: ${id}`) + + return { + id: updatedUser.id, + username: updatedUser.username, + displayName: updatedUser.displayName, + isAdmin: updatedUser.isAdmin, + isActive: updatedUser.isActive, + autoExec: updatedUser.autoExec + } } const deleteUser = async ( diff --git a/api/src/controllers/web.ts b/api/src/controllers/web.ts index 350eef2..9b72d08 100644 --- a/api/src/controllers/web.ts +++ b/api/src/controllers/web.ts @@ -90,7 +90,8 @@ const login = async ( username: user.username, displayName: user.displayName, isAdmin: user.isAdmin, - isActive: user.isActive + isActive: user.isActive, + autoExec: user.autoExec } return { diff --git a/api/src/middlewares/authenticateToken.ts b/api/src/middlewares/authenticateToken.ts index 716c1fd..032972f 100644 --- a/api/src/middlewares/authenticateToken.ts +++ b/api/src/middlewares/authenticateToken.ts @@ -1,14 +1,27 @@ +import { RequestHandler, Request, Response, NextFunction } from 'express' import jwt from 'jsonwebtoken' import { csrfProtection } from '../app' -import { verifyTokenInDB } from '../utils' +import { fetchLatestAutoExec, verifyTokenInDB } from '../utils' -export const authenticateAccessToken = (req: any, res: any, next: any) => { +export const authenticateAccessToken: RequestHandler = async ( + req, + res, + next +) => { // if request is coming from web and has valid session // we can validate the request and check for CSRF Token if (req.session?.loggedIn) { - req.user = req.session.user + if (req.session.user) { + const user = await fetchLatestAutoExec(req.session.user) - return csrfProtection(req, res, next) + if (user) { + if (user.isActive) { + req.user = user + return csrfProtection(req, res, next) + } else return res.sendStatus(401) + } + } + return res.sendStatus(401) } authenticateToken( @@ -20,7 +33,7 @@ export const authenticateAccessToken = (req: any, res: any, next: any) => { ) } -export const authenticateRefreshToken = (req: any, res: any, next: any) => { +export const authenticateRefreshToken: RequestHandler = (req, res, next) => { authenticateToken( req, res, @@ -31,16 +44,16 @@ export const authenticateRefreshToken = (req: any, res: any, next: any) => { } const authenticateToken = ( - req: any, - res: any, - next: any, + req: Request, + res: Response, + next: NextFunction, key: string, tokenType: 'accessToken' | 'refreshToken' ) => { const { MODE } = process.env if (MODE?.trim() !== 'server') { req.user = { - userId: '1234', + userId: 1234, clientId: 'desktopModeClientId', username: 'desktopModeUsername', displayName: 'desktopModeDisplayName', diff --git a/api/src/middlewares/desktop.ts b/api/src/middlewares/desktop.ts index 3444adf..8a6f80f 100644 --- a/api/src/middlewares/desktop.ts +++ b/api/src/middlewares/desktop.ts @@ -1,11 +1,13 @@ -export const desktopRestrict = (req: any, res: any, next: any) => { +import { RequestHandler } from 'express' + +export const desktopRestrict: RequestHandler = (req, res, next) => { const { MODE } = process.env if (MODE?.trim() !== 'server') return res.status(403).send('Not Allowed while in Desktop Mode.') next() } -export const desktopUsername = (req: any, res: any, next: any) => { +export const desktopUsername: RequestHandler = (req, res, next) => { const { MODE } = process.env if (MODE?.trim() !== 'server') return res.status(200).send({ diff --git a/api/src/middlewares/verifyAdmin.ts b/api/src/middlewares/verifyAdmin.ts index 0488b9e..4ca26f7 100644 --- a/api/src/middlewares/verifyAdmin.ts +++ b/api/src/middlewares/verifyAdmin.ts @@ -1,4 +1,6 @@ -export const verifyAdmin = (req: any, res: any, next: any) => { +import { RequestHandler } from 'express' + +export const verifyAdmin: RequestHandler = (req, res, next) => { const { MODE } = process.env if (MODE?.trim() !== 'server') return next() diff --git a/api/src/middlewares/verifyAdminIfNeeded.ts b/api/src/middlewares/verifyAdminIfNeeded.ts index d657e50..d126f3c 100644 --- a/api/src/middlewares/verifyAdminIfNeeded.ts +++ b/api/src/middlewares/verifyAdminIfNeeded.ts @@ -1,8 +1,10 @@ -export const verifyAdminIfNeeded = (req: any, res: any, next: any) => { +import { RequestHandler } from 'express' + +export const verifyAdminIfNeeded: RequestHandler = (req, res, next) => { const { user } = req const userId = parseInt(req.params.userId) - if (!user.isAdmin && user.userId !== userId) { + if (!user?.isAdmin && user?.userId !== userId) { return res.status(401).send('Admin account required') } next() diff --git a/api/src/model/User.ts b/api/src/model/User.ts index 61521b5..b16719a 100644 --- a/api/src/model/User.ts +++ b/api/src/model/User.ts @@ -27,12 +27,18 @@ export interface UserPayload { * @example "true" */ isActive?: boolean + /** + * User-specific auto-exec code + * @example "" + */ + autoExec?: string } interface IUserDocument extends UserPayload, Document { id: number isAdmin: boolean isActive: boolean + autoExec: string groups: Schema.Types.ObjectId[] tokens: [{ [key: string]: string }] } @@ -66,6 +72,9 @@ const userSchema = new Schema({ type: Boolean, default: true }, + autoExec: { + type: String + }, groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }], tokens: [ { diff --git a/api/src/routes/api/auth.ts b/api/src/routes/api/auth.ts index d463b22..34a45df 100644 --- a/api/src/routes/api/auth.ts +++ b/api/src/routes/api/auth.ts @@ -26,8 +26,11 @@ authRouter.post('/token', async (req, res) => { } }) -authRouter.post('/refresh', authenticateRefreshToken, async (req: any, res) => { - const userInfo: InfoJWT = req.user +authRouter.post('/refresh', authenticateRefreshToken, async (req, res) => { + const userInfo: InfoJWT = { + userId: req.user!.userId!, + clientId: req.user!.clientId! + } try { const response = await controller.refresh(userInfo) @@ -38,8 +41,11 @@ authRouter.post('/refresh', authenticateRefreshToken, async (req: any, res) => { } }) -authRouter.delete('/logout', authenticateAccessToken, async (req: any, res) => { - const userInfo: InfoJWT = req.user +authRouter.delete('/logout', authenticateAccessToken, async (req, res) => { + const userInfo: InfoJWT = { + userId: req.user!.userId!, + clientId: req.user!.clientId! + } try { await controller.logout(userInfo) diff --git a/api/src/routes/api/group.ts b/api/src/routes/api/group.ts index fc02289..8164262 100644 --- a/api/src/routes/api/group.ts +++ b/api/src/routes/api/group.ts @@ -33,12 +33,12 @@ groupRouter.get('/', authenticateAccessToken, async (req, res) => { } }) -groupRouter.get('/:groupId', authenticateAccessToken, async (req: any, res) => { +groupRouter.get('/:groupId', authenticateAccessToken, async (req, res) => { const { groupId } = req.params const controller = new GroupController() try { - const response = await controller.getGroup(groupId) + const response = await controller.getGroup(parseInt(groupId)) res.send(response) } catch (err: any) { res.status(403).send(err.toString()) @@ -49,12 +49,15 @@ groupRouter.post( '/:groupId/:userId', authenticateAccessToken, verifyAdmin, - async (req: any, res) => { + async (req, res) => { const { groupId, userId } = req.params const controller = new GroupController() try { - const response = await controller.addUserToGroup(groupId, userId) + const response = await controller.addUserToGroup( + parseInt(groupId), + parseInt(userId) + ) res.send(response) } catch (err: any) { res.status(403).send(err.toString()) @@ -66,12 +69,15 @@ groupRouter.delete( '/:groupId/:userId', authenticateAccessToken, verifyAdmin, - async (req: any, res) => { + async (req, res) => { const { groupId, userId } = req.params const controller = new GroupController() try { - const response = await controller.removeUserFromGroup(groupId, userId) + const response = await controller.removeUserFromGroup( + parseInt(groupId), + parseInt(userId) + ) res.send(response) } catch (err: any) { res.status(403).send(err.toString()) @@ -83,12 +89,12 @@ groupRouter.delete( '/:groupId', authenticateAccessToken, verifyAdmin, - async (req: any, res) => { + async (req, res) => { const { groupId } = req.params const controller = new GroupController() try { - await controller.deleteGroup(groupId) + await controller.deleteGroup(parseInt(groupId)) res.status(200).send('Group Deleted!') } catch (err: any) { res.status(403).send(err.toString()) diff --git a/api/src/routes/api/spec/user.spec.ts b/api/src/routes/api/spec/user.spec.ts index 9289a5e..64510a2 100644 --- a/api/src/routes/api/spec/user.spec.ts +++ b/api/src/routes/api/spec/user.spec.ts @@ -19,7 +19,8 @@ const user = { username: 'testUsername', password: '87654321', isAdmin: false, - isActive: true + isActive: true, + autoExec: 'some sas code for auto exec;' } const controller = new UserController() @@ -64,6 +65,7 @@ describe('user', () => { expect(res.body.displayName).toEqual(user.displayName) expect(res.body.isAdmin).toEqual(user.isAdmin) expect(res.body.isActive).toEqual(user.isActive) + expect(res.body.autoExec).toEqual(user.autoExec) }) it('should respond with Unauthorized if access token is not present', async () => { @@ -360,7 +362,25 @@ describe('user', () => { await deleteAllUsers() }) - it('should respond with user', async () => { + it('should respond with user autoExec when same user requests', async () => { + const dbUser = await controller.createUser(user) + const userId = dbUser.id + const accessToken = await generateAndSaveToken(userId) + + const res = await request(app) + .get(`/SASjsApi/user/${userId}`) + .auth(accessToken, { type: 'bearer' }) + .send() + .expect(200) + + expect(res.body.username).toEqual(user.username) + expect(res.body.displayName).toEqual(user.displayName) + expect(res.body.isAdmin).toEqual(user.isAdmin) + expect(res.body.isActive).toEqual(user.isActive) + expect(res.body.autoExec).toEqual(user.autoExec) + }) + + it('should respond with user autoExec when admin user requests', async () => { const dbUser = await controller.createUser(user) const userId = dbUser.id @@ -374,6 +394,7 @@ describe('user', () => { expect(res.body.displayName).toEqual(user.displayName) expect(res.body.isAdmin).toEqual(user.isAdmin) expect(res.body.isActive).toEqual(user.isActive) + expect(res.body.autoExec).toEqual(user.autoExec) }) it('should respond with user when access token is not of an admin account', async () => { @@ -395,6 +416,7 @@ describe('user', () => { expect(res.body.displayName).toEqual(user.displayName) expect(res.body.isAdmin).toEqual(user.isAdmin) expect(res.body.isActive).toEqual(user.isActive) + expect(res.body.autoExec).toBeUndefined() }) it('should respond with Unauthorized if access token is not present', async () => { diff --git a/api/src/routes/api/stp.ts b/api/src/routes/api/stp.ts index 425208e..c759a9d 100644 --- a/api/src/routes/api/stp.ts +++ b/api/src/routes/api/stp.ts @@ -34,7 +34,7 @@ stpRouter.post( '/execute', fileUploadController.preUploadMiddleware, fileUploadController.getMulterUploadObject().any(), - async (req: any, res: any) => { + async (req, res: any) => { const { error: errQ, value: query } = executeProgramRawValidation(req.query) const { error: errB, value: body } = executeProgramRawValidation(req.body) diff --git a/api/src/routes/api/user.ts b/api/src/routes/api/user.ts index e4d8e9a..fcd6d5e 100644 --- a/api/src/routes/api/user.ts +++ b/api/src/routes/api/user.ts @@ -36,12 +36,12 @@ userRouter.get('/', authenticateAccessToken, async (req, res) => { } }) -userRouter.get('/:userId', authenticateAccessToken, async (req: any, res) => { +userRouter.get('/:userId', authenticateAccessToken, async (req, res) => { const { userId } = req.params const controller = new UserController() try { - const response = await controller.getUser(userId) + const response = await controller.getUser(req, parseInt(userId)) res.send(response) } catch (err: any) { res.status(403).send(err.toString()) @@ -52,17 +52,17 @@ userRouter.patch( '/:userId', authenticateAccessToken, verifyAdminIfNeeded, - async (req: any, res) => { + async (req, res) => { const { user } = req const { userId } = req.params // only an admin can update `isActive` and `isAdmin` fields - const { error, value: body } = updateUserValidation(req.body, user.isAdmin) + const { error, value: body } = updateUserValidation(req.body, user!.isAdmin) if (error) return res.status(400).send(error.details[0].message) const controller = new UserController() try { - const response = await controller.updateUser(userId, body) + const response = await controller.updateUser(parseInt(userId), body) res.send(response) } catch (err: any) { res.status(403).send(err.toString()) @@ -74,17 +74,17 @@ userRouter.delete( '/:userId', authenticateAccessToken, verifyAdminIfNeeded, - async (req: any, res) => { + async (req, res) => { const { user } = req const { userId } = req.params // only an admin can delete user without providing password - const { error, value: data } = deleteUserValidation(req.body, user.isAdmin) + const { error, value: data } = deleteUserValidation(req.body, user!.isAdmin) if (error) return res.status(400).send(error.details[0].message) const controller = new UserController() try { - await controller.deleteUser(userId, data, user.isAdmin) + await controller.deleteUser(parseInt(userId), data, user!.isAdmin) res.status(200).send('Account Deleted!') } catch (err: any) { res.status(403).send(err.toString()) diff --git a/api/src/types/RequestUser.ts b/api/src/types/RequestUser.ts new file mode 100644 index 0000000..e85507f --- /dev/null +++ b/api/src/types/RequestUser.ts @@ -0,0 +1,9 @@ +export interface RequestUser { + userId: number + clientId: string + username: string + displayName: string + isAdmin: boolean + isActive: boolean + autoExec?: string +} diff --git a/api/src/types/index.ts b/api/src/types/index.ts index 9040575..9e42479 100644 --- a/api/src/types/index.ts +++ b/api/src/types/index.ts @@ -5,3 +5,4 @@ export * from './InfoJWT' export * from './PreProgramVars' export * from './Session' export * from './TreeNode' +export * from './RequestUser' diff --git a/api/src/types/system/express-session.d.ts b/api/src/types/system/express-session.d.ts index e55a990..5b70ed6 100644 --- a/api/src/types/system/express-session.d.ts +++ b/api/src/types/system/express-session.d.ts @@ -2,13 +2,6 @@ import express from 'express' declare module 'express-session' { interface SessionData { loggedIn: boolean - user: { - userId: number - clientId: string - username: string - displayName: string - isAdmin: boolean - isActive: boolean - } + user: import('../').RequestUser } } diff --git a/api/src/types/system/express.d.ts b/api/src/types/system/express.d.ts new file mode 100644 index 0000000..7ed4e79 --- /dev/null +++ b/api/src/types/system/express.d.ts @@ -0,0 +1,7 @@ +declare namespace Express { + export interface Request { + accessToken?: string + user?: import('../').RequestUser + sasSession?: import('../').Session + } +} diff --git a/api/src/utils/getPreProgramVariables.ts b/api/src/utils/getPreProgramVariables.ts index 44516d7..34adb14 100644 --- a/api/src/utils/getPreProgramVariables.ts +++ b/api/src/utils/getPreProgramVariables.ts @@ -1,6 +1,7 @@ +import { Request } from 'express' import { PreProgramVars } from '../types' -export const getPreProgramVariables = (req: any): PreProgramVars => { +export const getPreProgramVariables = (req: Request): PreProgramVars => { const host = req.get('host') const protocol = req.protocol + '://' const { user, accessToken } = req @@ -20,9 +21,9 @@ export const getPreProgramVariables = (req: any): PreProgramVars => { if (cookies.length) httpHeaders.push(`cookie: ${cookies.join('; ')}`) return { - username: user.username, - userId: user.userId, - displayName: user.displayName, + username: user!.username, + userId: user!.userId, + displayName: user!.displayName, serverUrl: protocol + host, httpHeaders } diff --git a/api/src/utils/validation.ts b/api/src/utils/validation.ts index ba9898f..70fd850 100644 --- a/api/src/utils/validation.ts +++ b/api/src/utils/validation.ts @@ -35,7 +35,8 @@ export const registerUserValidation = (data: any): Joi.ValidationResult => username: usernameSchema.required(), password: passwordSchema.required(), isAdmin: Joi.boolean(), - isActive: Joi.boolean() + isActive: Joi.boolean(), + autoExec: Joi.string() }).validate(data) export const deleteUserValidation = ( @@ -57,7 +58,8 @@ export const updateUserValidation = ( const validationChecks: any = { displayName: Joi.string().min(6), username: usernameSchema, - password: passwordSchema + password: passwordSchema, + autoExec: Joi.string() } if (isAdmin) { validationChecks.isAdmin = Joi.boolean() diff --git a/api/src/utils/verifyTokenInDB.ts b/api/src/utils/verifyTokenInDB.ts index f8397bb..83c4a26 100644 --- a/api/src/utils/verifyTokenInDB.ts +++ b/api/src/utils/verifyTokenInDB.ts @@ -1,11 +1,30 @@ import User from '../model/User' +import { RequestUser } from '../types' + +export const fetchLatestAutoExec = async ( + reqUser: RequestUser +): Promise => { + const dbUser = await User.findOne({ id: reqUser.userId }) + + if (!dbUser) return undefined + + return { + userId: reqUser.userId, + clientId: reqUser.clientId, + username: dbUser.username, + displayName: dbUser.displayName, + isAdmin: dbUser.isAdmin, + isActive: dbUser.isActive, + autoExec: dbUser.autoExec + } +} export const verifyTokenInDB = async ( userId: number, clientId: string, token: string, tokenType: 'accessToken' | 'refreshToken' -) => { +): Promise => { const dbUser = await User.findOne({ id: userId }) if (!dbUser) return undefined @@ -21,7 +40,8 @@ export const verifyTokenInDB = async ( username: dbUser.username, displayName: dbUser.displayName, isAdmin: dbUser.isAdmin, - isActive: dbUser.isActive + isActive: dbUser.isActive, + autoExec: dbUser.autoExec } : undefined }