mirror of
https://github.com/sasjs/server.git
synced 2026-01-05 05:40:06 +00:00
chore: auth docs also added
This commit is contained in:
222
src/controllers/auth.ts
Normal file
222
src/controllers/auth.ts
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
import { Security, Route, Tags, Example, Post, Body, Query, Hidden } from 'tsoa'
|
||||||
|
import jwt from 'jsonwebtoken'
|
||||||
|
import bcrypt from 'bcryptjs'
|
||||||
|
import User from '../model/User'
|
||||||
|
import { InfoJWT } from '../types'
|
||||||
|
import { removeTokensInDB, saveTokensInDB } from '../utils'
|
||||||
|
|
||||||
|
@Route('SASjsApi/auth')
|
||||||
|
@Tags('Auth')
|
||||||
|
export default class AuthController {
|
||||||
|
static authCodes: { [key: string]: { [key: string]: string } } = {}
|
||||||
|
static saveCode = (userId: number, clientId: string, code: string) => {
|
||||||
|
if (AuthController.authCodes[userId])
|
||||||
|
return (AuthController.authCodes[userId][clientId] = code)
|
||||||
|
|
||||||
|
AuthController.authCodes[userId] = { [clientId]: code }
|
||||||
|
return AuthController.authCodes[userId][clientId]
|
||||||
|
}
|
||||||
|
static deleteCode = (userId: number, clientId: string) =>
|
||||||
|
delete AuthController.authCodes[userId][clientId]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept a valid username/password, plus a CLIENT_ID, and return an AUTH_CODE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Example<AuthorizeResponse>({
|
||||||
|
code: 'someRandomCryptoString'
|
||||||
|
})
|
||||||
|
@Post('/authorize')
|
||||||
|
public async authorize(
|
||||||
|
@Body() body: AuthorizePayload
|
||||||
|
): Promise<AuthorizeResponse> {
|
||||||
|
return authorize(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts client/auth code and returns access/refresh tokens
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Example<TokenResponse>({
|
||||||
|
accessToken: 'someRandomCryptoString',
|
||||||
|
refreshToken: 'someRandomCryptoString'
|
||||||
|
})
|
||||||
|
@Post('/token')
|
||||||
|
public async token(@Body() body: TokenPayload): Promise<TokenResponse> {
|
||||||
|
return token(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns new access/refresh tokens
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Example<TokenResponse>({
|
||||||
|
accessToken: 'someRandomCryptoString',
|
||||||
|
refreshToken: 'someRandomCryptoString'
|
||||||
|
})
|
||||||
|
@Security('bearerAuth')
|
||||||
|
@Post('/refresh')
|
||||||
|
public async refresh(
|
||||||
|
@Query() @Hidden() data?: InfoJWT
|
||||||
|
): Promise<TokenResponse> {
|
||||||
|
return refresh(data!)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logout terminate access/refresh tokens and returns nothing
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Security('bearerAuth')
|
||||||
|
@Post('/logout')
|
||||||
|
public async logout(@Query() @Hidden() data?: InfoJWT) {
|
||||||
|
return logout(data!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorize = async (data: any): Promise<AuthorizeResponse> => {
|
||||||
|
const { username, password, clientId } = data
|
||||||
|
|
||||||
|
// Authenticate User
|
||||||
|
const user = await User.findOne({ username })
|
||||||
|
if (!user) throw new Error('Username is not found.')
|
||||||
|
|
||||||
|
const validPass = await bcrypt.compare(password, user.password)
|
||||||
|
if (!validPass) throw new Error('Invalid password.')
|
||||||
|
|
||||||
|
// generate authorization code against clientId
|
||||||
|
const userInfo: InfoJWT = {
|
||||||
|
clientId,
|
||||||
|
userId: user.id
|
||||||
|
}
|
||||||
|
const code = AuthController.saveCode(
|
||||||
|
user.id,
|
||||||
|
clientId,
|
||||||
|
generateAuthCode(userInfo)
|
||||||
|
)
|
||||||
|
|
||||||
|
return { code }
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = async (data: any): Promise<TokenResponse> => {
|
||||||
|
const { clientId, code } = data
|
||||||
|
|
||||||
|
const userInfo = await verifyAuthCode(clientId, code)
|
||||||
|
if (!userInfo) throw new Error('Invalid Auth Code')
|
||||||
|
|
||||||
|
if (AuthController.authCodes[userInfo.userId][clientId] !== code)
|
||||||
|
throw new Error('Invalid Auth Code')
|
||||||
|
|
||||||
|
AuthController.deleteCode(userInfo.userId, clientId)
|
||||||
|
|
||||||
|
const accessToken = generateAccessToken(userInfo)
|
||||||
|
const refreshToken = generateRefreshToken(userInfo)
|
||||||
|
|
||||||
|
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
|
||||||
|
|
||||||
|
return { accessToken, refreshToken }
|
||||||
|
}
|
||||||
|
|
||||||
|
const refresh = async (userInfo: InfoJWT): Promise<TokenResponse> => {
|
||||||
|
const accessToken = generateAccessToken(userInfo)
|
||||||
|
const refreshToken = generateRefreshToken(userInfo)
|
||||||
|
|
||||||
|
await saveTokensInDB(
|
||||||
|
userInfo.userId,
|
||||||
|
userInfo.clientId,
|
||||||
|
accessToken,
|
||||||
|
refreshToken
|
||||||
|
)
|
||||||
|
|
||||||
|
return { accessToken, refreshToken }
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = async (userInfo: InfoJWT) => {
|
||||||
|
await removeTokensInDB(userInfo.userId, userInfo.clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthorizePayload {
|
||||||
|
/**
|
||||||
|
* Username for user
|
||||||
|
* @example "johnSnow01"
|
||||||
|
*/
|
||||||
|
username: string
|
||||||
|
/**
|
||||||
|
* Password for user
|
||||||
|
* @example "secretpassword"
|
||||||
|
*/
|
||||||
|
password: string
|
||||||
|
/**
|
||||||
|
* Client ID
|
||||||
|
* @example "someFormattedClientID1234"
|
||||||
|
*/
|
||||||
|
clientId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthorizeResponse {
|
||||||
|
/**
|
||||||
|
* Authorization code
|
||||||
|
* @example "someRandomCryptoString"
|
||||||
|
*/
|
||||||
|
code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TokenPayload {
|
||||||
|
/**
|
||||||
|
* Client ID
|
||||||
|
* @example "someFormattedClientID1234"
|
||||||
|
*/
|
||||||
|
clientId: string
|
||||||
|
/**
|
||||||
|
* Authorization code
|
||||||
|
* @example "someRandomCryptoString"
|
||||||
|
*/
|
||||||
|
code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TokenResponse {
|
||||||
|
/**
|
||||||
|
* Access Token
|
||||||
|
* @example "someRandomCryptoString"
|
||||||
|
*/
|
||||||
|
accessToken: string
|
||||||
|
/**
|
||||||
|
* Refresh Token
|
||||||
|
* @example "someRandomCryptoString"
|
||||||
|
*/
|
||||||
|
refreshToken: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateAuthCode = (data: InfoJWT) =>
|
||||||
|
jwt.sign(data, process.env.AUTH_CODE_SECRET as string, {
|
||||||
|
expiresIn: '30s'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const generateAccessToken = (data: InfoJWT) =>
|
||||||
|
jwt.sign(data, process.env.ACCESS_TOKEN_SECRET as string, {
|
||||||
|
expiresIn: '1h'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const generateRefreshToken = (data: InfoJWT) =>
|
||||||
|
jwt.sign(data, process.env.REFRESH_TOKEN_SECRET as string, {
|
||||||
|
expiresIn: '1day'
|
||||||
|
})
|
||||||
|
|
||||||
|
const verifyAuthCode = async (
|
||||||
|
clientId: string,
|
||||||
|
code: string
|
||||||
|
): Promise<InfoJWT | undefined> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
jwt.verify(code, process.env.AUTH_CODE_SECRET as string, (err, data) => {
|
||||||
|
if (err) return resolve(undefined)
|
||||||
|
|
||||||
|
const clientInfo: InfoJWT = {
|
||||||
|
clientId: data?.clientId,
|
||||||
|
userId: data?.userId
|
||||||
|
}
|
||||||
|
if (clientInfo.clientId === clientId) {
|
||||||
|
return resolve(clientInfo)
|
||||||
|
}
|
||||||
|
return resolve(undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -16,13 +16,13 @@ import bcrypt from 'bcryptjs'
|
|||||||
|
|
||||||
import User, { UserPayload } from '../model/User'
|
import User, { UserPayload } from '../model/User'
|
||||||
|
|
||||||
interface userResponse {
|
interface UserResponse {
|
||||||
id: number
|
id: number
|
||||||
username: string
|
username: string
|
||||||
displayName: string
|
displayName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface userDetailsResponse {
|
interface UserDetailsResponse {
|
||||||
id: number
|
id: number
|
||||||
displayName: string
|
displayName: string
|
||||||
username: string
|
username: string
|
||||||
@@ -38,7 +38,7 @@ export default class UserController {
|
|||||||
* Get list of all users (username, displayname). All users can request this.
|
* Get list of all users (username, displayname). All users can request this.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Example<userResponse[]>([
|
@Example<UserResponse[]>([
|
||||||
{
|
{
|
||||||
id: 123,
|
id: 123,
|
||||||
username: 'johnusername',
|
username: 'johnusername',
|
||||||
@@ -51,7 +51,7 @@ export default class UserController {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
@Get('/')
|
@Get('/')
|
||||||
public async getAllUsers(): Promise<userResponse[]> {
|
public async getAllUsers(): Promise<UserResponse[]> {
|
||||||
return getAllUsers()
|
return getAllUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ export default class UserController {
|
|||||||
* Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.
|
* Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Example<userDetailsResponse>({
|
@Example<UserDetailsResponse>({
|
||||||
id: 1234,
|
id: 1234,
|
||||||
displayName: 'John Snow',
|
displayName: 'John Snow',
|
||||||
username: 'johnSnow01',
|
username: 'johnSnow01',
|
||||||
@@ -69,7 +69,7 @@ export default class UserController {
|
|||||||
@Post('/')
|
@Post('/')
|
||||||
public async createUser(
|
public async createUser(
|
||||||
@Body() body: UserPayload
|
@Body() body: UserPayload
|
||||||
): Promise<userDetailsResponse> {
|
): Promise<UserDetailsResponse> {
|
||||||
return createUser(body)
|
return createUser(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export default class UserController {
|
|||||||
* @example userId 1234
|
* @example userId 1234
|
||||||
*/
|
*/
|
||||||
@Get('{userId}')
|
@Get('{userId}')
|
||||||
public async getUser(@Path() userId: number): Promise<userDetailsResponse> {
|
public async getUser(@Path() userId: number): Promise<UserDetailsResponse> {
|
||||||
return getUser(userId)
|
return getUser(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ export default class UserController {
|
|||||||
* @param userId The user's identifier
|
* @param userId The user's identifier
|
||||||
* @example userId "1234"
|
* @example userId "1234"
|
||||||
*/
|
*/
|
||||||
@Example<userDetailsResponse>({
|
@Example<UserDetailsResponse>({
|
||||||
id: 1234,
|
id: 1234,
|
||||||
displayName: 'John Snow',
|
displayName: 'John Snow',
|
||||||
username: 'johnSnow01',
|
username: 'johnSnow01',
|
||||||
@@ -99,7 +99,7 @@ export default class UserController {
|
|||||||
public async updateUser(
|
public async updateUser(
|
||||||
@Path() userId: number,
|
@Path() userId: number,
|
||||||
@Body() body: UserPayload
|
@Body() body: UserPayload
|
||||||
): Promise<userDetailsResponse> {
|
): Promise<UserDetailsResponse> {
|
||||||
return updateUser(userId, body)
|
return updateUser(userId, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,12 +118,12 @@ export default class UserController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllUsers = async (): Promise<userResponse[]> =>
|
const getAllUsers = async (): Promise<UserResponse[]> =>
|
||||||
await User.find({})
|
await User.find({})
|
||||||
.select({ _id: 0, id: 1, username: 1, displayName: 1 })
|
.select({ _id: 0, id: 1, username: 1, displayName: 1 })
|
||||||
.exec()
|
.exec()
|
||||||
|
|
||||||
const createUser = async (data: any): Promise<userDetailsResponse> => {
|
const createUser = async (data: any): Promise<UserDetailsResponse> => {
|
||||||
const { displayName, username, password, isAdmin, isActive } = data
|
const { displayName, username, password, isAdmin, isActive } = data
|
||||||
|
|
||||||
// Checking if user is already in the database
|
// Checking if user is already in the database
|
||||||
@@ -145,7 +145,13 @@ const createUser = async (data: any): Promise<userDetailsResponse> => {
|
|||||||
|
|
||||||
const savedUser = await user.save()
|
const savedUser = await user.save()
|
||||||
|
|
||||||
return savedUser
|
return {
|
||||||
|
id: savedUser.id,
|
||||||
|
displayName: savedUser.displayName,
|
||||||
|
username: savedUser.username,
|
||||||
|
isActive: savedUser.isActive,
|
||||||
|
isAdmin: savedUser.isAdmin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUser = async (id: number) => {
|
const getUser = async (id: number) => {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import bcrypt from 'bcryptjs'
|
|
||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
|
|
||||||
|
import AuthController from '../../controllers/auth'
|
||||||
import Client from '../../model/Client'
|
import Client from '../../model/Client'
|
||||||
import User from '../../model/User'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
authenticateAccessToken,
|
authenticateAccessToken,
|
||||||
@@ -22,7 +21,6 @@ import { InfoJWT } from '../../types'
|
|||||||
const authRouter = express.Router()
|
const authRouter = express.Router()
|
||||||
|
|
||||||
const clientIDs = new Set()
|
const clientIDs = new Set()
|
||||||
const authCodes: { [key: string]: { [key: string]: string } } = {}
|
|
||||||
|
|
||||||
export const populateClients = async () => {
|
export const populateClients = async () => {
|
||||||
const result = await Client.find()
|
const result = await Client.find()
|
||||||
@@ -46,127 +44,63 @@ export const connectDB = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const saveCode = (userId: number, clientId: string, code: string) => {
|
|
||||||
if (authCodes[userId]) return (authCodes[userId][clientId] = code)
|
|
||||||
|
|
||||||
authCodes[userId] = { [clientId]: code }
|
|
||||||
return authCodes[userId][clientId]
|
|
||||||
}
|
|
||||||
export const deleteCode = (userId: number, clientId: string) =>
|
|
||||||
delete authCodes[userId][clientId]
|
|
||||||
|
|
||||||
authRouter.post('/authorize', async (req, res) => {
|
authRouter.post('/authorize', async (req, res) => {
|
||||||
const { error, value } = authorizeValidation(req.body)
|
const { error, value: body } = authorizeValidation(req.body)
|
||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
const { username, password, clientId } = value
|
const { clientId } = body
|
||||||
|
|
||||||
// Verify client ID
|
// Verify client ID
|
||||||
if (!clientIDs.has(clientId)) {
|
if (!clientIDs.has(clientId)) {
|
||||||
return res.status(403).send('Invalid clientId.')
|
return res.status(403).send('Invalid clientId.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate User
|
const controller = new AuthController()
|
||||||
const user = await User.findOne({ username })
|
try {
|
||||||
if (!user) return res.status(403).send('Username is not found.')
|
const response = await controller.authorize(body)
|
||||||
|
|
||||||
const validPass = await bcrypt.compare(password, user.password)
|
res.send(response)
|
||||||
if (!validPass) return res.status(403).send('Invalid password.')
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
// generate authorization code against clientId
|
|
||||||
const userInfo: InfoJWT = {
|
|
||||||
clientId,
|
|
||||||
userId: user.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = saveCode(user.id, clientId, generateAuthCode(userInfo))
|
|
||||||
|
|
||||||
res.json({ code })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
authRouter.post('/token', async (req, res) => {
|
authRouter.post('/token', async (req, res) => {
|
||||||
const { error, value } = tokenValidation(req.body)
|
const { error, value: body } = tokenValidation(req.body)
|
||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
const { clientId, code } = value
|
const controller = new AuthController()
|
||||||
|
try {
|
||||||
|
const response = await controller.token(body)
|
||||||
|
|
||||||
const userInfo = await verifyAuthCode(clientId, code)
|
res.send(response)
|
||||||
if (!userInfo) return res.sendStatus(403)
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
if (authCodes[userInfo.userId][clientId] !== code) return res.sendStatus(403)
|
}
|
||||||
|
|
||||||
deleteCode(userInfo.userId, clientId)
|
|
||||||
|
|
||||||
const accessToken = generateAccessToken(userInfo)
|
|
||||||
const refreshToken = jwt.sign(
|
|
||||||
userInfo,
|
|
||||||
process.env.REFRESH_TOKEN_SECRET as string
|
|
||||||
)
|
|
||||||
|
|
||||||
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
|
|
||||||
|
|
||||||
res.json({ accessToken: accessToken, refreshToken: refreshToken })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
authRouter.post('/refresh', authenticateRefreshToken, async (req: any, res) => {
|
authRouter.post('/refresh', authenticateRefreshToken, async (req: any, res) => {
|
||||||
const { userId, clientId } = req.user
|
const userInfo: InfoJWT = req.user
|
||||||
const userInfo = {
|
|
||||||
userId,
|
const controller = new AuthController()
|
||||||
clientId
|
try {
|
||||||
|
const response = await controller.refresh(userInfo)
|
||||||
|
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
const accessToken = generateAccessToken(userInfo)
|
|
||||||
const refreshToken = jwt.sign(
|
|
||||||
userInfo,
|
|
||||||
process.env.REFRESH_TOKEN_SECRET as string
|
|
||||||
)
|
|
||||||
|
|
||||||
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
|
|
||||||
|
|
||||||
res.json({ accessToken: accessToken, refreshToken: refreshToken })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
authRouter.delete('/logout', authenticateAccessToken, async (req: any, res) => {
|
authRouter.delete('/logout', authenticateAccessToken, async (req: any, res) => {
|
||||||
const { user } = req
|
const userInfo: InfoJWT = req.user
|
||||||
|
|
||||||
await removeTokensInDB(user.username, user.clientId)
|
const controller = new AuthController()
|
||||||
|
try {
|
||||||
|
await controller.logout(userInfo)
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
res.sendStatus(204)
|
res.sendStatus(204)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const generateAccessToken = (data: InfoJWT) =>
|
|
||||||
jwt.sign(data, process.env.ACCESS_TOKEN_SECRET as string, {
|
|
||||||
expiresIn: '1h'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const generateRefreshToken = (data: InfoJWT) =>
|
|
||||||
jwt.sign(data, process.env.REFRESH_TOKEN_SECRET as string, {
|
|
||||||
expiresIn: '1day'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const generateAuthCode = (data: InfoJWT) =>
|
|
||||||
jwt.sign(data, process.env.AUTH_CODE_SECRET as string, {
|
|
||||||
expiresIn: '30s'
|
|
||||||
})
|
|
||||||
|
|
||||||
const verifyAuthCode = async (
|
|
||||||
clientId: string,
|
|
||||||
code: string
|
|
||||||
): Promise<InfoJWT | undefined> => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
jwt.verify(code, process.env.AUTH_CODE_SECRET as string, (err, data) => {
|
|
||||||
if (err) return resolve(undefined)
|
|
||||||
|
|
||||||
const clientInfo: InfoJWT = {
|
|
||||||
clientId: data?.clientId,
|
|
||||||
userId: data?.userId
|
|
||||||
}
|
|
||||||
if (clientInfo.clientId === clientId) {
|
|
||||||
return resolve(clientInfo)
|
|
||||||
}
|
|
||||||
return resolve(undefined)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default authRouter
|
export default authRouter
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ import request from 'supertest'
|
|||||||
import app from '../../../app'
|
import app from '../../../app'
|
||||||
import UserController from '../../../controllers/user'
|
import UserController from '../../../controllers/user'
|
||||||
import ClientController from '../../../controllers/client'
|
import ClientController from '../../../controllers/client'
|
||||||
import {
|
import AuthController, {
|
||||||
generateAccessToken,
|
generateAccessToken,
|
||||||
generateAuthCode,
|
generateAuthCode,
|
||||||
generateRefreshToken,
|
generateRefreshToken
|
||||||
populateClients,
|
} from '../../../controllers/auth'
|
||||||
saveCode
|
import { populateClients } from '../auth'
|
||||||
} from '../auth'
|
|
||||||
import { InfoJWT } from '../../../types'
|
import { InfoJWT } from '../../../types'
|
||||||
import { saveTokensInDB, verifyTokenInDB } from '../../../utils'
|
import { saveTokensInDB, verifyTokenInDB } from '../../../utils'
|
||||||
|
|
||||||
@@ -115,7 +114,7 @@ describe('auth', () => {
|
|||||||
})
|
})
|
||||||
.expect(403)
|
.expect(403)
|
||||||
|
|
||||||
expect(res.text).toEqual('Username is not found.')
|
expect(res.text).toEqual('Error: Username is not found.')
|
||||||
expect(res.body).toEqual({})
|
expect(res.body).toEqual({})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -131,7 +130,7 @@ describe('auth', () => {
|
|||||||
})
|
})
|
||||||
.expect(403)
|
.expect(403)
|
||||||
|
|
||||||
expect(res.text).toEqual('Invalid password.')
|
expect(res.text).toEqual('Error: Invalid password.')
|
||||||
expect(res.body).toEqual({})
|
expect(res.body).toEqual({})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -167,7 +166,7 @@ describe('auth', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with access and refresh tokens', async () => {
|
it('should respond with access and refresh tokens', async () => {
|
||||||
const code = saveCode(
|
const code = AuthController.saveCode(
|
||||||
userInfo.userId,
|
userInfo.userId,
|
||||||
userInfo.clientId,
|
userInfo.clientId,
|
||||||
generateAuthCode(userInfo)
|
generateAuthCode(userInfo)
|
||||||
@@ -198,7 +197,7 @@ describe('auth', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with Bad Request if clientId is missing', async () => {
|
it('should respond with Bad Request if clientId is missing', async () => {
|
||||||
const code = saveCode(
|
const code = AuthController.saveCode(
|
||||||
userInfo.userId,
|
userInfo.userId,
|
||||||
userInfo.clientId,
|
userInfo.clientId,
|
||||||
generateAuthCode(userInfo)
|
generateAuthCode(userInfo)
|
||||||
@@ -228,7 +227,7 @@ describe('auth', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with Forbidden if clientId is invalid', async () => {
|
it('should respond with Forbidden if clientId is invalid', async () => {
|
||||||
const code = saveCode(
|
const code = AuthController.saveCode(
|
||||||
userInfo.userId,
|
userInfo.userId,
|
||||||
userInfo.clientId,
|
userInfo.clientId,
|
||||||
generateAuthCode(userInfo)
|
generateAuthCode(userInfo)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import request from 'supertest'
|
|||||||
import app from '../../../app'
|
import app from '../../../app'
|
||||||
import UserController from '../../../controllers/user'
|
import UserController from '../../../controllers/user'
|
||||||
import ClientController from '../../../controllers/client'
|
import ClientController from '../../../controllers/client'
|
||||||
import { generateAccessToken } from '../auth'
|
import { generateAccessToken } from '../../../controllers/auth'
|
||||||
import { saveTokensInDB } from '../../../utils'
|
import { saveTokensInDB } from '../../../utils'
|
||||||
|
|
||||||
const client = {
|
const client = {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import UserController from '../../../controllers/user'
|
|||||||
import { getTmpFilesFolderPath } from '../../../utils/file'
|
import { getTmpFilesFolderPath } from '../../../utils/file'
|
||||||
import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils'
|
import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { generateAccessToken } from '../auth'
|
import { generateAccessToken } from '../../../controllers/auth'
|
||||||
import { saveTokensInDB } from '../../../utils'
|
import { saveTokensInDB } from '../../../utils'
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { MongoMemoryServer } from 'mongodb-memory-server'
|
|||||||
import request from 'supertest'
|
import request from 'supertest'
|
||||||
import app from '../../../app'
|
import app from '../../../app'
|
||||||
import UserController from '../../../controllers/user'
|
import UserController from '../../../controllers/user'
|
||||||
import { generateAccessToken } from '../auth'
|
import { generateAccessToken } from '../../../controllers/auth'
|
||||||
import { saveTokensInDB } from '../../../utils'
|
import { saveTokensInDB } from '../../../utils'
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import User from '../model/User'
|
import User from '../model/User'
|
||||||
|
|
||||||
export const removeTokensInDB = async (username: string, clientId: string) => {
|
export const removeTokensInDB = async (userId: number, clientId: string) => {
|
||||||
const user = await User.findOne({ username })
|
const user = await User.findOne({ id: userId })
|
||||||
if (!user) return
|
if (!user) return
|
||||||
|
|
||||||
const tokenObjIndex = user.tokens.findIndex(
|
const tokenObjIndex = user.tokens.findIndex(
|
||||||
|
|||||||
Reference in New Issue
Block a user