From 0e78a07bbaf0e5bde939663333732d752637c071 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Tue, 15 Feb 2022 07:06:24 +0000 Subject: [PATCH 01/95] chore: migrated to throw `MeilingError` instead of calling `sendMeilingError` --- .swcrc | 2 +- package.json | 5 +- src/common/meiling/authentication/validate.ts | 2 +- src/common/meiling/v1/error/error.ts | 73 ++++++++++++++++--- src/common/meiling/v1/error/interface.ts | 10 ++- src/routes/v1/admin/apps/get.ts | 2 +- src/routes/v1/admin/apps/index.ts | 2 +- src/routes/v1/admin/apps/put.ts | 4 +- src/routes/v1/admin/index.ts | 44 ++++++++--- src/routes/v1/admin/internal/index.ts | 2 +- src/routes/v1/admin/sessions/crud.ts | 9 +-- src/routes/v1/admin/sessions/index.ts | 8 +- src/routes/v1/admin/tokens/index.ts | 12 +-- src/routes/v1/admin/users/authentications.ts | 14 ++-- src/routes/v1/admin/users/emails.ts | 21 +++--- src/routes/v1/admin/users/index.ts | 20 ++--- src/routes/v1/admin/users/phones.ts | 23 +++--- src/routes/v1/admin/users/sessions.ts | 5 +- src/routes/v1/meiling/apps/get.ts | 8 +- src/routes/v1/meiling/apps/list.ts | 2 +- src/routes/v1/meiling/authentication/issue.ts | 18 ++--- .../v1/meiling/authentication/verify.ts | 18 ++--- src/routes/v1/meiling/index.ts | 29 +++++++- src/routes/v1/meiling/lost-password.ts | 43 ++++------- src/routes/v1/meiling/signin.ts | 57 ++++++--------- src/routes/v1/meiling/signout.ts | 6 +- src/routes/v1/meiling/signup/index.ts | 2 +- src/routes/v1/meiling/signup/signup.ts | 33 ++++----- .../apps/actions/client_secret/delete.ts | 2 +- .../apps/actions/client_secret/post.ts | 2 +- .../users/actions/apps/actions/index.ts | 12 ++- .../apps/actions/permissions/delete.ts | 5 +- .../actions/apps/actions/permissions/post.ts | 5 +- .../apps/actions/redirect_uri/index.ts | 26 +++---- .../v1/meiling/users/actions/apps/delete.ts | 3 +- .../v1/meiling/users/actions/apps/get.ts | 2 +- .../v1/meiling/users/actions/apps/index.ts | 6 +- .../v1/meiling/users/actions/apps/post.ts | 13 ++-- .../v1/meiling/users/actions/auth/auth.ts | 44 ++++------- .../v1/meiling/users/actions/auth/check.ts | 49 +++++-------- .../meiling/users/actions/auth/device/auth.ts | 22 ++---- .../users/actions/auth/device/check.ts | 13 ++-- src/routes/v1/meiling/users/actions/index.ts | 7 +- .../v1/meiling/users/actions/info/get.ts | 8 +- .../v1/meiling/users/actions/info/list.ts | 4 +- .../v1/meiling/users/actions/info/put.ts | 14 ++-- .../actions/security/2fa/enable/index.ts | 9 +-- .../meiling/users/actions/security/2fa/get.ts | 2 +- .../actions/security/passwords/delete.ts | 2 +- .../users/actions/security/passwords/post.ts | 4 +- .../users/actions/security/passwords/put.ts | 7 +- .../actions/security/pgp/actions/delete.ts | 6 +- .../users/actions/security/pgp/actions/get.ts | 6 +- .../users/actions/security/pgp/actions/put.ts | 8 +- .../meiling/users/actions/security/pgp/get.ts | 2 +- .../users/actions/security/pgp/post.ts | 6 +- .../security/webauthn/actions/delete.ts | 6 +- .../actions/security/webauthn/actions/get.ts | 6 +- .../actions/security/webauthn/actions/put.ts | 8 +- .../users/actions/security/webauthn/index.ts | 4 +- tsconfig.json | 5 +- 61 files changed, 402 insertions(+), 390 deletions(-) diff --git a/.swcrc b/.swcrc index a7d87f33..ff29857d 100644 --- a/.swcrc +++ b/.swcrc @@ -14,7 +14,7 @@ "loose": true }, "module": { - "type": "commonjs", + "type": "es6", "strict": false, "strictMode": true, "lazy": true, diff --git a/package.json b/package.json index d536743d..7bd6f998 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.8.4", "description": "An Opensource Next Generation \"Gatekeeper\" with oAuth2 Authentication Provider and OpenID Connect Server", "main": "dist/", - "repository": "https://github.com/meili-ng/meiliNG", + "repository": "https://github.com/meili-NG/meiliNG", "author": "Alex4386 ", "license": "MIT", "dependencies": { @@ -57,7 +57,8 @@ "build": "swc src --out-dir dist/ --sync", "build:types": "tsc", "build:docker": "docker build .", - "start:dev": "nodemon", + "dev": "nodemon", + "start:dev": "swc src --out-dir dist/ --sync && node ./dist/", "start:prod": "swc src --out-dir dist/ --sync && NODE_ENV=production node ./dist/", "start": "NODE_ENV=production node ./dist/", "lint": "eslint '*/**/*.{js,ts,tsx}' --quiet --fix", diff --git a/src/common/meiling/authentication/validate.ts b/src/common/meiling/authentication/validate.ts index 5777d067..5399d2c4 100644 --- a/src/common/meiling/authentication/validate.ts +++ b/src/common/meiling/authentication/validate.ts @@ -16,7 +16,7 @@ export async function validatePGPSign( try { message = await OpenPGP.message.readArmored(challengeResponse); } catch (e) { - throw new Error(''); + throw new Error('Unable to parse PGP Signature'); } } diff --git a/src/common/meiling/v1/error/error.ts b/src/common/meiling/v1/error/error.ts index 5258e1e9..5cbc2f59 100644 --- a/src/common/meiling/v1/error/error.ts +++ b/src/common/meiling/v1/error/error.ts @@ -4,7 +4,7 @@ import { NodeEnvironment } from '../../../../interface'; import config from '../../../../resources/config'; import { ErrorResponse } from './interface'; import { ErrorType } from './type'; -import { Error } from '../..'; +import { Error as CommonError } from '../..'; function getMeilingErrorStatusCode(type: ErrorType) { switch (type) { @@ -80,16 +80,67 @@ function getMeilingErrorStatusCode(type: ErrorType) { ((n: never) => { })(type); } -export function sendMeilingError(rep: FastifyReply, type: ErrorType, description?: string, code?: string): void { - if (config.node.environment === NodeEnvironment.Development) - console.error(chalk.red('[ERROR]'), 'Error Report', type); +// TODO: implement throws +export class MeilingError extends Error { + public _isMeiling: true = true; + + public type: ErrorType; + public description?: string; + public details?: any; + public debug?: any; + + constructor(type: ErrorType, description?: string, details?: any, debug?: any) { + super(description); + this.type = type; + this.name = 'meiliNG Error'; + this.message = description ? description : type; + this.description = description; + this.details = details; + this.debug = debug; + } + + public toString() { + return this.description; + } + + public static load(error: MeilingError) { + const mlError = new MeilingError(error.type, error.description, error.details, error.debug); + console.log(mlError); + + return mlError; + } - const statusCode = getMeilingErrorStatusCode(type); + public loadError(error: Error) { + this.name = error.name; + this.message = error.message; + this.description = error.message; + this.stack = error.stack; + } + + public serialize(): ErrorResponse { + let base: ErrorResponse = { + type: this.type, + description: this.description, + details: this.details, + }; + + if (config.node.environment === NodeEnvironment.Development) { + base = { + ...base, + debug: this.debug, + stack: this.stack, + }; + } + + return base; + } - rep.status(statusCode).send({ - type, - description, - code, - url: Error.buildErrorCodeURL(code), - } as ErrorResponse); + public getStatusCode() { + const type = this.type; + return getMeilingErrorStatusCode(type); + } + + public sendFastify(rep: FastifyReply) { + rep.status(this.getStatusCode()).send(this.serialize()); + } } diff --git a/src/common/meiling/v1/error/interface.ts b/src/common/meiling/v1/error/interface.ts index 1fd062d2..59ec1603 100644 --- a/src/common/meiling/v1/error/interface.ts +++ b/src/common/meiling/v1/error/interface.ts @@ -2,7 +2,11 @@ import { ErrorType } from './type'; export interface ErrorResponse { type: ErrorType; - description: string; - code: string; - url: string; + description?: string; + details?: any; + debug?: any; + stack?: string; + + code?: string; + url?: string; } diff --git a/src/routes/v1/admin/apps/get.ts b/src/routes/v1/admin/apps/get.ts index f8a0780c..3a9df637 100644 --- a/src/routes/v1/admin/apps/get.ts +++ b/src/routes/v1/admin/apps/get.ts @@ -10,7 +10,7 @@ async function appAdminInfoHandler(req: FastifyRequest, rep: FastifyReply) { rep.send(client); return; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } } diff --git a/src/routes/v1/admin/apps/index.ts b/src/routes/v1/admin/apps/index.ts index 3a32a2e4..2dd9b2a2 100644 --- a/src/routes/v1/admin/apps/index.ts +++ b/src/routes/v1/admin/apps/index.ts @@ -32,7 +32,7 @@ const appsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done prismaQuery = JSON.parse(query); } catch (e) { if (rawQuery) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); return; } else if (typeof query === 'string') { prismaQuery = queryBuilder(query); diff --git a/src/routes/v1/admin/apps/put.ts b/src/routes/v1/admin/apps/put.ts index ec30b5ae..a492926d 100644 --- a/src/routes/v1/admin/apps/put.ts +++ b/src/routes/v1/admin/apps/put.ts @@ -7,7 +7,7 @@ async function appAdminPutHandler(req: FastifyRequest, rep: FastifyReply) { if (clientId) { const client = await Meiling.OAuth2.Client.getByClientId(clientId); - if (!client) return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + if (!client) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); // TODO: Implement updates later. const data = req.body as any; @@ -26,7 +26,7 @@ async function appAdminPutHandler(req: FastifyRequest, rep: FastifyReply) { rep.send({ success: true }); return; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } } diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index 24b8a183..11f056c8 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -11,6 +11,33 @@ import tokensAdminHandler from './tokens'; import usersAdminHandler from './users'; const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { + app.setErrorHandler(async (_err, req, rep) => { + const err = _err as Error; + if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { + const mlError = err as Meiling.V1.Error.MeilingError; + + return mlError.sendFastify(rep); + } else { + // This is internal server error. + if (_err.validation) { + // if it is validation issue, the error type is INVALID_REQUEST + const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + error.loadError(_err); + + return error.sendFastify(rep); + } else { + const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); + error.loadError(_err); + + return error.sendFastify(rep); + } + } + }); + + app.setNotFoundHandler((req, rep) => { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + }); + app.register(fastifyCors, { origin: config.node.environment === NodeEnvironment.Development @@ -22,8 +49,10 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( app.addHook('onRequest', (req, rep, next) => { if (!config.admin || !config.admin.tokens) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.FORBIDDEN); - throw new Error('User is not providing proper login credentials for admin'); + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.FORBIDDEN, + 'User is not providing proper login credentials for admin', + ); } const token = Meiling.Authentication.Token.getTokenFromRequest(req); @@ -41,8 +70,7 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( // ID and Password flow const isValidBasic = Utils.checkBase64(token.token); if (!isValidBasic) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_TOKEN); - throw new Error('Invalid Admin Token'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_TOKEN, 'Invalid Admin Token'); } const tokenString = Buffer.from(token.token, 'base64').toString('utf-8'); @@ -52,17 +80,15 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( const matchedTokens = basicTokens.filter((n) => n === tokenString); if (matchedTokens.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_TOKEN); - throw new Error('Invalid Admin Token'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_TOKEN, 'Invalid Admin Token'); } } else if (token.method.toLowerCase() === 'bearer') { const matchedTokens = config.admin.tokens.filter((n) => n === token.token); if (matchedTokens.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_TOKEN); - throw new Error('Invalid Admin Token'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_TOKEN, 'Invalid Admin Token'); } } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); } next(); diff --git a/src/routes/v1/admin/internal/index.ts b/src/routes/v1/admin/internal/index.ts index 6a370a36..f45ab711 100644 --- a/src/routes/v1/admin/internal/index.ts +++ b/src/routes/v1/admin/internal/index.ts @@ -17,7 +17,7 @@ const internalAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, rep.send({ success: true }); } catch (e) { console.error(e); - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); } }); diff --git a/src/routes/v1/admin/sessions/crud.ts b/src/routes/v1/admin/sessions/crud.ts index a34ac672..3a617a65 100644 --- a/src/routes/v1/admin/sessions/crud.ts +++ b/src/routes/v1/admin/sessions/crud.ts @@ -6,8 +6,7 @@ const sessionAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, d app.addHook('onRequest', async (req, rep) => { const token = (req.query as { token: string }).token; if (!token || token.trim() === '') { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); - throw new Error('invalid query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid query'); } const tokenData = await getPrismaClient().meilingSessionV1Token.findFirst({ @@ -17,8 +16,7 @@ const sessionAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, d }); if (!tokenData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('session not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); } }); @@ -33,8 +31,7 @@ const sessionAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, d }); if (!tokenDataOld) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('session not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); } if (body?.ip) { diff --git a/src/routes/v1/admin/sessions/index.ts b/src/routes/v1/admin/sessions/index.ts index 738ffd92..eb47c42e 100644 --- a/src/routes/v1/admin/sessions/index.ts +++ b/src/routes/v1/admin/sessions/index.ts @@ -16,7 +16,7 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }, }); - if (!tokenData) return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + if (!tokenData) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); rep.send(tokenData); return; } @@ -40,11 +40,7 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, try { prismaQuery = JSON.parse(query); } catch (e) { - return Meiling.V1.Error.sendMeilingError( - rep, - Meiling.V1.Error.ErrorType.INVALID_REQUEST, - 'invalid prisma query', - ); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); } } diff --git a/src/routes/v1/admin/tokens/index.ts b/src/routes/v1/admin/tokens/index.ts index a15ee443..a293e392 100644 --- a/src/routes/v1/admin/tokens/index.ts +++ b/src/routes/v1/admin/tokens/index.ts @@ -6,8 +6,7 @@ const tokensAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, do app.addHook('onRequest', async (req, rep) => { const token = (req.query as { token: string }).token; if (!token || token.trim() === '') { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); - throw new Error('invalid query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid query'); } const tokenData = await getPrismaClient().oAuthToken.findFirst({ @@ -17,8 +16,7 @@ const tokensAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, do }); if (!tokenData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('session not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); } }); @@ -32,8 +30,7 @@ const tokensAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, do }); if (!tokenData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('session not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); } const data = await Meiling.Authentication.Token.serialize(tokenData.token, tokenData.type); @@ -62,8 +59,7 @@ const tokensAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, do }); if (!tokenDataOld) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('session not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); } const tokenData = await getPrismaClient().meilingSessionV1Token.findFirst({ diff --git a/src/routes/v1/admin/users/authentications.ts b/src/routes/v1/admin/users/authentications.ts index 63bb3c8f..270d563a 100644 --- a/src/routes/v1/admin/users/authentications.ts +++ b/src/routes/v1/admin/users/authentications.ts @@ -41,12 +41,12 @@ const userAuthnsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions const uuid = (req.params as { uuid: string }).uuid; const user = await Meiling.Identity.User.getInfo(uuid); - if (!user) return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND, 'missing user'); + if (!user) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'missing user'); const data = req.body as AuthenticationBody; if (!validateBody(data)) - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body'); const method = data.method; const authn = await getPrismaClient().authentication.create({ @@ -88,7 +88,7 @@ const userAuthnAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (authn === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -109,14 +109,14 @@ const userAuthnAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }, }); - if (authn === null) return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - if (!user) return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND, 'missing user'); + if (authn === null) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + if (!user) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'missing user'); const data = req.body as AuthenticationBody; const method = authn.method; if (!validateBody(data, method)) - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body'); await getPrismaClient().authentication.update({ where: { @@ -149,7 +149,7 @@ const userAuthnAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (authn === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/admin/users/emails.ts b/src/routes/v1/admin/users/emails.ts index 3bdfe11e..67c48125 100644 --- a/src/routes/v1/admin/users/emails.ts +++ b/src/routes/v1/admin/users/emails.ts @@ -29,7 +29,7 @@ const userEmailsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions const body = req.body as UserEmailRegisterInterface | undefined; if (!body?.email || typeof body.email !== 'string') { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -52,7 +52,7 @@ const userEmailsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions ).filter((n) => n.email === email); if (matchingEmails.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.CONFLICT, 'email already exists'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.CONFLICT, 'email already exists'); return; } @@ -68,8 +68,7 @@ const userEmailsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions const othersPrimaryEmails = primaryEmails.filter((n) => n.userId !== uuid && n.isPrimary && n.email === email); if (othersPrimaryEmails.length > 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'there is other user who is using this email as primary email', ); @@ -124,7 +123,7 @@ const userEmailAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (email === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -150,12 +149,12 @@ const userEmailAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (email === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } if (!body.email) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -173,8 +172,7 @@ const userEmailAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, ); if (othersPrimaryEmails.length > 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'there is other user who is using this email as primary email', ); @@ -217,13 +215,12 @@ const userEmailAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (email === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } if (email.isPrimary) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'you should assign new primary email before deleting it', ); diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index e5fc8b44..c77bfd90 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -76,7 +76,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don prismaQuery = JSON.parse(query); } catch (e) { if (rawQuery) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); return; } else if (typeof query === 'string') { prismaQuery = queryBuilder(query); @@ -105,15 +105,14 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don // TODO: add endpoints to allow CRUD operations on user's authentication method by admin const data = req.body as any; - if (!data) - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Body'); + if (!data) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Body'); const hasRequirementsMet = Utils.isNotBlank(data.username); if (!hasRequirementsMet) - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Username'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Username'); if (!Utils.isValidName(data.name)) - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Name'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Name'); const name = data.name; @@ -140,7 +139,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don prismaQuery = JSON.parse(query); } catch (e) { if (rawQuery) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); return; } else if (typeof query === 'string') { prismaQuery = queryBuilder(query); @@ -168,8 +167,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done const user = await Meiling.Identity.User.getDetailedInfo(uuid); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('user not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } }); @@ -178,8 +176,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done const user = await Meiling.Identity.User.getDetailedInfo(uuid); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('user not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } rep.send(user); @@ -193,8 +190,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done const user = await Meiling.Identity.User.getInfo(uuid); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('user not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } await getPrismaClient().user.update({ diff --git a/src/routes/v1/admin/users/phones.ts b/src/routes/v1/admin/users/phones.ts index e0aae235..52a745be 100644 --- a/src/routes/v1/admin/users/phones.ts +++ b/src/routes/v1/admin/users/phones.ts @@ -30,7 +30,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions const body = req.body as UserPhoneRegisterInterface | undefined; if (!body?.phone || typeof body.phone !== 'string') { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -41,7 +41,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions const phone = libPhoneNumberJs(body.phone); if (!phone) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid phone number'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid phone number'); return; } @@ -54,7 +54,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions ).filter((n) => n.phone === phone.formatInternational()); if (matchingPhones.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.CONFLICT, 'phone number already exists'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.CONFLICT, 'phone number already exists'); return; } @@ -72,8 +72,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions ); if (othersPrimaryPhones.length > 0 && body.force !== true) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'there is other user who is using this phone as primary phone', ); @@ -127,7 +126,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (phone === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -152,7 +151,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (phone === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -161,7 +160,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, if (typeof body.phone === 'string') { const phoneNumberObj = libPhoneNumberJs(body.phone); if (!phoneNumberObj) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid phone number'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid phone number'); return; } @@ -182,8 +181,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, ); if (othersPrimaryPhones.length > 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'there is other user who is using this phone as primary phone', ); @@ -225,13 +223,12 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); if (phone === null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } if (phone.isPrimary) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.CONFLICT, 'you should assign new primary number before deleting it', ); diff --git a/src/routes/v1/admin/users/sessions.ts b/src/routes/v1/admin/users/sessions.ts index e5055e1b..77d1d642 100644 --- a/src/routes/v1/admin/users/sessions.ts +++ b/src/routes/v1/admin/users/sessions.ts @@ -8,8 +8,7 @@ const userSessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptio const user = await Meiling.Identity.User.getDetailedInfo(uuid); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); - throw new Error('user not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } const { query, pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; @@ -31,7 +30,7 @@ const userSessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptio try { prismaQuery = JSON.parse(query); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); return; } } diff --git a/src/routes/v1/meiling/apps/get.ts b/src/routes/v1/meiling/apps/get.ts index 6d5a45fc..a2135cad 100644 --- a/src/routes/v1/meiling/apps/get.ts +++ b/src/routes/v1/meiling/apps/get.ts @@ -10,7 +10,7 @@ async function appInfoHandler(req: FastifyRequest, rep: FastifyReply) { const client = await Meiling.OAuth2.Client.getByClientId(clientId); const acl = await Meiling.OAuth2.Client.getAccessControl(clientId); if (!client || !acl) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND); return; } @@ -19,7 +19,7 @@ async function appInfoHandler(req: FastifyRequest, rep: FastifyReply) { // If no user access controls, returning client info. if (!acl.userAclId) rep.send(Meiling.OAuth2.Client.sanitize(client)); // If not, returning unauthorized error. - else Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + else throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } @@ -29,14 +29,14 @@ async function appInfoHandler(req: FastifyRequest, rep: FastifyReply) { } if (!shouldShow) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } rep.send(Meiling.OAuth2.Client.sanitize(client)); return; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } } diff --git a/src/routes/v1/meiling/apps/list.ts b/src/routes/v1/meiling/apps/list.ts index 15786f99..0e04c8d0 100644 --- a/src/routes/v1/meiling/apps/list.ts +++ b/src/routes/v1/meiling/apps/list.ts @@ -7,7 +7,7 @@ async function appListHandler(req: FastifyRequest, rep: FastifyReply): Promise void): void { + app.setErrorHandler(async (_err, req, rep) => { + const err = _err as Error; + if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { + const mlError = err as Meiling.V1.Error.MeilingError; + + return mlError.sendFastify(rep); + } else { + // This is internal server error. + if (_err.validation) { + // if it is validation issue, the error type is INVALID_REQUEST + const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + error.loadError(_err); + + return error.sendFastify(rep); + } else { + const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); + error.loadError(_err); + + return error.sendFastify(rep); + } + } + }); + + app.setNotFoundHandler((req, rep) => { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + }); + app.register(fastifyCors, { origin: config.node.environment === NodeEnvironment.Development ? '*' : config.frontend.url, }); @@ -38,7 +65,7 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, app.addHook('onRequest', async (req, rep) => { const session = await Meiling.V1.Session.getSessionFromRequest(req); if (!session) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_SESSION); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_SESSION); throw new Error(); } diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 0351648d..2fcc1dae 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -14,14 +14,13 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply try { body = Utils.convertJsonIfNot(req.body); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is not a valid JSON.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is not a valid JSON.'); return; } if (body.password) { if (!session.passwordReset?.isVerified || !session.passwordReset.passwordResetUser) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED, 'password reset request not completed yet', ); @@ -47,8 +46,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply } if (!body.context?.username) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body does not contain context: username', ); @@ -58,7 +56,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply const username = body?.context?.username; if (!username) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'username is missing'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'username is missing'); return; } @@ -69,14 +67,13 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply } if (users.length > 1) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.MORE_THAN_ONE_USER_MATCHED, 'more than one user has matched', ); return; } else if (users.length < 1) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'no user was found!'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'no user was found!'); return; } @@ -107,14 +104,14 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply const challenge = Meiling.V1.Challenge.generateChallenge(currentMethod); if (!challenge) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNSUPPORTED_SIGNIN_METHOD); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNSUPPORTED_SIGNIN_METHOD); return; } if ( methods.map((n) => n.method.toLowerCase() as string).filter((n) => n === currentMethod.toLowerCase()).length === 0 ) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNSUPPORTED_SIGNIN_METHOD); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNSUPPORTED_SIGNIN_METHOD); return; } @@ -124,8 +121,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply const to = (await Meiling.Identity.User.getPrimaryEmail(user.id))?.email; if (!to || !Utils.isValidEmail(to)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID, 'email does not exist on this user', ); @@ -142,8 +138,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply } if (!to) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID, 'phone number does not exist on this user', ); @@ -156,8 +151,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply if (to !== undefined) { if (Meiling.V1.Challenge.isChallengeRateLimited(body.method, session.passwordReset?.challengeCreatedAt)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_RATE_LIMITED, 'You are rate limited', ); @@ -167,8 +161,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply const notificationMethod = Meiling.V1.Notification.convertToNotificationMethod(currentMethod); if (!notificationMethod) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID, 'invalid authorization method', ); @@ -220,8 +213,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply session.passwordReset?.challengeCreatedAt, ) ) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, 'generation request was not generated in first place.', ); @@ -234,8 +226,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply passwordReset.method.toLowerCase() !== body.method.toLowerCase() || !passwordReset.passwordResetUser ) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, 'generation request was not generated with particular method', ); @@ -247,8 +238,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply new Date().getTime() - new Date(passwordReset.challengeCreatedAt).getTime() > 1000 * config.token.invalidate.meiling.CHALLENGE_TOKEN ) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_TIMEOUT, 'generated request was timed out', ); @@ -261,8 +251,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply body.data.challengeResponse, ); if (!isValid) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID, 'invalid challenge', ); diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index bf2115ad..8948168b 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -13,7 +13,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro try { body = Utils.convertJsonIfNot(req.body); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is not a valid JSON.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is not a valid JSON.'); return; } @@ -22,7 +22,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const username = body?.data?.username; if (username === undefined) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is missing username.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is missing username.'); return; } @@ -50,7 +50,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro return; } - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_USERNAME); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_USERNAME); return; } else if (body.type === Meiling.V1.Interfaces.SigninType.USERNAME_AND_PASSWORD) { @@ -58,8 +58,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const password = body?.data?.password; if (username === undefined || password === undefined) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is missing username and password.', ); @@ -71,8 +70,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro if (authenticatedUsers.length === 1) { userToLogin = authenticatedUsers[0]; } else if (authenticatedUsers.length > 1) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.MORE_THAN_ONE_USER_MATCHED, 'more than one user was matched, use username instead.', ); @@ -81,9 +79,9 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const users = await Meiling.Identity.User.findByCommonUsername(username); if (users.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_PASSWORD, 'Wrong password.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_PASSWORD, 'Wrong password.'); } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'Wrong username.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'Wrong username.'); } return; } @@ -100,8 +98,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro type: Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH, }); - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUIRED, 'two factor authentication is required.', ); @@ -117,8 +114,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro if (body.type === Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH) { if (session.extendedAuthentication?.type !== Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUEST_NOT_GENERATED, 'two factor authentication request is not generated yet or overrided by passwordless login. please check your login request.', ); @@ -128,8 +124,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const userId = session.extendedAuthentication.id; if (userId === undefined) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUEST_NOT_GENERATED, 'two factor authentication request session does not contain user session. please redo your login.', ); @@ -139,8 +134,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const user = await Meiling.Identity.User.getBasicInfo(userId); if (user === null) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUEST_NOT_GENERATED, 'two factor authentication request session does not valid userId session. please redo your login.', ); @@ -157,7 +151,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const users = await Meiling.Identity.User.findByCommonUsername(username); if (users.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'Wrong username.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'Wrong username.'); return; } @@ -188,8 +182,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro // check signinMethod is valid if (Meiling.V1.Database.convertAuthentication(signinMethod) === undefined) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_SIGNIN_METHOD, 'invalid signin method: ' + signinMethod, ); @@ -197,8 +190,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro } if (!availableMethods.includes(signinMethod)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_SIGNIN_METHOD, 'unsupported signin method: ' + signinMethod, ); @@ -213,8 +205,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro if ( Meiling.V1.Challenge.isChallengeRateLimited(signinMethod, session.extendedAuthentication?.challengeCreatedAt) ) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_RATE_LIMITED, 'you have been rate limited. please try again later.', ); @@ -294,8 +285,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro // challenge was already set. therefore, check for session. if (session?.extendedAuthentication === undefined || session?.extendedAuthentication?.type !== body.type) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, 'authentication request was not generated yet or had been invalidated.', ); @@ -305,8 +295,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro // validate current method is same with session's extendedAuthentication const extendedAuthSession = session.extendedAuthentication; if (extendedAuthSession.method !== body.data?.method) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_NOT_CURRENT_CHALLENGE_METHOD, `authentication request is using different challenge method. please request this endpoint without challengeResponse field to request challenge again.`, @@ -320,8 +309,7 @@ please request this endpoint without challengeResponse field to request challeng new Date().getTime() > extendedAuthSession.challengeCreatedAt.getTime() + config.token.invalidate.meiling.CHALLENGE_TOKEN * 1000 ) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_TIMEOUT, 'authentication request timed out, please recreate the challenge.', ); @@ -334,7 +322,7 @@ please request this endpoint without challengeResponse field to request challeng const authorizedUsers: UserModel[] = []; if (challenge === undefined) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, `challenge is missing.`); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, `challenge is missing.`); return; } @@ -381,18 +369,17 @@ please request this endpoint without challengeResponse field to request challeng if (authorizedUsers.length === 1) { userToLogin = authorizedUsers[0]; } else if (authorizedUsers.length > 1) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.MORE_THAN_ONE_USER_MATCHED, 'more than one user was matched, login using username instead.', ); return; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.SIGNIN_FAILED, 'No matching users'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.SIGNIN_FAILED, 'No matching users'); return; } } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_SIGNIN_TYPE, 'invalid signin type.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_SIGNIN_TYPE, 'invalid signin type.'); return; } diff --git a/src/routes/v1/meiling/signout.ts b/src/routes/v1/meiling/signout.ts index 1a0d4850..ec3c9888 100644 --- a/src/routes/v1/meiling/signout.ts +++ b/src/routes/v1/meiling/signout.ts @@ -36,8 +36,7 @@ export async function signoutHandler(req: FastifyRequest, rep: FastifyReply): Pr token: Meiling.Authentication.Token.getTokenFromRequest(req)?.token, }); } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.ALREADY_SIGNED_OUT, 'you are already signed out.', ); @@ -45,8 +44,7 @@ export async function signoutHandler(req: FastifyRequest, rep: FastifyReply): Pr } } } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.ALREADY_SIGNED_OUT, 'you are already signed out.', ); diff --git a/src/routes/v1/meiling/signup/index.ts b/src/routes/v1/meiling/signup/index.ts index 5b09c7b8..32ce1127 100644 --- a/src/routes/v1/meiling/signup/index.ts +++ b/src/routes/v1/meiling/signup/index.ts @@ -6,7 +6,7 @@ import { signupHandler } from './signup'; export function signupPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.addHook('onRequest', (req, rep, next) => { if (!config.meiling.signup.enabled) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED, 'Signup is disabled'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED, 'Signup is disabled'); return; } diff --git a/src/routes/v1/meiling/signup/signup.ts b/src/routes/v1/meiling/signup/signup.ts index 759863c5..61657cb3 100644 --- a/src/routes/v1/meiling/signup/signup.ts +++ b/src/routes/v1/meiling/signup/signup.ts @@ -20,8 +20,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro if (!Utils.isValidValue(body.username, body.email, body.phone, body.password)) { // you are out. - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `Invalid body (${['username', 'email', 'phone', 'password'].filter((n: string) => { return Utils.isValidValue(body[n as keyof MeilingV1Signup]); @@ -31,15 +30,14 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro } if (!Utils.isValidName(body.name)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Name'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Name'); return; } const signupChallenge = await Meiling.V1.Session.getAuthenticationStatus(req); if (signupChallenge === undefined) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, 'Signup Validation requests were not generated.', ); @@ -56,8 +54,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro // check user input is valid. if (!Utils.isValidUsername(username)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Username should be consisting alphanumeric characters and _, -, .', ); @@ -65,8 +62,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro } if (!Utils.isValidPassword(password)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'password should contain at least 8 characters.', ); @@ -74,8 +70,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro } if (!phone) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Phone number should be valid ITU compliant international number', ); @@ -83,8 +78,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro } if (!Utils.isValidEmail(email)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Entered email is NOT a valid email.', ); @@ -94,7 +88,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro // check with validation. if (!(signupChallenge.email?.isVerified && signupChallenge.phone?.isVerified)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED); return; } @@ -105,20 +99,19 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro phone.formatInternational() === libmobilephoneJs(signupChallenge.phone.to)?.formatInternational() ) ) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID); return; } const user = await Meiling.Identity.User.findByUsername(username); if (user.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.EXISTING_USERNAME); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.EXISTING_USERNAME); return; } const userByEmail = await Meiling.Identity.User.findByUsername(email); if (userByEmail.length > 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.EXISTING_USERNAME, 'there is already a user using same email', ); @@ -134,7 +127,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro }); if (emails.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.EMAIL_NOT_ALLOWED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.EMAIL_NOT_ALLOWED); return; } } @@ -147,7 +140,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro }); if (phones.length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.PHONE_NOT_ALLOWED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.PHONE_NOT_ALLOWED); return; } } diff --git a/src/routes/v1/meiling/users/actions/apps/actions/client_secret/delete.ts b/src/routes/v1/meiling/users/actions/apps/actions/client_secret/delete.ts index ccab3e3d..2d4d1210 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/client_secret/delete.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/client_secret/delete.ts @@ -21,7 +21,7 @@ async function clientSecretDeleteHandler(_req: FastifyRequest, rep: FastifyReply })) === 1; if (!res) { - return Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND, 'secret not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'secret not found'); } await getPrismaClient().oAuthClientSecrets.delete({ diff --git a/src/routes/v1/meiling/users/actions/apps/actions/client_secret/post.ts b/src/routes/v1/meiling/users/actions/apps/actions/client_secret/post.ts index 7cf1144f..9d1d85da 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/client_secret/post.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/client_secret/post.ts @@ -12,7 +12,7 @@ async function clientSecretPostHandler(_req: FastifyRequest, rep: FastifyReply): const secret = Meiling.Authentication.Token.generateToken(64); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } diff --git a/src/routes/v1/meiling/users/actions/apps/actions/index.ts b/src/routes/v1/meiling/users/actions/apps/actions/index.ts index ca24a784..a25e8802 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/index.ts @@ -19,8 +19,10 @@ function authorizedAppsActionsPlugin(app: FastifyInstance, opts: FastifyPluginOp const req = _req as MeilingV1ClientRequest; if (!req.status.authorized) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); - throw new Error('Unauthorized!'); + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.UNAUTHORIZED, + 'User has not authorized this application.', + ); } done(); @@ -37,8 +39,10 @@ function appOwnerActionsPlugin(app: FastifyInstance, opts: FastifyPluginOptions, const req = _req as MeilingV1ClientRequest; if (!req.status.owned) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); - throw new Error('Unauthorized!'); + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.UNAUTHORIZED, + 'User is not owner of this application.', + ); } done(); diff --git a/src/routes/v1/meiling/users/actions/apps/actions/permissions/delete.ts b/src/routes/v1/meiling/users/actions/apps/actions/permissions/delete.ts index b6429844..9f66364a 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/permissions/delete.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/permissions/delete.ts @@ -14,7 +14,7 @@ async function permissionsDeleteHandler(_req: FastifyRequest, rep: FastifyReply) } else if (permissionsRaw instanceof Array) { permissionsToRemove = permissionsRaw; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -32,8 +32,7 @@ async function permissionsDeleteHandler(_req: FastifyRequest, rep: FastifyReply) const toRemove = permissionsToRemove.filter((n) => permissions.includes(n)); if (toRemove.length === 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED, 'provided permissions array does not provide existing permissions', ); diff --git a/src/routes/v1/meiling/users/actions/apps/actions/permissions/post.ts b/src/routes/v1/meiling/users/actions/apps/actions/permissions/post.ts index 487da9a2..0b4e1c6a 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/permissions/post.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/permissions/post.ts @@ -14,7 +14,7 @@ async function permissionsPostHandler(_req: FastifyRequest, rep: FastifyReply): } else if (permissionsRaw instanceof Array) { permissionsToAdd = permissionsRaw; } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -42,8 +42,7 @@ async function permissionsPostHandler(_req: FastifyRequest, rep: FastifyReply): const toAdd = permissionsToAdd.filter((n) => availables.includes(n)); if (toAdd.length === 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED, 'provided permissions array does not provide available permissions', ); diff --git a/src/routes/v1/meiling/users/actions/apps/actions/redirect_uri/index.ts b/src/routes/v1/meiling/users/actions/apps/actions/redirect_uri/index.ts index c9a92416..b13f52b4 100644 --- a/src/routes/v1/meiling/users/actions/apps/actions/redirect_uri/index.ts +++ b/src/routes/v1/meiling/users/actions/apps/actions/redirect_uri/index.ts @@ -33,7 +33,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp let redirect_uri = (req.body as MeilingRedirectUriPostRequest).redirect_uri; if (!Utils.isNotBlank(redirect_uri) || !Utils.isValidUri(redirect_uri)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -44,7 +44,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp redirect_uri = tmp_redirect_uri.toString(); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); return; } @@ -60,7 +60,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp }); if (conflicts > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.CONFLICT, 'Redirect URI already exists'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.CONFLICT, 'Redirect URI already exists'); return; } @@ -85,7 +85,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp let redirect_uri = (req.body as MeilingRedirectUriPostRequest).redirect_uri; if (!Utils.isNotBlank(redirect_uri) || !Utils.isValidUri(redirect_uri)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -96,7 +96,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp redirect_uri = tmp_redirect_uri.toString(); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); return; } @@ -112,7 +112,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp }); if (deleteCount == 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND, 'Redirect URI not found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Redirect URI not found'); return; } @@ -133,7 +133,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp app.get('/:uuid', async (req_, rep) => { const req = req_ as MeilingV1ClientRequest; if (!Utils.isNotBlank((req.params as any).uuid)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -147,7 +147,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp }); if (match == null) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -160,7 +160,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp app.delete('/:uuid', async (req_, rep) => { const req = req_ as MeilingV1ClientRequest; if (!Utils.isNotBlank((req.params as any).uuid)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -174,7 +174,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp }); if (matches == 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } @@ -195,7 +195,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp let redirect_uri = (req.body as MeilingRedirectUriPostRequest).redirect_uri; if (!Utils.isNotBlank(redirect_uri) || !Utils.isValidUri(redirect_uri)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -206,7 +206,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp redirect_uri = tmp_redirect_uri.toString(); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid URI'); return; } @@ -222,7 +222,7 @@ export function appRedirectURIPlugin(app: FastifyInstance, opts: FastifyPluginOp }); if (matchingCount > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.CONFLICT, 'Redirect URI already exists'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.CONFLICT, 'Redirect URI already exists'); return; } diff --git a/src/routes/v1/meiling/users/actions/apps/delete.ts b/src/routes/v1/meiling/users/actions/apps/delete.ts index 3c85bb9a..217cd837 100644 --- a/src/routes/v1/meiling/users/actions/apps/delete.ts +++ b/src/routes/v1/meiling/users/actions/apps/delete.ts @@ -7,8 +7,7 @@ async function appDeleteHandler(req_: FastifyRequest, rep: FastifyReply): Promis const req = req_ as MeilingV1ClientRequest; if (!req.status.owned) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, "you don't have permission to do this.", ); diff --git a/src/routes/v1/meiling/users/actions/apps/get.ts b/src/routes/v1/meiling/users/actions/apps/get.ts index 4f1ba336..eb14acd9 100644 --- a/src/routes/v1/meiling/users/actions/apps/get.ts +++ b/src/routes/v1/meiling/users/actions/apps/get.ts @@ -13,7 +13,7 @@ async function appGetHandler(req_: FastifyRequest, rep: FastifyReply): Promise n.id === clientId).length > 0; if (!owned && !authorized) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND); - throw new Error('You do not own/authorized this'); + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND, + 'User has not authorized this application yet', + ); } const client = (await Meiling.OAuth2.Client.getByClientId(clientId)) as OAuthClient; diff --git a/src/routes/v1/meiling/users/actions/apps/post.ts b/src/routes/v1/meiling/users/actions/apps/post.ts index 48b21778..f6b5c57c 100644 --- a/src/routes/v1/meiling/users/actions/apps/post.ts +++ b/src/routes/v1/meiling/users/actions/apps/post.ts @@ -21,24 +21,23 @@ async function appCreateHandler(req: FastifyRequest, rep: FastifyReply): Promise const users = await Meiling.V1.Session.getLoggedIn(req); if (users.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } if (!Utils.isValidValue(body?.name, body?.image, body?.privacy, body?.terms, body?.accessControl?.permissions)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } const owner = await getUserFromActionRequest(req); if (!owner) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid ownerId'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid ownerId'); return; } if (users.filter((n) => n.id === owner.id).length === 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'you are not logged In for ownerId', ); @@ -60,7 +59,7 @@ async function appCreateHandler(req: FastifyRequest, rep: FastifyReply): Promise const permissionCheck = await Promise.all(permissionsPromises); if (permissionCheck.indexOf(null) >= 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid permissions'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid permissions'); return; } @@ -157,7 +156,7 @@ async function appCreateHandler(req: FastifyRequest, rep: FastifyReply): Promise }); if (!client) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); return; } diff --git a/src/routes/v1/meiling/users/actions/auth/auth.ts b/src/routes/v1/meiling/users/actions/auth/auth.ts index fd2fa673..c11634e5 100644 --- a/src/routes/v1/meiling/users/actions/auth/auth.ts +++ b/src/routes/v1/meiling/users/actions/auth/auth.ts @@ -14,30 +14,29 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: // validations if (!query.client_id) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing client_id'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing client_id'); return; } if (!query.response_type) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing response_type'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing response_type'); return; } if (!query.scope) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing scope'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing scope'); return; } if (!query.redirect_uri) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing redirect_uri'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing redirect_uri'); return; } // get userData of selected user const userData = await Meiling.Identity.User.getDetailedInfo(userBase); if (!userData) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'unable to fetch user from DB.', ); @@ -48,8 +47,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: const clientId = query.client_id; const client = await Meiling.OAuth2.Client.getByClientId(clientId); if (client === null) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND, 'oAuth2 application with specified client_id does not exist', ); @@ -59,8 +57,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: // load access control const acl = await Meiling.OAuth2.Client.getAccessControl(clientId); if (!acl) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'Failed to get Access Control from Server.', ); @@ -70,8 +67,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: // is this user able to pass client check const clientPrivateCheck = await Meiling.OAuth2.ClientAccessControls.checkUsers(acl, userBase); if (!clientPrivateCheck) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'specified oAuth2 application is inaccessible', ); @@ -101,8 +97,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: .filter((j) => j !== undefined); if (unsupportedScopes.length > 0) { // invalid permissions found! - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNSUPPORTED_SCOPE, `the scope: (${unsupportedScopes.join(' ')}) is not supported`, ); @@ -112,16 +107,14 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: const areScopesAllowed = await Meiling.OAuth2.ClientAccessControls.checkPermissions(acl, requestedPermissions); if (areScopesAllowed !== true) { if (areScopesAllowed === false) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'Failed to get Access Control from Server.', ); return; } else { const deniedScopes = areScopesAllowed.map((n) => n.name); - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_AUTHORIZED_SCOPES, `the scope (${deniedScopes.join(' ')}) is not authorized`, ); @@ -141,8 +134,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: // if no redirectUri rule that meets user provided redirectUri if (!redirectUriCheck) { // callback match failed - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_REDIRECT_URI_INVALID, `${query.redirect_uri} is not in pre-defined redirect uri.`, ); @@ -154,8 +146,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: let code_challenge = false; if (query.code_challenge || query.code_challenge_method) { if (!Utils.isValidValue(query.code_challenge, query.code_challenge_method)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge should send code_challenge_method too.`, ); @@ -163,8 +154,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: } if (query.code_challenge_method !== 'S256' && query.code_challenge_method !== 'plain') { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge_method should be S256 or plain`, ); @@ -173,8 +163,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: if (query.code_challenge_method === 'S256') { if (!Utils.checkBase64(query.code_challenge as string)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge should be base64 encoded sha256 hash string`, ); @@ -229,8 +218,7 @@ export async function meilingV1OAuthClientAuthHandler(req: FastifyRequest, rep: }); return; } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid response_type: (' + query.response_type + ') .', ); diff --git a/src/routes/v1/meiling/users/actions/auth/check.ts b/src/routes/v1/meiling/users/actions/auth/check.ts index 63b1d133..51a2e79c 100644 --- a/src/routes/v1/meiling/users/actions/auth/check.ts +++ b/src/routes/v1/meiling/users/actions/auth/check.ts @@ -14,35 +14,34 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, // validation if (!query.client_id) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing client_id'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing client_id'); return; } if (!query.response_type) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing response_type'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing response_type'); return; } if (!query.scope) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing scope'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing scope'); return; } if (!query.redirect_uri) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing redirect_uri'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing redirect_uri'); return; } if (query.display === 'page') { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.APPLICATION_USER_ACTION_REQUIRED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.APPLICATION_USER_ACTION_REQUIRED); return; } // get userData of selected user const userData = await Meiling.Identity.User.getDetailedInfo(userBase); if (!userData) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'unable to fetch user from DB.', ); @@ -53,8 +52,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, const clientId = query.client_id; const client = await Meiling.OAuth2.Client.getByClientId(clientId); if (client === null) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND, 'oAuth2 application with specified client_id does not exist', ); @@ -64,8 +62,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, // load access control const acl = await Meiling.OAuth2.Client.getAccessControl(clientId); if (!acl) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'Failed to get Access Control from Server.', ); @@ -75,8 +72,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, // is this user able to pass client check const clientPrivateCheck = await Meiling.OAuth2.ClientAccessControls.checkUsers(acl, userBase); if (!clientPrivateCheck) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'specified oAuth2 application is inaccessible', ); @@ -106,8 +102,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, .filter((j) => j !== undefined); if (unsupportedScopes.length > 0) { // invalid permissions found! - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNSUPPORTED_SCOPE, `the scope: (${unsupportedScopes.join(' ')}) is not supported`, ); @@ -117,16 +112,14 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, const areScopesAllowed = await Meiling.OAuth2.ClientAccessControls.checkPermissions(acl, requestedPermissions); if (areScopesAllowed !== true) { if (areScopesAllowed === false) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'Failed to get Access Control from Server.', ); return; } else { const deniedScopes = areScopesAllowed.map((n) => n.name); - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_AUTHORIZED_SCOPES, `the scope: (${deniedScopes.join(' ')}) is not authorized`, ); @@ -140,8 +133,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, // if no redirectUri rule that meets user provided redirectUri if (!redirectUriCheck) { // callback match failed - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_REDIRECT_URI_INVALID, `${query.redirect_uri} is not in pre-defined redirect uri.`, ); @@ -157,8 +149,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, if (!(permissionCheck || shouldBypassPermissionCheck)) { // new permissions added. // user action required! nope! - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_USER_ACTION_REQUIRED, 'permission upgrade was requested, user action with prompt is required.', ); @@ -170,8 +161,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, let code_challenge = false; if (query.code_challenge || query.code_challenge_method) { if (!Utils.isValidValue(query.code_challenge, query.code_challenge_method)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge should send code_challenge_method too.`, ); @@ -179,8 +169,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, } if (query.code_challenge_method !== 'S256' && query.code_challenge_method !== 'plain') { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge_method should be S256 or plain`, ); @@ -189,8 +178,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, if (query.code_challenge_method === 'S256') { if (!Utils.checkBase64(query.code_challenge as string)) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, `code_challenge should be base64 encoded sha256 hash string`, ); @@ -245,8 +233,7 @@ export async function meilingV1OAuthClientAuthCheckHandler(req: FastifyRequest, }); return; } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid response_type: (' + query.response_type + ') .', ); diff --git a/src/routes/v1/meiling/users/actions/auth/device/auth.ts b/src/routes/v1/meiling/users/actions/auth/device/auth.ts index 232fab1a..e55a5514 100644 --- a/src/routes/v1/meiling/users/actions/auth/device/auth.ts +++ b/src/routes/v1/meiling/users/actions/auth/device/auth.ts @@ -18,7 +18,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti // validate if (!Utils.isValidValue(query, query.user_code)) { if (!Utils.isValidValue(body, body.user_code)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing user_code.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing user_code.'); return; } @@ -28,8 +28,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti // get userData of selected user const userData = await Meiling.Identity.User.getDetailedInfo(userBase); if (!userData) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'unable to fetch user from DB.', ); @@ -53,7 +52,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti query.user_code, ); if (matchingUserCodes.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'no matching user_code found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'no matching user_code found'); return; } @@ -61,8 +60,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti const client = await Meiling.OAuth2.ClientAuthorization.getClient(userCode.authorizationId); if (!client) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND, 'unable to find proper client', ); @@ -72,8 +70,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti // load access control const acl = await Meiling.OAuth2.Client.getAccessControl(client.id); if (!acl) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'Failed to get Access Control from Server.', ); @@ -83,8 +80,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti // is this user able to pass client check const clientPrivateCheck = await Meiling.OAuth2.ClientAccessControls.checkUsers(acl, userBase); if (!clientPrivateCheck) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'specified oAuth2 application is inaccessible', ); @@ -93,8 +89,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti const authorization = await Meiling.OAuth2.ClientAuthorization.getById(userCode.authorizationId); if (!authorization) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, "specified oAuth2 application didn't requested this authorization session", ); @@ -116,8 +111,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti const metadata = userCode.metadata as unknown as Meiling.Authentication.Token.TokenMetadata; if (!metadata?.data?.deviceCode) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, "token doesn't seems to be have proper metadata", ); diff --git a/src/routes/v1/meiling/users/actions/auth/device/check.ts b/src/routes/v1/meiling/users/actions/auth/device/check.ts index 8d550d5f..bcd0bfe6 100644 --- a/src/routes/v1/meiling/users/actions/auth/device/check.ts +++ b/src/routes/v1/meiling/users/actions/auth/device/check.ts @@ -18,7 +18,7 @@ export async function deviceCodeCheckHandler(req: FastifyRequest, rep: FastifyRe // validate if (!Utils.isValidValue(query, query.user_code)) { if (!Utils.isValidValue(body, body.user_code)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing user_code.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing user_code.'); return; } @@ -28,8 +28,7 @@ export async function deviceCodeCheckHandler(req: FastifyRequest, rep: FastifyRe // get userData of selected user const userData = await Meiling.Identity.User.getDetailedInfo(userBase); if (!userData) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, 'unable to fetch user from DB.', ); @@ -53,7 +52,7 @@ export async function deviceCodeCheckHandler(req: FastifyRequest, rep: FastifyRe query.user_code, ); if (matchingUserCodes.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'no matching user_code found'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'no matching user_code found'); return; } @@ -61,8 +60,7 @@ export async function deviceCodeCheckHandler(req: FastifyRequest, rep: FastifyRe const client = await Meiling.OAuth2.ClientAuthorization.getClient(userCode.authorizationId); if (!client) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.APPLICATION_NOT_FOUND, 'unable to find proper client', ); @@ -71,8 +69,7 @@ export async function deviceCodeCheckHandler(req: FastifyRequest, rep: FastifyRe const authorization = await Meiling.OAuth2.ClientAuthorization.getById(userCode.authorizationId); if (!authorization) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, "specified oAuth2 application didn't requested this authorization session", ); diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index 8e884f62..8630d5c3 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -13,15 +13,12 @@ export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOpti app.addHook('onRequest', async (req, rep) => { const userBase = await getUserFromActionRequest(req); if (userBase === undefined) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid request.'); - throw new Error('User is not privileged to run this command'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid request.'); } else if (userBase === null) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'you are not logged in as specified user.', ); - throw new Error('User is not privileged to run this command'); } }); diff --git a/src/routes/v1/meiling/users/actions/info/get.ts b/src/routes/v1/meiling/users/actions/info/get.ts index 813f0561..7e3b1dfb 100644 --- a/src/routes/v1/meiling/users/actions/info/get.ts +++ b/src/routes/v1/meiling/users/actions/info/get.ts @@ -19,20 +19,18 @@ export async function userGetInfo(req: FastifyRequest, rep: FastifyReply) { rep.send(user); return; } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_FOUND, 'specified user uuid was not available.', ); } } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'required field (user uuid) is missing', ); } } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); } } diff --git a/src/routes/v1/meiling/users/actions/info/list.ts b/src/routes/v1/meiling/users/actions/info/list.ts index d9e1b17c..ac85f9c7 100644 --- a/src/routes/v1/meiling/users/actions/info/list.ts +++ b/src/routes/v1/meiling/users/actions/info/list.ts @@ -9,7 +9,7 @@ export async function userGetLoggedInUserInfo(req: FastifyRequest, rep: FastifyR if (userRawSession && userRawSession.length > 0) { const users = session.user; if (!users) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); return; } @@ -22,6 +22,6 @@ export async function userGetLoggedInUserInfo(req: FastifyRequest, rep: FastifyR rep.send(result); } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); } } diff --git a/src/routes/v1/meiling/users/actions/info/put.ts b/src/routes/v1/meiling/users/actions/info/put.ts index b0b2a0d1..903f3fbe 100644 --- a/src/routes/v1/meiling/users/actions/info/put.ts +++ b/src/routes/v1/meiling/users/actions/info/put.ts @@ -31,8 +31,7 @@ export async function userUpdateInfo(req: FastifyRequest, rep: FastifyReply) { }); if (!user) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_FOUND, 'specified user uuid was not available.', ); @@ -41,8 +40,7 @@ export async function userUpdateInfo(req: FastifyRequest, rep: FastifyReply) { const isLockOK = await Meiling.Identity.User.checkLockedProps(user.id, body); if (!isLockOK) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.FORBIDDEN, 'you can not update locked prop fields', ); @@ -65,20 +63,18 @@ export async function userUpdateInfo(req: FastifyRequest, rep: FastifyReply) { rep.send(await getSanitizedUser(user.id)); return; } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_FOUND, 'specified user uuid was not available.', ); } } else { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'required field (user uuid) is missing', ); } } else { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); } } diff --git a/src/routes/v1/meiling/users/actions/security/2fa/enable/index.ts b/src/routes/v1/meiling/users/actions/security/2fa/enable/index.ts index 03a908bb..bc93e6c0 100644 --- a/src/routes/v1/meiling/users/actions/security/2fa/enable/index.ts +++ b/src/routes/v1/meiling/users/actions/security/2fa/enable/index.ts @@ -8,7 +8,7 @@ function user2FAEnablePlugin(app: FastifyInstance, opts: FastifyPluginOptions, d app.get('/', async (req, rep) => { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } @@ -20,7 +20,7 @@ function user2FAEnablePlugin(app: FastifyInstance, opts: FastifyPluginOptions, d app.post('/', async (req, rep) => { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } @@ -87,8 +87,7 @@ function user2FAEnablePlugin(app: FastifyInstance, opts: FastifyPluginOptions, d const twoFactorReadyMethods = currentAvailables.filter((n) => n.available && n.enabled['2fa']); if (twoFactorReadyMethods.length === 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.UNSUPPORTED_SIGNIN_METHOD, 'there is no 2fa supported method to login', ); @@ -110,7 +109,7 @@ function user2FAEnablePlugin(app: FastifyInstance, opts: FastifyPluginOptions, d app.delete('/', async (req, rep) => { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } diff --git a/src/routes/v1/meiling/users/actions/security/2fa/get.ts b/src/routes/v1/meiling/users/actions/security/2fa/get.ts index 5071c524..6acf9301 100644 --- a/src/routes/v1/meiling/users/actions/security/2fa/get.ts +++ b/src/routes/v1/meiling/users/actions/security/2fa/get.ts @@ -6,7 +6,7 @@ import { Meiling } from '../../../../../../../common'; async function get2FAInfo(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } diff --git a/src/routes/v1/meiling/users/actions/security/passwords/delete.ts b/src/routes/v1/meiling/users/actions/security/passwords/delete.ts index b1f6e0b4..a7cd0a11 100644 --- a/src/routes/v1/meiling/users/actions/security/passwords/delete.ts +++ b/src/routes/v1/meiling/users/actions/security/passwords/delete.ts @@ -9,7 +9,7 @@ export async function userPasswordDeleteHandler(req: FastifyRequest, rep: Fastif const body = req.body as PasswordBody; if (!body?.password) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid request.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid request.'); return; } diff --git a/src/routes/v1/meiling/users/actions/security/passwords/post.ts b/src/routes/v1/meiling/users/actions/security/passwords/post.ts index 6db03533..6ca7f4c1 100644 --- a/src/routes/v1/meiling/users/actions/security/passwords/post.ts +++ b/src/routes/v1/meiling/users/actions/security/passwords/post.ts @@ -8,13 +8,13 @@ export async function userPasswordCreateHandler(req: FastifyRequest, rep: Fastif const body = req.body as PasswordBody; if (!Utils.isValidValue(body, body?.password)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body.'); return; } const password = body.password; if ((await Meiling.Identity.User.checkPassword(user, password)).length > 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.EXISTING_PASSWORD, 'existing password.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.EXISTING_PASSWORD, 'existing password.'); return; } diff --git a/src/routes/v1/meiling/users/actions/security/passwords/put.ts b/src/routes/v1/meiling/users/actions/security/passwords/put.ts index 43199012..c3bf8d4d 100644 --- a/src/routes/v1/meiling/users/actions/security/passwords/put.ts +++ b/src/routes/v1/meiling/users/actions/security/passwords/put.ts @@ -10,21 +10,20 @@ export async function userPasswordUpdateHandler(req: FastifyRequest, rep: Fastif const body = req.body as PasswordChangeBody; if (!Utils.isValidValue(body, body?.password, body?.newPassword)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid body.'); return; } const password = body.password; const passwordRowsToChange = await Meiling.Identity.User.checkPassword(user, password); if (passwordRowsToChange.length === 0) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.WRONG_PASSWORD, 'wrong password.'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_PASSWORD, 'wrong password.'); return; } const newPassword = body.newPassword; if ((await Meiling.Identity.User.checkPassword(user, newPassword)).length > 0) { - Meiling.V1.Error.sendMeilingError( - rep, + throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.EXISTING_PASSWORD, 'existing password is used as new password.', ); diff --git a/src/routes/v1/meiling/users/actions/security/pgp/actions/delete.ts b/src/routes/v1/meiling/users/actions/security/pgp/actions/delete.ts index 432a0cdc..ffd41f35 100644 --- a/src/routes/v1/meiling/users/actions/security/pgp/actions/delete.ts +++ b/src/routes/v1/meiling/users/actions/security/pgp/actions/delete.ts @@ -8,13 +8,13 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userPGPActionDeleteKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const pgpId = (req.params as any).pgpId; if (!Utils.isNotBlank(pgpId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -30,7 +30,7 @@ async function userPGPActionDeleteKey(req: FastifyRequest, rep: FastifyReply): P })) > 0; if (!checkExist) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/pgp/actions/get.ts b/src/routes/v1/meiling/users/actions/security/pgp/actions/get.ts index bc04a529..f7d1c72d 100644 --- a/src/routes/v1/meiling/users/actions/security/pgp/actions/get.ts +++ b/src/routes/v1/meiling/users/actions/security/pgp/actions/get.ts @@ -8,13 +8,13 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userPGPActionGetKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const pgpId = (req.params as any).pgpId; if (!Utils.isNotBlank(pgpId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -29,7 +29,7 @@ async function userPGPActionGetKey(req: FastifyRequest, rep: FastifyReply): Prom }); if (!keyData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/pgp/actions/put.ts b/src/routes/v1/meiling/users/actions/security/pgp/actions/put.ts index fa8a0669..fb5c8869 100644 --- a/src/routes/v1/meiling/users/actions/security/pgp/actions/put.ts +++ b/src/routes/v1/meiling/users/actions/security/pgp/actions/put.ts @@ -8,18 +8,18 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userPGPActionPutKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const pgpId = (req.params as any).pgpId; if (!Utils.isNotBlank(pgpId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } if (!req.body) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -36,7 +36,7 @@ async function userPGPActionPutKey(req: FastifyRequest, rep: FastifyReply): Prom }); if (!keyData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/pgp/get.ts b/src/routes/v1/meiling/users/actions/security/pgp/get.ts index 76ef1964..e96ef37c 100644 --- a/src/routes/v1/meiling/users/actions/security/pgp/get.ts +++ b/src/routes/v1/meiling/users/actions/security/pgp/get.ts @@ -8,7 +8,7 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userPGPGetKeys(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } diff --git a/src/routes/v1/meiling/users/actions/security/pgp/post.ts b/src/routes/v1/meiling/users/actions/security/pgp/post.ts index 98470440..100b91d7 100644 --- a/src/routes/v1/meiling/users/actions/security/pgp/post.ts +++ b/src/routes/v1/meiling/users/actions/security/pgp/post.ts @@ -10,13 +10,13 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userPGPPostKeys(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const { name, key } = (req.body as any) || {}; if (!Utils.isNotBlank(name, key)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -50,7 +50,7 @@ async function userPGPPostKeys(req: FastifyRequest, rep: FastifyReply): Promise< rep.send({ success: true }); } catch (e) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid pgp key'); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid pgp key'); return; } } diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts index 05debf1b..23f5cac4 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts @@ -8,13 +8,13 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userWebAuthnActionDeleteKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const tokenId = (req.params as any).tokenId; if (!Utils.isNotBlank(tokenId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -30,7 +30,7 @@ async function userWebAuthnActionDeleteKey(req: FastifyRequest, rep: FastifyRepl })) > 0; if (!checkExist) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts index 0251924f..223ca95c 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts @@ -8,13 +8,13 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userWebAuthnActionGetKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const tokenId = (req.params as any).tokenId; if (!Utils.isNotBlank(tokenId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -29,7 +29,7 @@ async function userWebAuthnActionGetKey(req: FastifyRequest, rep: FastifyReply): }); if (!keyData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts index b9e6791a..b8461990 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts @@ -8,18 +8,18 @@ const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.E async function userWebAuthnActionPutKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } const tokenId = (req.params as any).tokenId; if (!Utils.isNotBlank(tokenId)) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } if (!req.body) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -36,7 +36,7 @@ async function userWebAuthnActionPutKey(req: FastifyRequest, rep: FastifyReply): }); if (!keyData) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.NOT_FOUND); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); return; } diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts index b0a4af58..9d5666e3 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts @@ -8,7 +8,7 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do app.get('/', async (req, rep) => { const user = await getUserFromActionRequest(req); if (!user) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } @@ -38,7 +38,7 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do const user = await getUserFromActionRequest(req); if (!user || !session) { - Meiling.V1.Error.sendMeilingError(rep, Meiling.V1.Error.ErrorType.UNAUTHORIZED); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); return; } diff --git a/tsconfig.json b/tsconfig.json index e9ba7271..1c172178 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,14 +4,15 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "declarationMap": true, + /* Generates a sourcemap for each corresponding '.d.ts' file. */ "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ "outDir": "./dist/", /* Redirect output structure to the directory. */ From ac5def61213c882c83ce68a70018d418962fba4a Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Tue, 15 Feb 2022 08:00:09 +0000 Subject: [PATCH 02/95] feat: add swagger --- package.json | 1 + src/common/fastify/index.ts | 38 +++++++ src/common/index.ts | 2 + src/common/terminal/banner.ts | 8 +- src/index.ts | 16 ++- yarn.lock | 183 ++++++++++++++++++++++++++++++++-- 6 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 src/common/fastify/index.ts diff --git a/package.json b/package.json index 7bd6f998..01f81ecf 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "fastify-cors": "^5.1.0", "fastify-formbody": "^5.0.0", "fastify-secure-session": "^2.3.0", + "fastify-swagger": "^4.15.0", "figlet": "^1.5.0", "jsonwebtoken": "^8.5.1", "libphonenumber-js": "^1.9.49", diff --git a/src/common/fastify/index.ts b/src/common/fastify/index.ts new file mode 100644 index 00000000..4ea1ac93 --- /dev/null +++ b/src/common/fastify/index.ts @@ -0,0 +1,38 @@ +import { FastifyInstance } from 'fastify'; +import fastifySwagger from 'fastify-swagger'; +import { nameStylized } from '..'; +import { info as packageJson } from '../../resources/package'; +import config from '../../resources/config'; + +export function setupSwaggerUI(app: FastifyInstance) { + app.register(fastifySwagger, { + routePrefix: '/docs', + openapi: { + info: { + title: nameStylized, + description: packageJson.description, + version: packageJson.version, + }, + externalDocs: { + url: 'https://meili.ng', + description: 'GitHub Repository', + }, + servers: [ + { + url: config.meiling.hostname, + }, + ], + components: { + securitySchemes: { + apiKey: { + type: 'apiKey', + name: 'apiKey', + in: 'header', + }, + }, + }, + }, + hideUntagged: true, + exposeRoute: true, + }); +} diff --git a/src/common/index.ts b/src/common/index.ts index 09ad3956..3fee9bc5 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,3 +1,5 @@ +export const nameStylized = 'meiliNG'; + export * as Meiling from './meiling'; export * as Event from './event'; export * as Terminal from './terminal'; diff --git a/src/common/terminal/banner.ts b/src/common/terminal/banner.ts index 1ffb0cf5..c0bd38e3 100644 --- a/src/common/terminal/banner.ts +++ b/src/common/terminal/banner.ts @@ -4,15 +4,15 @@ import { info as packageJson } from '../../resources/package'; import Figlet from 'figlet'; import chalk from 'chalk'; import { NodeEnvironment } from '../../interface'; -import { Utils } from '..'; +import { nameStylized, Utils } from '..'; export const showBanner = (): void => { - console.log(Figlet.textSync('meiliNG', 'Small Slant')); + console.log(Figlet.textSync(nameStylized, 'Small Slant')); console.log(); - console.log(`${chalk.bold('meiliNG')} - ${chalk.italic(`ver. ${packageJson.version}`)}`); + console.log(`${chalk.bold(nameStylized)} - ${chalk.italic(`ver. ${packageJson.version}`)}`); console.log(chalk.cyan(chalk.underline(packageJson.repository))); console.log(); - console.log(`Copyright © meiliNG Contributors`); + console.log(`Copyright © ${nameStylized} Contributors`); console.log( `Built with ${chalk.redBright('<3')} by ${chalk.cyan('Stella')} ${chalk.blue('IT')} ${chalk.magenta( 'Inc.', diff --git a/src/index.ts b/src/index.ts index 7ce198dd..7813e04f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,8 @@ -import chalk from 'chalk'; import fastify from 'fastify'; import fastifyFormbody from 'fastify-formbody'; import fs from 'fs'; import { Meiling, Startup, Terminal } from './common'; +import { setupSwaggerUI } from './common/fastify'; import config from './resources/config'; import meilingPlugin from './routes'; @@ -26,18 +26,19 @@ const main = async () => { : false, }); - Terminal.Log.info('Registering for Fastify Handler'); + Terminal.Log.info('Registering for Fastify Handler for form handling...'); app.register(fastifyFormbody); + Terminal.Log.info('Testing database connection...'); if (!(await Meiling.Database.testDatabase())) { Terminal.Log.error('Failed to connect! Please check if database is online.'); process.exit(1); } - Terminal.Log.info('Running check for JWT certificate configuration for ID Token generation...'); + Terminal.Log.info('Running check for JWT certificate configuration for id_token generation...'); await Startup.checkIDTokenIssueCredentials(); - Terminal.Log.info('Running Startup Garbage Collection...'); + Terminal.Log.info('Running Garbage Collection...'); await Startup.runStartupGarbageCollection(); Terminal.Log.info('Registering Root Endpoints...'); @@ -45,10 +46,14 @@ const main = async () => { if (typeof config.fastify.listen === 'string') { if (fs.existsSync(config.fastify.listen)) { + Terminal.Log.info('Deleting existing UNIX Socket...'); fs.unlinkSync(config.fastify.listen); } } + Terminal.Log.info('Preparing SwaggerUI for API Docs...'); + setupSwaggerUI(app); + Terminal.Log.info('Starting up fastify...'); await app.listen(config.fastify.listen, config.fastify.address); @@ -67,6 +72,9 @@ const main = async () => { } } + Terminal.Log.info('Starting up SwaggerUI...'); + app.swagger(); + Terminal.Log.ok('meiliNG has started up.'); }; diff --git a/yarn.lock b/yarn.lock index d61bc75b..4498658e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -490,6 +490,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + args@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/args/-/args-5.0.1.tgz#4bf298df90a4799a09521362c579278cc2fdd761" @@ -808,6 +813,13 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +content-disposition@^0.5.3: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + cookie-signature@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.1.0.tgz#cc94974f91fb9a9c1bb485e95fc2b7f4b120aff2" @@ -883,6 +895,13 @@ dateformat@^4.5.1: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -934,6 +953,16 @@ denque@^2.0.1: resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -977,6 +1006,11 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + elliptic@^6.4.0: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -995,6 +1029,16 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding-negotiator@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz#79871bb5473b81f6a0670e8de5303fb5ee0868a3" + integrity sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ== + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1021,6 +1065,11 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1171,6 +1220,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -1292,6 +1346,30 @@ fastify-secure-session@^2.3.0: fastify-plugin "^3.0.0" sodium-native "^3.0.0" +fastify-static@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.5.0.tgz#0d3feff5373f5ed9c4e4cf31a2b84c2f70c35bb2" + integrity sha512-Q7Tgl55AjsmBwiO4hKYib2BUCt+XTWLJ6Xp8YPPHU3EsrKNpevJ4cz8pjf1Ey1QhHw9O8Y2FDKdu+IC74oHvqw== + dependencies: + content-disposition "^0.5.3" + encoding-negotiator "^2.0.1" + fastify-plugin "^3.0.0" + glob "^7.1.4" + p-limit "^3.1.0" + readable-stream "^3.4.0" + send "^0.17.1" + +fastify-swagger@^4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/fastify-swagger/-/fastify-swagger-4.15.0.tgz#993cb8fe6d818cb7d456f8a9290ad3de39f0228f" + integrity sha512-gFHc1FcvYLvhGhQvtb3KlxnF+CeM/0mIDJ6E12/kBTPJ1tYDeqIXwAdKZJ19abcReYEH6J3UAnLXDh7cmhT/IQ== + dependencies: + fastify-plugin "^3.0.0" + fastify-static "^4.0.0" + js-yaml "^4.0.0" + json-schema-resolver "^1.3.0" + openapi-types "^10.0.0" + fastify-warning@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" @@ -1397,6 +1475,11 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1450,7 +1533,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -1556,6 +1639,17 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -1630,7 +1724,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1777,6 +1871,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" @@ -1787,6 +1888,15 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-resolver@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-schema-resolver/-/json-schema-resolver-1.3.0.tgz#0840864b06780363d31fb03cdfae5047e2f81fbb" + integrity sha512-EX7W1r8aZ/T3j8GbbBxPXi60bnsELfT90OiA1QrbGMvwzVSbyMNOAzvMFcFb8m7gKCXZLJpGe+cJOvWgoFl29A== + dependencies: + debug "^4.1.1" + rfdc "^1.1.4" + uri-js "^4.2.2" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2061,6 +2171,11 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -2098,12 +2213,17 @@ mri@1.1.4: resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2210,6 +2330,13 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2224,6 +2351,11 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +openapi-types@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-10.0.0.tgz#0debbf663b2feed0322030b5b7c9080804076934" + integrity sha512-Y8xOCT2eiKGYDzMW9R4x5cmfc3vGaaI4EL2pwhDmodWw1HlK18YcZ4uJxc7Rdp7/gGzAygzH9SXr6GKYIXbRcQ== + opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" @@ -2255,7 +2387,7 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -2504,6 +2636,11 @@ quick-format-unescaped@^4.0.3: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -2514,7 +2651,7 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^3.0.0, readable-stream@^3.6.0: +readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -2618,7 +2755,7 @@ rxjs@^7.5.1: dependencies: tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -2691,6 +2828,25 @@ semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" +send@^0.17.1: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -2701,6 +2857,11 @@ set-cookie-parser@^2.4.1: resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -2832,6 +2993,11 @@ ssh2@^1.5.0: cpu-features "0.0.2" nan "^2.15.0" +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + string-argv@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -2941,6 +3107,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" From 51063bd7faee0676c3ba99fa0193533a587fd1ba Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Tue, 15 Feb 2022 10:50:02 +0000 Subject: [PATCH 03/95] chore: add meiling v1 session support --- src/common/fastify/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/fastify/index.ts b/src/common/fastify/index.ts index 4ea1ac93..4efd7f14 100644 --- a/src/common/fastify/index.ts +++ b/src/common/fastify/index.ts @@ -24,10 +24,10 @@ export function setupSwaggerUI(app: FastifyInstance) { ], components: { securitySchemes: { - apiKey: { - type: 'apiKey', - name: 'apiKey', - in: 'header', + sessionV1: { + type: 'http', + description: 'Session Token for Meiling V1 Endpoints', + scheme: 'bearer', }, }, }, From 4b0cbba483f4e65b914341df7ff770439b253af5 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Tue, 15 Feb 2022 14:33:20 +0000 Subject: [PATCH 04/95] chore: umm... implemented basics --- .swcrc | 2 +- package.json | 5 +- src/common/fastify/index.ts | 33 ++++++++ src/index.ts | 8 +- src/routes/v1/meiling/index.ts | 137 ++++++++++++++++++++++++++++++- src/routes/v1/meiling/session.ts | 101 +++++++++++++++-------- src/routes/v1/meiling/signin.ts | 2 - 7 files changed, 243 insertions(+), 45 deletions(-) diff --git a/.swcrc b/.swcrc index ff29857d..a7d87f33 100644 --- a/.swcrc +++ b/.swcrc @@ -14,7 +14,7 @@ "loose": true }, "module": { - "type": "es6", + "type": "commonjs", "strict": false, "strictMode": true, "lazy": true, diff --git a/package.json b/package.json index 01f81ecf..edc78178 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meiling", - "version": "0.8.4", + "version": "0.8.4-snapshot", "description": "An Opensource Next Generation \"Gatekeeper\" with oAuth2 Authentication Provider and OpenID Connect Server", "main": "dist/", "repository": "https://github.com/meili-NG/meiliNG", @@ -70,7 +70,8 @@ "migrate:redeploy": "prisma migrate reset --preview-feature; rm -rf ./prisma/migrations/; prisma migrate dev --preview-feature", "generate": "prisma generate", "keygen": "node ./keygen.js", - "cleanup": "node ./dist/cleanup.js" + "cleanup": "node ./dist/cleanup.js", + "env:setup": "NODE_OPTIONS=\"--es-module-specifier-resolution=node\"" }, "husky": { "hooks": { diff --git a/src/common/fastify/index.ts b/src/common/fastify/index.ts index 4efd7f14..cde0eaf5 100644 --- a/src/common/fastify/index.ts +++ b/src/common/fastify/index.ts @@ -35,4 +35,37 @@ export function setupSwaggerUI(app: FastifyInstance) { hideUntagged: true, exposeRoute: true, }); + + app.addSchema({ + $id: 'Any', + anyOf: [ + { + type: 'string', + nullable: true, + }, + { + type: 'number', + nullable: true, + }, + { + type: 'boolean', + nullable: true, + }, + { + type: 'integer', + nullable: true, + }, + { + type: 'array', + items: { + $ref: 'Any#', + }, + nullable: true, + }, + { + type: 'object', + nullable: true, + }, + ], + }); } diff --git a/src/index.ts b/src/index.ts index 7813e04f..04cdc6db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,7 +29,10 @@ const main = async () => { Terminal.Log.info('Registering for Fastify Handler for form handling...'); app.register(fastifyFormbody); - Terminal.Log.info('Testing database connection...'); + Terminal.Log.info('Preparing SwaggerUI for API Docs...'); + setupSwaggerUI(app); + + Terminal.Log.info('Initiating database connection...'); if (!(await Meiling.Database.testDatabase())) { Terminal.Log.error('Failed to connect! Please check if database is online.'); process.exit(1); @@ -51,9 +54,6 @@ const main = async () => { } } - Terminal.Log.info('Preparing SwaggerUI for API Docs...'); - setupSwaggerUI(app); - Terminal.Log.info('Starting up fastify...'); await app.listen(config.fastify.listen, config.fastify.address); diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index cccafe45..d40e9b37 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -17,6 +17,18 @@ export interface FastifyRequestWithSession extends FastifyRequest { } function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.addSchema({ + $id: 'MeilingV1Error', + type: 'object', + properties: { + type: { type: 'string', enum: Object.values(Meiling.V1.Error.ErrorType) }, + description: { type: 'string' }, + details: { type: 'string' }, + debug: { type: 'object', nullable: true }, + stack: { type: 'string', nullable: true }, + }, + }); + app.setErrorHandler(async (_err, req, rep) => { const err = _err as Error; if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { @@ -28,6 +40,7 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: if (_err.validation) { // if it is validation issue, the error type is INVALID_REQUEST const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + console.error(_err); error.loadError(_err); return error.sendFastify(rep); @@ -66,13 +79,133 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, const session = await Meiling.V1.Session.getSessionFromRequest(req); if (!session) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_SESSION); - throw new Error(); } (req as FastifyRequestWithSession).session = session; }); - app.post('/signin', signinHandler); + app.addSchema({ + $id: 'MeilingV1SigninAuthnData', + type: 'object', + properties: { + method: { type: 'string', enum: Object.values(Meiling.V1.Interfaces.ExtendedAuthMethods), nullable: true }, + challengeResponse: { type: 'string', nullable: true }, + challengeContext: { $ref: 'Any#' }, + }, + }); + + app.post( + '/signin', + { + schema: { + description: 'Endpoint to sign-in current session into specified account', + tags: ['meiling'], + summary: 'Signin', + security: [{ sessionV1: [] }], + params: {}, + body: { + oneOf: [ + { + type: 'object', + properties: { + type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.USERNAME_CHECK] }, + data: { + type: 'object', + properties: { + username: { type: 'string' }, + }, + }, + }, + }, + { + type: 'object', + properties: { + type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.USERNAME_AND_PASSWORD] }, + data: { + type: 'object', + properties: { + username: { type: 'string' }, + password: { type: 'string' }, + }, + }, + }, + }, + { + type: 'object', + properties: { + type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH] }, + data: { + $ref: 'MeilingV1SigninAuthnData#', + }, + }, + }, + ], + }, + response: { + 200: { + oneOf: [ + { + type: 'object', + description: + '(on username check) When the user was previously logged in and matches only one user, returns abstract user info.', + properties: { + success: { type: 'boolean' }, + data: { + type: 'object', + description: 'abstract user data', + properties: { + id: { type: 'string', format: 'uuid' }, + profileId: { type: 'string', format: 'uri', nullable: true }, + name: { type: 'string', nullable: true }, + username: { type: 'string' }, + }, + nullable: true, + }, + }, + }, + { + type: 'object', + description: '(on 2fa session) When user requests available 2fa methods, this is how meiliNG returns.', + properties: { + methods: { + type: 'array', + items: { + type: 'string', + enum: Object.values(Meiling.V1.Interfaces.ExtendedAuthMethods), + }, + }, + }, + }, + { + type: 'object', + description: + '(on 2fa session) When user requests challenge of 2fa, this is how server provides challenge or request user to reply with challenge', + properties: { + to: { type: 'string', nullable: true }, + type: { + type: 'string', + enum: [ + Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH, + Meiling.V1.Interfaces.SigninType.PASSWORDLESS, + ], + }, + challenge: { $ref: 'Any#' }, + }, + }, + ], + }, + '4xx': { + $ref: 'MeilingV1Error#', + }, + '5xx': { + $ref: 'MeilingV1Error#', + }, + }, + }, + }, + signinHandler, + ); + app.register(signupPlugin, { prefix: '/signup' }); app.post('/lost-password', lostPasswordHandler); diff --git a/src/routes/v1/meiling/session.ts b/src/routes/v1/meiling/session.ts index 997ce3f3..85db5368 100644 --- a/src/routes/v1/meiling/session.ts +++ b/src/routes/v1/meiling/session.ts @@ -3,45 +3,78 @@ import { Meiling } from '../../../common'; import { BaridegiLogType, sendBaridegiLog } from '../../../common/event/baridegi'; export function sessionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { - app.get('/', async (req, rep) => { - let token = Meiling.V1.Session.getTokenFromRequest(req); + app.get( + '/', + { + schema: { + description: 'Issue a new Session token or Verify Session token for meiliNG V1 Endpoints', + tags: ['meiling'], + summary: 'Issue a new Session', + security: [{}, { sessionV1: [] }], + params: {}, + response: { + 200: { + description: 'Token is Valid', + type: 'object', + properties: { + success: { type: 'boolean' }, + }, + }, + 201: { + description: 'Issued Token', + type: 'object', + properties: { + success: { type: 'boolean' }, + token: { type: 'string' }, + }, + }, + 400: { + description: 'Provided Token is invalid', + $ref: 'MeilingV1Error#', + }, + 500: { + description: 'Server error occurred during issuing token', + $ref: 'MeilingV1Error#', + }, + }, + }, + }, + async (req, rep) => { + let token = Meiling.V1.Session.getTokenFromRequest(req); - if (token) { - const [isToken, isValid] = await Promise.all([ - Meiling.V1.Session.isToken(token), - Meiling.V1.Session.isValid(token), - ]); - if (isToken && isValid) { - rep.send({ - success: true, - }); - return; + if (token && token.trim() !== '') { + const [isToken, isValid] = await Promise.all([ + Meiling.V1.Session.isToken(token), + Meiling.V1.Session.isValid(token), + ]); + if (isToken && isValid) { + return rep.status(200).send({ + success: true, + }); + } else { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_TOKEN, 'Your token is expired'); + } } else { - rep.send({ - success: false, + token = await Meiling.V1.Session.createToken(req); + sendBaridegiLog(BaridegiLogType.NEW_SESSION, { + ip: req.ip, + token: token, }); - return; - } - } else { - token = await Meiling.V1.Session.createToken(req); - sendBaridegiLog(BaridegiLogType.NEW_SESSION, { - ip: req.ip, - token: token, - }); - if (token) { - rep.send({ - success: true, - token, - }); - } else { - rep.send({ - success: false, - }); + if (token) { + return rep.status(201).send({ + success: true, + token, + }); + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR, + 'Failed to issue a token', + ); + } } - return; - } - }); + }, + ); done(); } diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index 8948168b..de3d2e49 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -14,7 +14,6 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro body = Utils.convertJsonIfNot(req.body); } catch (e) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is not a valid JSON.'); - return; } let userToLogin: UserModel; @@ -23,7 +22,6 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro if (username === undefined) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'body is missing username.'); - return; } const users = await Meiling.Identity.User.findByCommonUsername(username); From f8eef0444b5ceaf94017e34c007e15e95241a9ab Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Tue, 15 Feb 2022 15:56:07 +0000 Subject: [PATCH 05/95] chore: sanitizing via swagger --- src/common/meiling/v1/error/error.ts | 10 ++----- src/common/utils.ts | 8 ++++-- src/routes/v1/meiling/index.ts | 2 +- src/routes/v1/meiling/signup/index.ts | 40 ++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/common/meiling/v1/error/error.ts b/src/common/meiling/v1/error/error.ts index 5cbc2f59..1c3fe7c3 100644 --- a/src/common/meiling/v1/error/error.ts +++ b/src/common/meiling/v1/error/error.ts @@ -86,17 +86,13 @@ export class MeilingError extends Error { public type: ErrorType; public description?: string; - public details?: any; - public debug?: any; - constructor(type: ErrorType, description?: string, details?: any, debug?: any) { + constructor(type: ErrorType, description?: string) { super(description); this.type = type; this.name = 'meiliNG Error'; this.message = description ? description : type; this.description = description; - this.details = details; - this.debug = debug; } public toString() { @@ -104,7 +100,7 @@ export class MeilingError extends Error { } public static load(error: MeilingError) { - const mlError = new MeilingError(error.type, error.description, error.details, error.debug); + const mlError = new MeilingError(error.type, error.description); console.log(mlError); return mlError; @@ -121,13 +117,11 @@ export class MeilingError extends Error { let base: ErrorResponse = { type: this.type, description: this.description, - details: this.details, }; if (config.node.environment === NodeEnvironment.Development) { base = { ...base, - debug: this.debug, stack: this.stack, }; } diff --git a/src/common/utils.ts b/src/common/utils.ts index e6511bcc..0c33584d 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -95,12 +95,16 @@ export interface MeilingV1SignupName { middleName?: string; } +export const usernameRegex = /^[A-Za-z0-9-_\.]+$/g; +export const minPasswordLength = 8; + export function isValidUsername(username: string): boolean { - return /^[A-Za-z0-9-_\.]+$/g.test(username); + usernameRegex.lastIndex = 0; + return usernameRegex.test(username); } export function isValidPassword(password: string): boolean { - return password.length >= 8; + return password.length >= minPasswordLength; } export function isValidEmail(email: string): boolean { diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index d40e9b37..10c83b29 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -20,6 +20,7 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: app.addSchema({ $id: 'MeilingV1Error', type: 'object', + required: ['type'], properties: { type: { type: 'string', enum: Object.values(Meiling.V1.Error.ErrorType) }, description: { type: 'string' }, @@ -40,7 +41,6 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: if (_err.validation) { // if it is validation issue, the error type is INVALID_REQUEST const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); - console.error(_err); error.loadError(_err); return error.sendFastify(rep); diff --git a/src/routes/v1/meiling/signup/index.ts b/src/routes/v1/meiling/signup/index.ts index 32ce1127..84924068 100644 --- a/src/routes/v1/meiling/signup/index.ts +++ b/src/routes/v1/meiling/signup/index.ts @@ -1,5 +1,6 @@ import { FastifyInstance, FastifyPluginOptions } from 'fastify'; import { Meiling } from '../../../../common'; +import { Utils } from '../../../../common/'; import config from '../../../../resources/config'; import { signupHandler } from './signup'; @@ -13,7 +14,44 @@ export function signupPlugin(app: FastifyInstance, opts: FastifyPluginOptions, d next(); }); - app.post('/', signupHandler); + app.post( + '/', + { + schema: { + description: 'Endpoint to sign-up an account', + tags: ['meiling'], + summary: 'Signup', + security: [{ sessionV1: [] }], + params: {}, + body: { + type: 'object', + properties: { + username: { type: 'string', pattern: Utils.usernameRegex.source }, + email: { type: 'string', format: 'email' }, + phone: { type: 'string' }, + password: { type: 'string', minLength: Utils.minPasswordLength }, + name: { + type: 'object', + properties: { + name: { type: 'string', minLength: 1 }, + familyName: { type: 'string', minLength: 1 }, + middleName: { type: 'string', nullable: true }, + givenName: { type: 'string', minLength: 1 }, + }, + required: ['name', 'familyName', 'givenName'], + }, + }, + required: ['username', 'email', 'phone', 'password', 'name'], + }, + response: { + 200: { + type: 'number', + }, + }, + }, + }, + signupHandler, + ); done(); } From 68fa41abbadc707c43ff181dab11228164d8bd82 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 17 Feb 2022 02:21:52 +0000 Subject: [PATCH 06/95] chore: remove duplicates --- src/routes/v1/meiling/index.ts | 56 +++++++++++++++++++++++++- src/routes/v1/meiling/signup/signup.ts | 43 +------------------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index 10c83b29..ed319bdc 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -19,6 +19,7 @@ export interface FastifyRequestWithSession extends FastifyRequest { function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.addSchema({ $id: 'MeilingV1Error', + description: 'Common error response of meiliNG', type: 'object', required: ['type'], properties: { @@ -208,7 +209,60 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, app.register(signupPlugin, { prefix: '/signup' }); - app.post('/lost-password', lostPasswordHandler); + app.post( + '/lost-password', + { + schema: { + summary: 'Password Recovery (Lost Password)', + description: 'Provides Password recovery flow', + tags: ['meiling'], + security: [{ sessionV1: [] }], + params: {}, + body: { + oneOf: [ + { + type: 'object', + properties: { + password: { type: 'string' }, + }, + required: ['password'], + }, + { + type: 'object', + properties: { + context: { + type: 'object', + properties: { + username: { type: 'string' }, + }, + required: ['username'], + }, + method: { + type: 'string', + enum: Object.values(Meiling.V1.Interfaces.ExtendedAuthMethods), + nullable: true, + }, + data: { + type: 'object', + }, + }, + required: ['context'], + }, + {}, + ], + }, + response: { + '4xx': { + $ref: 'MeilingV1Error#', + }, + '5xx': { + $ref: 'MeilingV1Error#', + }, + }, + }, + }, + lostPasswordHandler, + ); app.register(signoutPlugin, { prefix: '/signout' }); diff --git a/src/routes/v1/meiling/signup/signup.ts b/src/routes/v1/meiling/signup/signup.ts index 61657cb3..249715f7 100644 --- a/src/routes/v1/meiling/signup/signup.ts +++ b/src/routes/v1/meiling/signup/signup.ts @@ -18,21 +18,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro const session = (req as FastifyRequestWithSession).session; const body = req.body as MeilingV1Signup; - if (!Utils.isValidValue(body.username, body.email, body.phone, body.password)) { - // you are out. - throw new Meiling.V1.Error.MeilingError( - Meiling.V1.Error.ErrorType.INVALID_REQUEST, - `Invalid body (${['username', 'email', 'phone', 'password'].filter((n: string) => { - return Utils.isValidValue(body[n as keyof MeilingV1Signup]); - })})`, - ); - return; - } - - if (!Utils.isValidName(body.name)) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'Invalid Name'); - return; - } + // Validation no longer required const signupChallenge = await Meiling.V1.Session.getAuthenticationStatus(req); @@ -51,24 +37,7 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro const phone = libmobilephoneJs(body.phone); const username = body.username; - // check user input is valid. - - if (!Utils.isValidUsername(username)) { - throw new Meiling.V1.Error.MeilingError( - Meiling.V1.Error.ErrorType.INVALID_REQUEST, - 'Username should be consisting alphanumeric characters and _, -, .', - ); - return; - } - - if (!Utils.isValidPassword(password)) { - throw new Meiling.V1.Error.MeilingError( - Meiling.V1.Error.ErrorType.INVALID_REQUEST, - 'password should contain at least 8 characters.', - ); - return; - } - + // check if phone input properly parsed. if (!phone) { throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, @@ -77,14 +46,6 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro return; } - if (!Utils.isValidEmail(email)) { - throw new Meiling.V1.Error.MeilingError( - Meiling.V1.Error.ErrorType.INVALID_REQUEST, - 'Entered email is NOT a valid email.', - ); - return; - } - // check with validation. if (!(signupChallenge.email?.isVerified && signupChallenge.phone?.isVerified)) { From 041ea354a76c8a1ae145575eb185c1af8e513864 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 17 Feb 2022 02:42:37 +0000 Subject: [PATCH 07/95] chore: `userDelete` --- prisma/schema.prisma | 4 +- src/common/meiling/identity/user.ts | 16 ++++++- src/routes/v1/meiling/users/actions/index.ts | 2 + .../v1/meiling/users/actions/info/delete.ts | 46 +++++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/routes/v1/meiling/users/actions/info/delete.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9d6b8f0d..889e5023 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -44,12 +44,12 @@ model User { lockedProps Json? createdAt DateTime @default(now()) + deletedAt DateTime? + lastSignIn DateTime @default(now()) lastAuthenticated DateTime @default(now()) ownedClientSecrets OAuthClientSecrets[] - isDeleted Boolean @default(false) - metadata Json? } diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 535b1361..46d0ddec 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -80,8 +80,22 @@ export async function getBasicInfo( user: UserModel | string, queryOptions?: UserQueryOptions, ): Promise { + const deletedQuery = queryOptions?.includeDeleted + ? {} + : { + OR: [ + { + deletedAt: null, + }, + { + deletedAt: { + gte: new Date(), + }, + }, + ], + }; const prismaQuery = { - isDeleted: queryOptions?.includeDeleted ? undefined : false, + ...deletedQuery, }; const userDatabase = await getPrismaClient().user.findFirst({ diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index 8630d5c3..83bef9b0 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -2,6 +2,7 @@ import { FastifyInstance, FastifyPluginOptions, FastifyRequest } from 'fastify'; import { Meiling } from '../../../../../common'; import { userAppPlugin } from './apps'; import { clientAuthPlugin } from './auth'; +import { userDelete } from './info/delete'; import { userGetInfo } from './info/get'; import { userUpdateInfo } from './info/put'; import userSecurityPlugin from './security'; @@ -24,6 +25,7 @@ export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOpti app.get('/', userGetInfo); app.put('/', userUpdateInfo); + app.delete('/', userDelete); // TODO: Remove this later. // legacy compatibility reasons. will be deprecated in future. diff --git a/src/routes/v1/meiling/users/actions/info/delete.ts b/src/routes/v1/meiling/users/actions/info/delete.ts new file mode 100644 index 00000000..dd9b0048 --- /dev/null +++ b/src/routes/v1/meiling/users/actions/info/delete.ts @@ -0,0 +1,46 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { FastifyRequestWithSession } from '../../..'; +import { Meiling } from '../../../../../../common'; +import { getSanitizedUser } from '../../../../../../common/meiling/sanitize'; +import { getPrismaClient } from '../../../../../../resources/prisma'; + +export async function userDelete(req: FastifyRequest, rep: FastifyReply) { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + + if (userRawSession && userRawSession.length > 0) { + if (userId && userId !== '') { + const users = userRawSession.filter((n) => n.id === userId); + + if (users.length === 1) { + const user = await getSanitizedUser(users[0].id); + + await getPrismaClient().user.update({ + where: { + id: user?.id, + }, + data: { + deletedAt: new Date(), + }, + }); + + rep.send({ success: true }); + return; + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user was not available.', + ); + } + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'required field (user uuid) is missing', + ); + } + } else { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'You are not logged in.'); + } +} From 698f8441da3eab6a6c8e99afca57b3092dc652b5 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 17 Feb 2022 03:08:43 +0000 Subject: [PATCH 08/95] chore: yeah --- src/routes/v1/admin/users/index.ts | 48 +++++++++++++++++++ .../v1/meiling/users/actions/info/delete.ts | 22 ++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index c77bfd90..9cce5aff 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -211,6 +211,54 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done rep.send({ success: true }); }); + app.delete('/', async (req, rep) => { + const uuid = (req.params as { uuid: string }).uuid; + const user = await getPrismaClient().user.findUnique({ + where: { + id: uuid, + }, + }); + + if (user) { + await getPrismaClient().user.update({ + where: { + id: uuid, + }, + data: { + deletedAt: new Date(), + }, + }); + + const userLoggedInJson = { id: user?.id }; + const userSessions = await getPrismaClient().meilingSessionV1Token.findMany({ + where: { + session: { + path: '$.user', + array_contains: userLoggedInJson, + }, + }, + }); + + await Promise.all( + userSessions.map(async (n) => { + await getPrismaClient().meilingSessionV1Token.delete({ + where: { + token: n.token, + }, + }); + }), + ); + + rep.send({ success: true }); + return; + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user was not available.', + ); + } + }); + app.register(userEmailsAdminHandler, { prefix: '/emails' }); app.register(userPhonesAdminHandler, { prefix: '/phones' }); app.register(userSessionsAdminHandler, { prefix: '/sessions' }); diff --git a/src/routes/v1/meiling/users/actions/info/delete.ts b/src/routes/v1/meiling/users/actions/info/delete.ts index dd9b0048..439a892c 100644 --- a/src/routes/v1/meiling/users/actions/info/delete.ts +++ b/src/routes/v1/meiling/users/actions/info/delete.ts @@ -14,7 +14,7 @@ export async function userDelete(req: FastifyRequest, rep: FastifyReply) { if (userId && userId !== '') { const users = userRawSession.filter((n) => n.id === userId); - if (users.length === 1) { + if (users.length >= 1) { const user = await getSanitizedUser(users[0].id); await getPrismaClient().user.update({ @@ -26,6 +26,26 @@ export async function userDelete(req: FastifyRequest, rep: FastifyReply) { }, }); + const userLoggedInJson = { id: user?.id }; + const userSessions = await getPrismaClient().meilingSessionV1Token.findMany({ + where: { + session: { + path: '$.user', + array_contains: userLoggedInJson, + }, + }, + }); + + await Promise.all( + userSessions.map(async (n) => { + await getPrismaClient().meilingSessionV1Token.delete({ + where: { + token: n.token, + }, + }); + }), + ); + rep.send({ success: true }); return; } else { From ec26331aadca496a044e5160b54e4e86cbcd7808 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 17 Feb 2022 03:43:58 +0000 Subject: [PATCH 09/95] chore: target commonjs --- .swcrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.swcrc b/.swcrc index ff29857d..a7d87f33 100644 --- a/.swcrc +++ b/.swcrc @@ -14,7 +14,7 @@ "loose": true }, "module": { - "type": "es6", + "type": "commonjs", "strict": false, "strictMode": true, "lazy": true, From 5e084118c08c3b49e3c9bf6d58f0ea4f146d42a2 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 17 Feb 2022 04:08:48 +0000 Subject: [PATCH 10/95] chore: just remove user from session --- src/routes/v1/admin/users/index.ts | 8 +++++++- src/routes/v1/meiling/users/actions/info/delete.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index 9cce5aff..283dff2d 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -241,10 +241,16 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done await Promise.all( userSessions.map(async (n) => { - await getPrismaClient().meilingSessionV1Token.delete({ + await getPrismaClient().meilingSessionV1Token.update({ where: { token: n.token, }, + data: { + session: { + ...(n.session as any), + user: (n.session as any).user.filter((o: { id: string }) => o.id !== user?.id), + }, + }, }); }), ); diff --git a/src/routes/v1/meiling/users/actions/info/delete.ts b/src/routes/v1/meiling/users/actions/info/delete.ts index 439a892c..08cac9d2 100644 --- a/src/routes/v1/meiling/users/actions/info/delete.ts +++ b/src/routes/v1/meiling/users/actions/info/delete.ts @@ -38,10 +38,16 @@ export async function userDelete(req: FastifyRequest, rep: FastifyReply) { await Promise.all( userSessions.map(async (n) => { - await getPrismaClient().meilingSessionV1Token.delete({ + await getPrismaClient().meilingSessionV1Token.update({ where: { token: n.token, }, + data: { + session: { + ...(n.session as any), + user: (n.session as any).user.filter((o: { id: string }) => o.id !== user?.id), + }, + }, }); }), ); From d168b9037747932548d1fe22808de19115ad9900 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 10:25:14 +0000 Subject: [PATCH 11/95] chore(deps): bump minimist from 1.2.5 to 1.2.6 Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d61bc75b..144d022c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2089,9 +2089,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mri@1.1.4: version "1.1.4" From 03e2b4838a158e0dec68ef466a612436ef812586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Thu, 31 Mar 2022 19:40:18 +0900 Subject: [PATCH 12/95] chore: implement `/v1/admin/session/count` --- src/routes/v1/admin/sessions/index.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/routes/v1/admin/sessions/index.ts b/src/routes/v1/admin/sessions/index.ts index eb47c42e..f9ea38b7 100644 --- a/src/routes/v1/admin/sessions/index.ts +++ b/src/routes/v1/admin/sessions/index.ts @@ -29,9 +29,9 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, } = pageSize && page ? { - skip: (Number(pageSize) * (Number(page) - 1)) as number, - take: Number(pageSize) as number, - } + skip: (Number(pageSize) * (Number(page) - 1)) as number, + take: Number(pageSize) as number, + } : {}; let prismaQuery = undefined; @@ -52,6 +52,27 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, rep.send(sessions); }); + app.get('/count', async (req, rep) => { + const { query } = (req.query as any) || {}; + let prismaQuery = undefined; + + if (query !== undefined) { + try { + prismaQuery = JSON.parse(query); + } catch (e) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid prisma query'); + } + } + + const count = await getPrismaClient().meilingSessionV1Token.count({ + where: prismaQuery, + }); + + rep.send({ + count, + }); + }); + app.register(sessionAdminHandler); done(); From 3a42deac0f06d0457d695c611ced9a7007751449 Mon Sep 17 00:00:00 2001 From: Stella-IT-Bot Date: Thu, 31 Mar 2022 19:49:40 +0900 Subject: [PATCH 13/95] fix: fix linting errors --- src/routes/v1/admin/sessions/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/v1/admin/sessions/index.ts b/src/routes/v1/admin/sessions/index.ts index f9ea38b7..1c91c438 100644 --- a/src/routes/v1/admin/sessions/index.ts +++ b/src/routes/v1/admin/sessions/index.ts @@ -29,9 +29,9 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, } = pageSize && page ? { - skip: (Number(pageSize) * (Number(page) - 1)) as number, - take: Number(pageSize) as number, - } + skip: (Number(pageSize) * (Number(page) - 1)) as number, + take: Number(pageSize) as number, + } : {}; let prismaQuery = undefined; From 2a29ac75fb27e1de0a95096905985bec81f7ca9a Mon Sep 17 00:00:00 2001 From: Stella-IT-Bot Date: Thu, 31 Mar 2022 19:52:25 +0900 Subject: [PATCH 14/95] chore: update dependencies --- yarn.lock | 437 +++++++++++++++++++++++++++--------------------------- 1 file changed, 219 insertions(+), 218 deletions(-) diff --git a/yarn.lock b/yarn.lock index 94db829d..3085e1f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,21 +93,21 @@ fastq "^1.6.0" "@prisma/client@^3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.9.2.tgz#ad17dcfb702842573fe6ec3b7dc4615eff8d8fc6" - integrity sha512-VlEIYVMyfFZHbVBOlunPl47gmP/Z0zzPjPj8I7uKEIaABqrUy50ru3XS0aZd8GFvevVwt7p91xxkUjNjrWhKAQ== + version "3.11.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.11.1.tgz#bde6dec71ae133d04ce1c6658e3d76627a3c6dc7" + integrity sha512-B3C7zQG4HbjJzUr2Zg9UVkBJutbqq9/uqkl1S138+keZCubJrwizx3RuIvGwI+s+pm3qbsyNqXiZgL3Ir0fSng== dependencies: - "@prisma/engines-version" "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009" + "@prisma/engines-version" "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" -"@prisma/engines-version@3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009": - version "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009.tgz#ea03ffa723382a526dc6625ce6eae9b6ad984400" - integrity sha512-5Dh+qTDhpPR66w6NNAnPs+/W/Qt4r1DSd+qhfPFcDThUK4uxoZKGlPb2IYQn5LL+18aIGnmteDf7BnVMmvBNSQ== +"@prisma/engines-version@3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9": + version "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz#81a1835b495ad287ad7824dbd62f74e9eee90fb9" + integrity sha512-HkcsDniA4iNb/gi0iuyOJNAM7nD/LwQ0uJm15v360O5dee3TM4lWdSQiTYBMK6FF68ACUItmzSur7oYuUZ2zkQ== -"@prisma/engines@3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009": - version "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009.tgz#e5c345cdedb7be83d11c1e0c5ab61d866b411256" - integrity sha512-qM+uJbkelB21bnK44gYE049YTHIjHysOuj0mj5U2gDGyNLfmiazlggzFPCgEjgme4U5YB2tYs6Z5Hq08Kl8pjA== +"@prisma/engines@3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9": + version "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz#09ac23f8f615a8586d8d44538060ada199fe872c" + integrity sha512-MILbsGnvmnhCbFGa2/iSnsyGyazU3afzD7ldjCIeLIGKkNBMSZgA2IvpYsAXl+6qFHKGrS3B2otKfV31dwMSQw== "@sindresorhus/is@^0.14.0": version "0.14.0" @@ -115,98 +115,98 @@ integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== "@swc/cli@^0.1.51": - version "0.1.55" - resolved "https://registry.yarnpkg.com/@swc/cli/-/cli-0.1.55.tgz#6c00b836ae56f35b4a5243f7fad5f9674470b016" - integrity sha512-akkLuRexFq8XTi6JNZ27mXD4wcKXLDSLj4g7YMU+/upFM8IeD1IEp1Mxtre7MzCZn+QOQgPF8N8IReJoHuSn3g== + version "0.1.57" + resolved "https://registry.yarnpkg.com/@swc/cli/-/cli-0.1.57.tgz#a9c424de5a217ec20a4b7c2c0e5c343980537e83" + integrity sha512-HxM8TqYHhAg+zp7+RdTU69bnkl4MWdt1ygyp6BDIPjTiaJVH6Dizn2ezbgDS8mnFZI1FyhKvxU/bbaUs8XhzQg== dependencies: commander "^7.1.0" fast-glob "^3.2.5" slash "3.0.0" source-map "^0.7.3" -"@swc/core-android-arm-eabi@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.138.tgz#4605fa4afc0bb515798a7b7ebd274eb06f67775b" - integrity sha512-N79aTHj/jZNa8nXjOrfAaYYBkJxCQ9ZVFikQKSbBETU8usk7qAWDdCs94Y0q/Sow+9uiqguRVOrPFKSrN8LMTg== - -"@swc/core-android-arm64@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.138.tgz#7bb94a78d7253ca8b6ec92be435c5a7686dbd68c" - integrity sha512-ZNRqTjZpNrB39pCX5OmtnNTnzU3X1GjZX2xDouS1jknEE+TPz1ZJsM4zNlz6AObd7caJhU7qRyWNDM0nlcnJZQ== - -"@swc/core-darwin-arm64@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.138.tgz#8a31dbdb90626f503a837ee71fa3bb7866ac3eb1" - integrity sha512-DlT0s3Iw3bmOCk4jln0Q9AC1H7q75bZojyODcPXQ2T24s6LcBeD1lNAfyQ2RmaQJTlBM04LjNYqvjA2HAR4ckw== - -"@swc/core-darwin-x64@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.138.tgz#cc389708336dabc411a6d4705c2be17f9407054b" - integrity sha512-+8ahwSnUTPCmpB1VkMTJdfcFU+ZGQ5JnA1dpSvDhB/u8wV2Dpk0ozpX+3xjqYXoUdhZvdHW1FxKZrhMhscJriA== - -"@swc/core-freebsd-x64@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.138.tgz#2f29b1e8f133825fefb558a071f3bdb67dcf3c32" - integrity sha512-4icXrpDBN2r24PIRF2DBZ9IPgnXnEqO7/bySIUoL7ul8su2yoRP4Xp3Xi+XP+uBvtrVttwYtzGPNikVggVSK1Q== - -"@swc/core-linux-arm-gnueabihf@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.138.tgz#255c2011d865ff8f8118753f8900b51545c30000" - integrity sha512-YdEKUvT9GGBEsKSyXc/YJ0cWSetBV3JhxouYLCv4AoQsTrDU5vDQDFUWlT21pzlbwC66ffbpYxnugpsqBm5XKg== - -"@swc/core-linux-arm64-gnu@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.138.tgz#89813e14240bde17aaa914a47e84626a10ae13ec" - integrity sha512-cn/YrVvghCgSpagzHins1BQnJ07J53aCvlp57iXDA2xfH/HwXTijIy+UzqpQaLeKKQ8gMXmfzj/M7WklccN8jw== - -"@swc/core-linux-arm64-musl@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.138.tgz#c33351846218a4bd471505c9215233608f648ab9" - integrity sha512-aYoeZ46gaewTYYShHwlYhL8ARrLILiEnTWJFEWoUfAfbDwi4zaLyymRYmdpUyRHr+D9jloM5BKFNWnRPBTyCEg== - -"@swc/core-linux-x64-gnu@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.138.tgz#0be2226c7c701d8f58051ca47e78f24d479a9faa" - integrity sha512-gt9qP426kkIx4Yu2Dd9U2S44OE8ynRi47rt2HvdHaBlMsGfMH28EyMet3UT61ZVHMEoDxADQctz0JD1/29Ha1Q== - -"@swc/core-linux-x64-musl@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.138.tgz#07feede753206a4858dd275a0a4f99501909010e" - integrity sha512-lySbIVGApaDQVKPwH8D+9J5dkrawJTrBm86vY7F9sDPR5yCq5Buxx6Pn1X6VKE6e5vlEEb1zbVQmCrFgdUcgig== - -"@swc/core-win32-arm64-msvc@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.138.tgz#04e7dbfefb2e933433be32254c52c65add15c086" - integrity sha512-UmDtaC9ds1SNNfhYrHW1JvBhy7wKb/Y9RcQOsfG3StxqqnYkOWDkQt9dY5O9lAG8Iw/TCxzjJhm6ul48eMv9OQ== - -"@swc/core-win32-ia32-msvc@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.138.tgz#7d897c97ac5338e8a947d6c0c032e8068b521a2e" - integrity sha512-evapKq/jVKMI5KDXUvpu3rhYf/L0VIg92TTphpxJSNjo7k5w9n68RY3MXtm1BmtCR4ZWtx0OEXzr9ckUDcqZDA== - -"@swc/core-win32-x64-msvc@1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.138.tgz#6a54a72ed035d3b327f2576f4a586da093dc4898" - integrity sha512-wYrARtnPg/svsQd0oovbth2JAhOugAgbnaOS0CMiWB4vaFBx+1GHJl5wzdhh9jt1kzsu4xZ4237tUeMH+s6d0A== +"@swc/core-android-arm-eabi@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.161.tgz#3a723984a51705a6360fefc7c7efb5a7681c8f3f" + integrity sha512-SYm08FusdMo70JaKEYE7GpJHVp020iqPL3FjYEmQ+iyhc0Id8RlMeFt7ZtIj0aYHPKudR3GljzG5FVJXmm1Iuw== + +"@swc/core-android-arm64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.161.tgz#4d9e1b2d6a42ee767fda8ee7d46f059ab001ff0b" + integrity sha512-zk+GgVGKwIO9PsUcLZ7tG1XGGBJ/xyv5Or9/R0rQArBTGS5mvSK4d+9XrItQph8i3ECZhik3PuexmR7us6ysCw== + +"@swc/core-darwin-arm64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.161.tgz#bdef41c63d905a1da094c6756f09ca3ff19644d1" + integrity sha512-pf65TWy9oFkWCRzRq16Ec6rglurdajWT5tv1E93Kh4izEFLvKN/Mp+8EMnqOcoAn+HEtjzp2R6NosBruV/d1Ww== + +"@swc/core-darwin-x64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.161.tgz#96980fb8c3207f8305457864241c4a942b4d9903" + integrity sha512-QdgsY+BjYO0ngSIwR/xZn6W3iP0E/+of38Afon3maANDiKzvzsvyZm4IVTznOaxG1ZUJ/q1oKeRV/DcW7QvHiw== + +"@swc/core-freebsd-x64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.161.tgz#8b41d589a04c1236ab0d6163cca548574925cae4" + integrity sha512-yApHncnlQNQINxxcz+Y+svlrdU3d/yaJ769eoThIQXsZTL0Il3gnhhkjJkMEigLTexpQZQOGjgYnV9HKkpYqkw== + +"@swc/core-linux-arm-gnueabihf@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.161.tgz#4d475d57fdccaab900d88195e2b4e1b990e45e21" + integrity sha512-DGSKqKSBQ42mAMmPhWkfgzXaci4RU0XgmnO1bFVkl8Yw9TaxBBBeCbLIBYJik4DehOOYic9gtXZIfEs90+oc2w== + +"@swc/core-linux-arm64-gnu@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.161.tgz#e528dd661ed85f9069a5792536a2f784cab377f8" + integrity sha512-wdEPjBLuf0bUMafURrUN11MOGs7PHnedWOFAfvyRuNf4HdfwbS2nYDpFCL4mklN8BuprxvRFWfoA+ROigexK4g== + +"@swc/core-linux-arm64-musl@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.161.tgz#928dc578ba5cd8bb26decee62d150c565a09f1f5" + integrity sha512-EPwDDlAIchv1FG1Vc2ArUGsX2b87LSEXHjF59TuOj+oXOANHnFRQa/28wHpeMYN5lHYmyjMplfn37XYLMo8BDw== + +"@swc/core-linux-x64-gnu@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.161.tgz#c13866ef8a1eade5bf9b9b0f0be4b90d69970f10" + integrity sha512-UE+8n2PLCojxywQd1nPbMcus/3zLQjg05Oozrvl1IkHBssk89tk2GhLujUwbFS+MoGFPKAmL+wT+9lXHavK7Og== + +"@swc/core-linux-x64-musl@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.161.tgz#dd171b5357a5e34ece729e4aba528c15cfe4727b" + integrity sha512-mkshCdRhS5s1w1Koph/kS8EJVEmrq+/p4iLsLDozXi1RL16lzk5SYn4ppmzF/Zj9OpgJ+Nzk7kNcZMMJMVIwqw== + +"@swc/core-win32-arm64-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.161.tgz#e8e7cb5bac7319525ba297e4a2819dafc44f98d6" + integrity sha512-5ZMhPSeFJO+h0Ejoq766S25VvrooUW0RdhfcG2u7OFqhdlTXHlvryL7jdf6tILltmJxNWeAGrNE8YI+ARolTeQ== + +"@swc/core-win32-ia32-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.161.tgz#938e66e731f2d72b3dcf8af963c36a807f46286b" + integrity sha512-/c+L8bYCjg8pbx3Jbgx9Cns9nlLUpB4CmugfIdlW+2EdncyZyKu+u+D0egnOjvtlxe8BNw0889oH1Lv4p7KuhA== + +"@swc/core-win32-x64-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.161.tgz#f95a8ebe77fe35a1b9e87b52628b870a706b43be" + integrity sha512-FXzZXf+kXvqgZFd+dIzD8Pcc22yejm/XNvpGTy9HZHWYLvlif+QSXrNgvX1oyMWZYT+NCVHwebKjS9FTnTMi9w== "@swc/core@^1.2.138": - version "1.2.138" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.138.tgz#e54d8488094f7f90cb00455cb0380693c0935865" - integrity sha512-XMbpq6y2BiTju5KCtveM3h32Ma3chGm/fQEjErZmWNOcPIpupGLPosSU1bH35Udee4GHNJH3NfkZIDR0cjHWIg== + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.161.tgz#bbc79daeb33c1436df8eac58994dc0b73480a02f" + integrity sha512-RXv1y2HDqZ4gAjdvqV0KL1Oms8vUkDgXRU5SPOEa3zMzMDNKHvRfoiBk4ZyaGzhGcr0zflqT4EADKgTB8RFNsw== optionalDependencies: - "@swc/core-android-arm-eabi" "1.2.138" - "@swc/core-android-arm64" "1.2.138" - "@swc/core-darwin-arm64" "1.2.138" - "@swc/core-darwin-x64" "1.2.138" - "@swc/core-freebsd-x64" "1.2.138" - "@swc/core-linux-arm-gnueabihf" "1.2.138" - "@swc/core-linux-arm64-gnu" "1.2.138" - "@swc/core-linux-arm64-musl" "1.2.138" - "@swc/core-linux-x64-gnu" "1.2.138" - "@swc/core-linux-x64-musl" "1.2.138" - "@swc/core-win32-arm64-msvc" "1.2.138" - "@swc/core-win32-ia32-msvc" "1.2.138" - "@swc/core-win32-x64-msvc" "1.2.138" + "@swc/core-android-arm-eabi" "1.2.161" + "@swc/core-android-arm64" "1.2.161" + "@swc/core-darwin-arm64" "1.2.161" + "@swc/core-darwin-x64" "1.2.161" + "@swc/core-freebsd-x64" "1.2.161" + "@swc/core-linux-arm-gnueabihf" "1.2.161" + "@swc/core-linux-arm64-gnu" "1.2.161" + "@swc/core-linux-arm64-musl" "1.2.161" + "@swc/core-linux-x64-gnu" "1.2.161" + "@swc/core-linux-x64-musl" "1.2.161" + "@swc/core-win32-arm64-msvc" "1.2.161" + "@swc/core-win32-ia32-msvc" "1.2.161" + "@swc/core-win32-x64-msvc" "1.2.161" "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -233,9 +233,9 @@ integrity sha512-cskPTju7glYgzvkJy/hftqw7Fen3fsd0yrPOqcbBLJu+YdDQuA438akS1g+2XVKGzsQOnXGV2I9ePv6xUBnKMQ== "@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/jsonwebtoken@^8.5.0": version "8.5.8" @@ -245,14 +245,14 @@ "@types/node" "*" "@types/node@*": - version "17.0.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c" - integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw== + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/node@^14.14.7": - version "14.18.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.11.tgz#9bd810a959e1728d78df0f68b5c825b8ea7156f4" - integrity sha512-zCoCEMA+IPpsRkyCFBqew5vGb7r8RSiB3uwdu/map7uwLAfu1MTazW26/pUDWoNnF88vJz4W3U56i5gtXNqxGg== + version "14.18.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.12.tgz#0d4557fd3b94497d793efd4e7d92df2f83b4ef24" + integrity sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A== "@types/openpgp@^4.4.14": version "4.4.18" @@ -322,10 +322,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.11.0": - version "5.11.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.11.0.tgz#ba345818a2540fdf2755c804dc2158517ab61188" - integrity sha512-cxgBFGSRCoBEhvSVLkKw39+kMzUKHlJGVwwMbPcTZX3qEhuXhrjwaZXWMxVfxDgyMm+b5Q5b29Llo2yow8Y7xQ== +"@typescript-eslint/types@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f" + integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw== "@typescript-eslint/typescript-estree@4.33.0": version "4.33.0" @@ -341,12 +341,12 @@ tsutils "^3.21.0" "@typescript-eslint/typescript-estree@^5.11.0": - version "5.11.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.11.0.tgz#53f9e09b88368191e52020af77c312a4777ffa43" - integrity sha512-yVH9hKIv3ZN3lw8m/Jy5I4oXO4ZBMqijcXCdA4mY8ull6TPTAoQnKKrcZ0HDXg7Bsl0Unwwx7jcXMuNZc0m4lg== + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488" + integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg== dependencies: - "@typescript-eslint/types" "5.11.0" - "@typescript-eslint/visitor-keys" "5.11.0" + "@typescript-eslint/types" "5.17.0" + "@typescript-eslint/visitor-keys" "5.17.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -361,18 +361,18 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.11.0": - version "5.11.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.11.0.tgz#888542381f1a2ac745b06d110c83c0b261487ebb" - integrity sha512-E8w/vJReMGuloGxJDkpPlGwhxocxOpSVgSvjiLO5IxZPmxZF30weOeJYyPSEACwM+X4NziYS9q+WkN/2DHYQwA== +"@typescript-eslint/visitor-keys@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128" + integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA== dependencies: - "@typescript-eslint/types" "5.11.0" + "@typescript-eslint/types" "5.17.0" eslint-visitor-keys "^3.0.0" "@xmldom/xmldom@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.0.tgz#9f83fd9b3506c9603baad67e44eb6e6ee8eee0ce" - integrity sha512-7wVnF+rKrVDEo1xjzkkidTG0grclaVnX0vKa0z9JSXcEdtftUJjvU33jLGg6SHyvs3eeqEsI7jZ6NxYfRypEEg== + version "0.8.1" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.1.tgz#70c239275fc6d6a84e41b9a8d623a93c0d59b6b4" + integrity sha512-4wOae+5N2RZ+CZXd9ZKwkaDi55IxrSTOjHpxTvQQ4fomtOJmqVxbmICA9jE1jvnqNhpfgz8cnfFagG86wV/xLQ== abbrev@1: version "1.1.1" @@ -413,9 +413,9 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: uri-js "^4.2.2" ajv@^8.0.1, ajv@^8.1.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -538,9 +538,9 @@ atomic-sleep@^1.0.0: integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== avvio@^7.1.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.2.tgz#58e00e7968870026cd7b7d4f689d596db629e251" - integrity sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw== + version "7.2.5" + resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.5.tgz#65ba255f10b0bea7ac6eded71a5344cd88f5de19" + integrity sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA== dependencies: archy "^1.0.0" debug "^4.0.0" @@ -608,7 +608,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -647,6 +647,11 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= +buildcheck@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.3.tgz#70451897a95d80f7807e68fc412eb2e7e35ff4d5" + integrity sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA== + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -821,9 +826,9 @@ content-disposition@^0.5.3: safe-buffer "5.2.1" cookie-signature@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.1.0.tgz#cc94974f91fb9a9c1bb485e95fc2b7f4b120aff2" - integrity sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A== + version "1.2.0" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.0.tgz#4deed303f5f095e7a02c979e3fcb19157f5eaeea" + integrity sha512-R0BOPfLGTitaKhgKROKZQN6iyq2iDQcH1DOF8nJoaWapguX5bC2w+Q/I9NmmM5lfcvEarnLZr+cCvmEYYSXvYA== cookie@^0.4.0: version "0.4.2" @@ -841,12 +846,13 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cpu-features@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.2.tgz#9f636156f1155fd04bdbaa028bb3c2fbef3cea7a" - integrity sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA== +cpu-features@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.3.tgz#2acee87f762d11d5197babb34629293007a09edd" + integrity sha512-p6C/uud4F4bDyCz9+BNU22KdV1AGxPK6L9rQG9x3x4SSzdMPyBPErP7Rxn8avT2ex1M2g5Rpjz5Us/ri/766Qg== dependencies: - nan "^2.14.1" + buildcheck "0.0.3" + nan "^2.15.0" create-hash@^1.1.0, create-hash@^1.1.2: version "1.2.0" @@ -910,9 +916,9 @@ debug@^3.2.7: ms "^2.1.1" debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -1295,9 +1301,9 @@ fast-levenshtein@^2.0.6: integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-redact@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.0.tgz#37c26cda9cab70bc04393f7ba1feb2d176da6c6b" - integrity sha512-dir8LOnvialLxiXDPESMDHGp82CHi6ZEYTVkcvdn5d7psdv9ZkkButXrOeXST4aqreIRR+N7CYlsrwFuorurVg== + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.1.tgz#790fcff8f808c2e12fabbfb2be5cb2deda448fa0" + integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8: version "2.1.1" @@ -1305,12 +1311,12 @@ fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8: integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== fastify-cookie@^5.0.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/fastify-cookie/-/fastify-cookie-5.5.0.tgz#5898ef8197a3976874c30c04c21f103856ab251f" - integrity sha512-XhexnjmAR4CUh3Cz6Ko0is+pa8k1bS6+nkf/i3viv4p7R1fwGtGhAXuz+b4nEM0x7pvdi5ApKY73Bp5CELZP7g== + version "5.6.0" + resolved "https://registry.yarnpkg.com/fastify-cookie/-/fastify-cookie-5.6.0.tgz#90f098779438524e7ac6624c00ff5787b865d313" + integrity sha512-zmZhw1CugavEZjFToMDz6FTawXw9QQ6bJ1vhhalMLYTbhog8C42+1jIWENKjV6PkiERdDRhXahj9MiYSVNynDw== dependencies: cookie-signature "^1.1.0" - fastify-plugin "^3.0.0" + fastify-plugin "^3.0.1" fastify-cors@^5.1.0: version "5.2.0" @@ -1332,7 +1338,7 @@ fastify-formbody@^5.0.0: dependencies: fastify-plugin "^3.0.0" -fastify-plugin@^3.0.0: +fastify-plugin@^3.0.0, fastify-plugin@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.1.tgz#79e84c29f401020f38b524f59f2402103fd21ed2" integrity sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA== @@ -1347,9 +1353,9 @@ fastify-secure-session@^2.3.0: sodium-native "^3.0.0" fastify-static@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.5.0.tgz#0d3feff5373f5ed9c4e4cf31a2b84c2f70c35bb2" - integrity sha512-Q7Tgl55AjsmBwiO4hKYib2BUCt+XTWLJ6Xp8YPPHU3EsrKNpevJ4cz8pjf1Ey1QhHw9O8Y2FDKdu+IC74oHvqw== + version "4.6.1" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.6.1.tgz#687131da76f1d4391fb8b47f71ea2118cdc85803" + integrity sha512-vy7N28U4AMhuOim12ZZWHulEE6OQKtzZbHgiB8Zj4llUuUQXPka0WHAQI3njm1jTCx4W6fixUHfpITxweMtAIA== dependencies: content-disposition "^0.5.3" encoding-negotiator "^2.0.1" @@ -1360,9 +1366,9 @@ fastify-static@^4.0.0: send "^0.17.1" fastify-swagger@^4.15.0: - version "4.15.0" - resolved "https://registry.yarnpkg.com/fastify-swagger/-/fastify-swagger-4.15.0.tgz#993cb8fe6d818cb7d456f8a9290ad3de39f0228f" - integrity sha512-gFHc1FcvYLvhGhQvtb3KlxnF+CeM/0mIDJ6E12/kBTPJ1tYDeqIXwAdKZJ19abcReYEH6J3UAnLXDh7cmhT/IQ== + version "4.17.1" + resolved "https://registry.yarnpkg.com/fastify-swagger/-/fastify-swagger-4.17.1.tgz#bf256a53ed8974a17e25eaa3b98d14362b72c023" + integrity sha512-VUo8W7C+YIw/e+YbNTc15Nhl5xa9MpRMPFDKkRgwvgh0cn1mvGgT34sk77mlDclKwiEO471ayW+EFSL0OYXE1A== dependencies: fastify-plugin "^3.0.0" fastify-static "^4.0.0" @@ -1370,15 +1376,10 @@ fastify-swagger@^4.15.0: json-schema-resolver "^1.3.0" openapi-types "^10.0.0" -fastify-warning@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" - integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== - fastify@^3.27.1: - version "3.27.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.27.1.tgz#7e976473c15d7dc405ad624ffafb6612a6281d10" - integrity sha512-GLn3ow5BGqg/m+ztXvztp8Xp7SuH99vAm4zfbN7407Qzi4mB055SG/lWH/gYolz5Oq2K8LtUpZqt1Ccf/YkVmA== + version "3.27.4" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.27.4.tgz#67ffd61b5bea74768a7de28dbef5b6bc58f9e953" + integrity sha512-SOfnHBxG9zxCSIvt6aHoR/cao8QBddWmGP/mb5KQKRc+KI1kB7b79M2hCDOTSyHdLAF2OX+oI6X3weeLc+MqKg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" @@ -1394,7 +1395,7 @@ fastify@^3.27.1: rfdc "^1.1.4" secure-json-parse "^2.0.0" semver "^7.3.2" - tiny-lru "^7.0.0" + tiny-lru "^8.0.1" fastq@^1.6.0, fastq@^1.6.1: version "1.13.0" @@ -1466,9 +1467,9 @@ flatted@^3.1.0: integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== follow-redirects@^1.14.0: - version "1.14.8" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" - integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== forwarded@0.2.0: version "0.2.0" @@ -1553,9 +1554,9 @@ global-dirs@^3.0.0: ini "2.0.0" globals@^13.6.0, globals@^13.9.0: - version "13.12.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.1.tgz#ec206be932e6c77236677127577aa8e50bf1c5cb" - integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw== + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== dependencies: type-fest "^0.20.2" @@ -1978,18 +1979,18 @@ levn@^0.4.1: type-check "~0.4.0" libphonenumber-js@^1.9.49: - version "1.9.49" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.49.tgz#d431703cd699be2ccced5b95f26182a7c50a9227" - integrity sha512-/wEOIONcVboFky+lWlCaF7glm1FhBz11M5PHeCApA+xDdVfmhKjHktHS8KjyGxouV5CSXIr4f3GvLSpJa4qMSg== + version "1.9.50" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.50.tgz#f5028a2c4cc47a69d69a0de3629afad97a613712" + integrity sha512-cCzQPChw2XbordcO2LKiw5Htx5leHVfFk/EXkxNHqJfFo7Fndcb1kF5wPJpc316vCJhhikedYnVysMh3Sc7Ocw== light-my-request@^4.2.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.7.1.tgz#deb33c4485a08395760f16e5a7a044e6102bb4c4" - integrity sha512-7/bT6M+iHY90L9/rW7aboVYt0o0uOqzIx4yofC67d6WE9uLksecGf3mxPuZfVjMONG+i6hCq6z5NZCxqzpA2yw== + version "4.9.0" + resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.9.0.tgz#83559c7ce7e503466113e36f40a1d596a1886626" + integrity sha512-b1U3z4OVPoO/KanT14NRkXMr9rRtXAiq0ORqNrqhDyb5bGkZjAdEc6GRN1GWCfgaLBG+aq73qkCLDNeB3c2sLw== dependencies: ajv "^8.1.0" cookie "^0.4.0" - fastify-warning "^0.2.0" + process-warning "^1.0.0" set-cookie-parser "^2.4.1" lines-and-columns@^1.1.6: @@ -2164,12 +2165,12 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" mime@1.6.0: version "1.6.0" @@ -2197,9 +2198,9 @@ minimalistic-crypto-utils@^1.0.1: integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= minimatch@^3.0.4: - version "3.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" - integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" @@ -2249,7 +2250,7 @@ named-placeholders@^1.1.2: dependencies: lru-cache "^4.1.3" -nan@^2.14.1, nan@^2.15.0: +nan@^2.15.0: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== @@ -2279,9 +2280,9 @@ node-localstorage@~1.3.0: write-file-atomic "^1.1.4" node-ssh@^12.0.3: - version "12.0.3" - resolved "https://registry.yarnpkg.com/node-ssh/-/node-ssh-12.0.3.tgz#ea6635e5ccfb7b30806e6a0a1c518626ec76985f" - integrity sha512-+TrX99Fvu50ZwBu/1Z9oWV1xC+vjADCJACSmvdgYUeUH/PKIX6Y5ltPvrh30WFXcxaP1wHN09BBVdQ3jfZlfoA== + version "12.0.4" + resolved "https://registry.yarnpkg.com/node-ssh/-/node-ssh-12.0.4.tgz#92ac845c9bc9715f2fcf907ff7c9973ca51fd5c0" + integrity sha512-5M3FBeAWjEpAQvVakQde6CeviEoEiYb6IjJL9mrMen9at63GAv0Q5vOFHFP+SM1Y7pTN3EBvJ/I+oxn2Lpydbw== dependencies: is-stream "^2.0.0" make-dir "^3.1.0" @@ -2486,7 +2487,7 @@ pem2jwk@^1.0.2: parse-asn1 "^5.1.0" safe-buffer "^5.1.2" -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2515,9 +2516,9 @@ pino-std-serializers@^3.1.0: integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== pino@^6.13.0: - version "6.13.4" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.13.4.tgz#e7bd5e8292019609c841c37a3f1d73ee10bb80f7" - integrity sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA== + version "6.14.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78" + integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== dependencies: fast-redact "^3.0.0" fast-safe-stringify "^2.0.8" @@ -2559,16 +2560,16 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@^2.1.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + version "2.6.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" + integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== prisma@^3.9.2: - version "3.9.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.9.2.tgz#cc2da4e8db91231dea7465adf9db6e19f11032a9" - integrity sha512-i9eK6cexV74OgeWaH3+e6S07kvC9jEZTl6BqtBH398nlCU0tck7mE9dicY6YQd+euvMjjCtY89q4NgmaPnUsSg== + version "3.11.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.11.1.tgz#fff9c0bcf83cb30c2e1d650882d5eb3c5565e028" + integrity sha512-aYn8bQwt1xwR2oSsVNHT4PXU7EhsThIwmpNB/MNUaaMx5OPLTro6VdNJe/sJssXFLxhamfWeMjwmpXjljo6xkg== dependencies: - "@prisma/engines" "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009" + "@prisma/engines" "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" process-warning@^1.0.0: version "1.0.0" @@ -2749,9 +2750,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.1: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== dependencies: tslib "^2.1.0" @@ -2978,19 +2979,19 @@ sprintf-js@~1.0.2: integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sqlstring@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.2.tgz#cdae7169389a1375b18e885f2e60b3e460809514" - integrity sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" + integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== ssh2@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.6.0.tgz#61aebc3a6910fe488f9c85cd8355bdf8d4724e05" - integrity sha512-lxc+uvXqOxyQ99N2M7k5o4pkYDO5GptOTYduWw7hIM41icxvoBcCNHcj+LTKrjkL0vFcAl+qfZekthoSFRJn2Q== + version "1.8.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.8.0.tgz#97a9bfa3348412a2ed266265ddb351746b6edfc8" + integrity sha512-NVIRkIwJvWl+mcRozp+EBzHMVCcbDKBea64ToPdZEk43yAVGwmfqYZRPFRnnvGjsKC34wYCmiupTcKgCVNVNNg== dependencies: asn1 "^0.2.4" bcrypt-pbkdf "^1.0.2" optionalDependencies: - cpu-features "0.0.2" + cpu-features "0.0.3" nan "^2.15.0" "statuses@>= 1.5.0 < 2", statuses@~1.5.0: @@ -3090,10 +3091,10 @@ through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -tiny-lru@^7.0.0: - version "7.0.6" - resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" - integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== +tiny-lru@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-8.0.2.tgz#812fccbe6e622ded552e3ff8a4c3b5ff34a85e4c" + integrity sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg== to-readable-stream@^1.0.0: version "1.0.0" @@ -3183,9 +3184,9 @@ typedarray-to-buffer@^3.1.5: is-typedarray "^1.0.0" typescript@^4.5.5: - version "4.5.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" - integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== undefsafe@^2.0.5: version "2.0.5" @@ -3262,9 +3263,9 @@ whatwg-url@^5.0.0: webidl-conversions "^3.0.0" which-pm-runs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" - integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + version "1.1.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" + integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== which@^2.0.1: version "2.0.2" From 6abb3d10bef95c0666aaf359279e38202669859c Mon Sep 17 00:00:00 2001 From: Stella-IT-Bot Date: Thu, 31 Mar 2022 19:54:42 +0900 Subject: [PATCH 15/95] chore: bump up version to 0.9.0 snapshot --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index edc78178..b40271c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meiling", - "version": "0.8.4-snapshot", + "version": "0.9.0-snapshot", "description": "An Opensource Next Generation \"Gatekeeper\" with oAuth2 Authentication Provider and OpenID Connect Server", "main": "dist/", "repository": "https://github.com/meili-NG/meiliNG", From b852288d3fcda9aac793e942c8f2b42fa14994cd Mon Sep 17 00:00:00 2001 From: Stella-IT-Bot Date: Thu, 31 Mar 2022 19:55:27 +0900 Subject: [PATCH 16/95] chore: yes, I use emacs. So what --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f6247959..46cc2eca 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ config.js # use prisma db push prisma/migrations + +# Emacs Temp files +*~ From 638694e7ce1e5291a6a4cb0ce99ab316ea854115 Mon Sep 17 00:00:00 2001 From: Stella-IT-Bot Date: Thu, 31 Mar 2022 20:00:18 +0900 Subject: [PATCH 17/95] chore: new autodeploy code --- .github/workflows/deploy-s4ait-production.yml | 1 + ecosystem.config.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-s4ait-production.yml b/.github/workflows/deploy-s4ait-production.yml index 7f0b1e76..9c02d673 100644 --- a/.github/workflows/deploy-s4ait-production.yml +++ b/.github/workflows/deploy-s4ait-production.yml @@ -56,3 +56,4 @@ jobs: DEPLOY_PRODUCTION_KEY_PATH: ~/.ssh/id_rsa DEPLOY_PRODUCTION_BYPASS_KEY_CHECK: true DEPLOY_PRODUCTION_SUPPRESS_SSH_LOG: true + DEPLOY_PRODUCTION_REF: ${{ github.ref }} diff --git a/ecosystem.config.js b/ecosystem.config.js index b122c41f..fff34f35 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -32,7 +32,7 @@ module.exports = { production: { user: process.env.DEPLOY_PRODUCTION_USER, host: process.env.DEPLOY_PRODUCTION_HOST, - ref: 'origin/main', + ref: process.env.DEPLOY_PRODUCTION_REF || 'origin/main', repo: 'https://github.com/meili-ng/meiliNG', path: process.env.DEPLOY_PRODUCTION_PATH, 'pre-deploy-local': `node deploy-env.production.js`, From 712f9a6638e57e9acef8e241f3c64b775b2d5e73 Mon Sep 17 00:00:00 2001 From: Baw-Appie Date: Fri, 15 Apr 2022 15:16:49 +0900 Subject: [PATCH 18/95] [Lost-Password] Fix Bug --- .idea/misc.xml | 8 ++++++++ src/routes/v1/meiling/index.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .idea/misc.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..283b9b4d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index ed319bdc..f9634f3b 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -248,7 +248,7 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, }, required: ['context'], }, - {}, + // {}, ], }, response: { From 2520e97d6335ae20b06a5306b62a2ff75d36e584 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 16 Apr 2022 10:43:26 +0000 Subject: [PATCH 19/95] fix: JWT kid support --- src/common/meiling/identity/user.ts | 1 + src/routes/v1/oauth2/certs.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 46d0ddec..bfc33701 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -698,6 +698,7 @@ export async function createIDToken( return JWT.sign(jwtData, key, { algorithm, issuer: config.openid.issuingAuthority, + jwtid: config.openid.jwt.keyId, }); } else { return undefined; diff --git a/src/routes/v1/oauth2/certs.ts b/src/routes/v1/oauth2/certs.ts index d3793ff9..ae1c0b14 100644 --- a/src/routes/v1/oauth2/certs.ts +++ b/src/routes/v1/oauth2/certs.ts @@ -5,10 +5,17 @@ import config from '../../../resources/config'; const pem2jwk = require('pem2jwk'); const oAuth2CertsHandler = (req: FastifyRequest, rep: FastifyReply): void => { + let alg = config.openid.jwt.algorithm; + if ((alg as string) === 'ES256K') { + alg = 'ES256'; + } + rep.send({ keys: [ { + alg, kid: config.openid.jwt.keyId, + use: 'sig', ...pem2jwk(config.openid.jwt.publicKey), }, ], From 4f3dbd05f311ac14999b5b921be49ab4870a7c0f Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 11:58:13 +0000 Subject: [PATCH 20/95] fix: keyId --- src/common/meiling/identity/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index bfc33701..8b343291 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -698,7 +698,7 @@ export async function createIDToken( return JWT.sign(jwtData, key, { algorithm, issuer: config.openid.issuingAuthority, - jwtid: config.openid.jwt.keyId, + keyid: config.openid.jwt.keyId, }); } else { return undefined; From f2950a79f41108b0dd8cc868b1a6bdcde8629a3c Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 12:51:37 +0000 Subject: [PATCH 21/95] chore: add email by user --- .../v1/meiling/users/actions/emails/index.ts | 79 +++++++++++++++++++ src/routes/v1/meiling/users/actions/index.ts | 3 + src/routes/v1/meiling/users/index.ts | 2 +- .../users/{actions/info/list.ts => users.ts} | 4 +- 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/routes/v1/meiling/users/actions/emails/index.ts rename src/routes/v1/meiling/users/{actions/info/list.ts => users.ts} (88%) diff --git a/src/routes/v1/meiling/users/actions/emails/index.ts b/src/routes/v1/meiling/users/actions/emails/index.ts new file mode 100644 index 00000000..43bb4026 --- /dev/null +++ b/src/routes/v1/meiling/users/actions/emails/index.ts @@ -0,0 +1,79 @@ +import { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; +import { FastifyRequestWithSession } from '../../..'; +import { Meiling } from '../../../../../../common'; +import { getSanitizedUser } from '../../../../../../common/meiling/sanitize'; + +function userEmailsPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.get('/', getUserEmails); + app.post('/', addUserEmail); + done(); +} + +export default userEmailsPlugin; + +export async function getUserEmails(req: FastifyRequest, rep: FastifyReply) { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + + if (userRawSession && userRawSession.filter((n) => n.id === userId).length > 0) { + const emails = await Meiling.Identity.User.getEmails(userId); + + rep.send(emails); + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } +} + +export async function addUserEmail(req: FastifyRequest, rep: FastifyReply) { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + const signupChallenge = await Meiling.V1.Session.getAuthenticationStatus(req); + const body = req.body as any; + + const email = body.email as string; + + if (!email || typeof email !== 'string') + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'email is missing'); + + if (!signupChallenge) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, + 'Signup Validation requests were not generated.', + ); + return; + } + + // check with validation. + + if (!signupChallenge.email?.isVerified) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED); + return; + } else if (signupChallenge.email.to !== email) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID); + return; + } + + if (userRawSession && userRawSession.filter((n) => n.id === userId).length > 0) { + const emails = await Meiling.Identity.User.getEmails(userId); + const isTherePrimary = emails.filter((n) => n.isPrimary).length > 0; + + let isPrimary = false; + if (!isTherePrimary) isPrimary = true; + + await Meiling.Identity.User.addEmail(userId, email.trim(), isPrimary); + + rep.send(emails); + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } +} diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index 83bef9b0..e4b8fd69 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -2,6 +2,7 @@ import { FastifyInstance, FastifyPluginOptions, FastifyRequest } from 'fastify'; import { Meiling } from '../../../../../common'; import { userAppPlugin } from './apps'; import { clientAuthPlugin } from './auth'; +import userEmailsPlugin from './emails'; import { userDelete } from './info/delete'; import { userGetInfo } from './info/get'; import { userUpdateInfo } from './info/put'; @@ -33,6 +34,8 @@ export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOpti app.register(userPasswordsPlugin, { prefix: '/passwords' }); app.register(clientAuthPlugin, { prefix: '/auth' }); + + app.register(userEmailsPlugin, { prefix: '/emails' }); app.register(userAppPlugin, { prefix: '/apps' }); app.register(userSecurityPlugin, { prefix: '/security' }); diff --git a/src/routes/v1/meiling/users/index.ts b/src/routes/v1/meiling/users/index.ts index 547c037b..7ed7f993 100644 --- a/src/routes/v1/meiling/users/index.ts +++ b/src/routes/v1/meiling/users/index.ts @@ -1,6 +1,6 @@ import { FastifyInstance, FastifyPluginOptions } from 'fastify'; import { userActionsHandler } from './actions'; -import { userGetLoggedInUserInfo } from './actions/info/list'; +import { userGetLoggedInUserInfo } from './users'; export function userPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.get('/', userGetLoggedInUserInfo); diff --git a/src/routes/v1/meiling/users/actions/info/list.ts b/src/routes/v1/meiling/users/users.ts similarity index 88% rename from src/routes/v1/meiling/users/actions/info/list.ts rename to src/routes/v1/meiling/users/users.ts index ac85f9c7..6528d3c9 100644 --- a/src/routes/v1/meiling/users/actions/info/list.ts +++ b/src/routes/v1/meiling/users/users.ts @@ -1,6 +1,6 @@ import { FastifyReply, FastifyRequest } from 'fastify'; -import { FastifyRequestWithSession } from '../../..'; -import { Meiling } from '../../../../../../common'; +import { FastifyRequestWithSession } from '..'; +import { Meiling } from '../../../../common'; export async function userGetLoggedInUserInfo(req: FastifyRequest, rep: FastifyReply) { const session = (req as FastifyRequestWithSession).session; From 470c6fb97a8ba2a8b3361f0eafbe4463d5521b94 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 13:42:47 +0000 Subject: [PATCH 22/95] chore: add crud operation on email --- src/common/meiling/sanitize.ts | 5 ++ .../users/actions/emails/actions/index.ts | 51 +++++++++++++++++++ .../v1/meiling/users/actions/emails/index.ts | 6 ++- .../users/actions/security/webauthn/index.ts | 9 ++-- 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 src/routes/v1/meiling/users/actions/emails/actions/index.ts diff --git a/src/common/meiling/sanitize.ts b/src/common/meiling/sanitize.ts index 1ba4b476..a8c87e6b 100644 --- a/src/common/meiling/sanitize.ts +++ b/src/common/meiling/sanitize.ts @@ -1,3 +1,4 @@ +import { Email } from '@prisma/client'; import { User } from './identity'; import { Client } from './oauth2'; @@ -24,3 +25,7 @@ export async function getSanitizedUser(user: string): Promise void): void { + app.addHook('onRequest', async (req, rep) => { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + if (!userRawSession || userRawSession.filter((n) => n.id === userId).length == 0) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } + + const emailId = (req.params as any)?.emailId; + + if (!emailId) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'emailId is missing'); + + const emails = await Meiling.Identity.User.getEmails(userId); + const matchingEmail = emails.find((n) => n.id === emailId); + + if (!matchingEmail) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + } + + (req as any).email = matchingEmail; + }); + + app.get('/', async (req, rep) => { + const email = (req as any).email as Email; + + rep.send(Meiling.Sanitize.getSanitizedEmail(email)); + }); + + app.delete('/', async (req, rep) => { + const userId = (req.params as any)?.userId; + const email = (req as any).email as Email; + + await Meiling.Identity.User.removeEmail(userId, email.email); + rep.send({ success: true }); + }); + + done(); +} + +export default userEmailActionPlugin; diff --git a/src/routes/v1/meiling/users/actions/emails/index.ts b/src/routes/v1/meiling/users/actions/emails/index.ts index 43bb4026..f85c1f38 100644 --- a/src/routes/v1/meiling/users/actions/emails/index.ts +++ b/src/routes/v1/meiling/users/actions/emails/index.ts @@ -1,11 +1,13 @@ import { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; import { FastifyRequestWithSession } from '../../..'; import { Meiling } from '../../../../../../common'; -import { getSanitizedUser } from '../../../../../../common/meiling/sanitize'; +import userEmailActionPlugin from './actions'; function userEmailsPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.get('/', getUserEmails); app.post('/', addUserEmail); + app.register(userEmailActionPlugin, { prefix: '/:emailId' }); + done(); } @@ -20,7 +22,7 @@ export async function getUserEmails(req: FastifyRequest, rep: FastifyReply) { if (userRawSession && userRawSession.filter((n) => n.id === userId).length > 0) { const emails = await Meiling.Identity.User.getEmails(userId); - rep.send(emails); + rep.send(emails.map((n) => Meiling.Sanitize.getSanitizedEmail(n))); } else { throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.NOT_FOUND, diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts index 9d5666e3..8b5a42dd 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts @@ -3,6 +3,7 @@ import { getUserFromActionRequest } from '../..'; import { Meiling, Utils } from '../../../../../../../common'; import { getPrismaClient } from '../../../../../../../resources/prisma'; import userWebAuthnActionsPlugin from './actions'; +import crypto from 'crypto'; function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.get('/', async (req, rep) => { @@ -42,16 +43,16 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do return; } - if (Utils.isNotBlank(body.id, body.response, body.response?.attenationObject, body)) { + if (Utils.isNotBlank(body.id, body.hostname, body.response, body.response?.attenationObject, body)) { // TODO: Implement registration procedure } else { - const challenge = Meiling.Authentication.Token.generateToken(64); + const challenge = crypto.randomBytes(64); await Meiling.V1.Session.setSession(req, { ...session, registering: { webAuthn: { - challenge, + challenge: challenge.toString('base64'), }, }, }); @@ -63,7 +64,7 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do displayName: user.name, icon: user.profileUrl ? user.profileUrl : undefined, }, - challenge, + challenge: challenge.toString('base64'), }); } }); From 501aa1955086a50fbee6addbd6c7cdff3a87a802 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 13:54:52 +0000 Subject: [PATCH 23/95] chore: email/phones --- src/common/meiling/sanitize.ts | 6 +- .../v1/meiling/users/actions/emails/index.ts | 2 +- src/routes/v1/meiling/users/actions/index.ts | 3 + .../users/actions/phones/actions/index.ts | 51 +++++++++++ .../v1/meiling/users/actions/phones/index.ts | 88 +++++++++++++++++++ 5 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/routes/v1/meiling/users/actions/phones/actions/index.ts create mode 100644 src/routes/v1/meiling/users/actions/phones/index.ts diff --git a/src/common/meiling/sanitize.ts b/src/common/meiling/sanitize.ts index a8c87e6b..d0d704fd 100644 --- a/src/common/meiling/sanitize.ts +++ b/src/common/meiling/sanitize.ts @@ -1,4 +1,4 @@ -import { Email } from '@prisma/client'; +import { Email, Phone } from '@prisma/client'; import { User } from './identity'; import { Client } from './oauth2'; @@ -29,3 +29,7 @@ export async function getSanitizedUser(user: string): Promise void): void { + app.addHook('onRequest', async (req, rep) => { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + if (!userRawSession || userRawSession.filter((n) => n.id === userId).length == 0) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } + + const phoneId = (req.params as any)?.phoneId; + + if (!phoneId) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'phoneId is missing'); + + const phones = await Meiling.Identity.User.getPhones(userId); + const matchingPhone = phones.find((n) => n.id === phoneId); + + if (!matchingPhone) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + } + + (req as any).phone = matchingPhone; + }); + + app.get('/', async (req, rep) => { + const phone = (req as any).phone as Phone; + + rep.send(Meiling.Sanitize.getSanitizedPhone(phone)); + }); + + app.delete('/', async (req, rep) => { + const userId = (req.params as any)?.userId; + const phone = (req as any).phone as Phone; + + await Meiling.Identity.User.removePhone(userId, phone.phone); + rep.send({ success: true }); + }); + + done(); +} + +export default userPhoneActionPlugin; diff --git a/src/routes/v1/meiling/users/actions/phones/index.ts b/src/routes/v1/meiling/users/actions/phones/index.ts new file mode 100644 index 00000000..540ccc7b --- /dev/null +++ b/src/routes/v1/meiling/users/actions/phones/index.ts @@ -0,0 +1,88 @@ +import { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; +import { FastifyRequestWithSession } from '../../..'; +import { Meiling } from '../../../../../../common'; +import userPhoneActionPlugin from './actions'; +import libPhonenumberJs from 'libphonenumber-js'; + +function userPhonesPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.get('/', getUserPhones); + app.post('/', addUserPhone); + app.register(userPhoneActionPlugin, { prefix: '/:phoneId' }); + + done(); +} + +export default userPhonesPlugin; + +export async function getUserPhones(req: FastifyRequest, rep: FastifyReply) { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + + if (userRawSession && userRawSession.filter((n) => n.id === userId).length > 0) { + const phones = await Meiling.Identity.User.getPhones(userId); + + rep.send(phones.map((n) => Meiling.Sanitize.getSanitizedPhone(n))); + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } +} + +export async function addUserPhone(req: FastifyRequest, rep: FastifyReply) { + const session = (req as FastifyRequestWithSession).session; + const userRawSession = session.user; + + const userId = (req.params as any)?.userId; + const signupChallenge = await Meiling.V1.Session.getAuthenticationStatus(req); + const body = req.body as any; + + const phoneRaw = body.phone as string; + + if (!phoneRaw || typeof phoneRaw !== 'string') + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'phone is missing'); + + const phone = libPhonenumberJs(phoneRaw); + + if (!phone) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid ITU phone number'); + } + + if (!signupChallenge) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED, + 'Signup Validation requests were not generated.', + ); + return; + } + + // check with validation. + + if (!signupChallenge.phone?.isVerified) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED); + return; + } else if (signupChallenge.phone.to !== phone?.formatInternational()) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID); + return; + } + + if (userRawSession && userRawSession.filter((n) => n.id === userId).length > 0) { + const phones = await Meiling.Identity.User.getPhones(userId); + const isTherePrimary = phones.filter((n) => n.isPrimary).length > 0; + + let isPrimary = false; + if (!isTherePrimary) isPrimary = true; + + await Meiling.Identity.User.addPhone(userId, phone.formatInternational(), isPrimary); + + rep.send(phones); + } else { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'specified user uuid was not available.', + ); + } +} From 01377cf5c39424071a49a7dd7788fd512317448b Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 14:02:22 +0000 Subject: [PATCH 24/95] fix: refactored how isPrimary allocation is processed --- src/common/meiling/identity/user.ts | 96 ++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 8b343291..38515185 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -514,25 +514,45 @@ export async function addEmail(userId: string, email: string, isPrimary = false) }); if (isPrimary) { - const prevPrimariesPromise = []; - for (const prevPrimary of prevPrimaries) { - prevPrimariesPromise.push( - getPrismaClient().email.update({ - where: { - id: prevPrimary.id, - }, - data: { - isPrimary: false, - }, - }), - ); - } - await Promise.all(prevPrimariesPromise); + await setPrimaryEmail(userId, email); } return true; } +export async function setPrimaryEmail(userId: string, email: string) { + const emails = await getEmails(userId); + + const targetEmail = emails.find((n) => n.email === email); + const prevPrimaries = emails.filter((n) => n.isPrimary); + + if (!targetEmail) return false; + + await getPrismaClient().email.update({ + where: { + id: targetEmail.id, + }, + data: { + isPrimary: true, + }, + }); + + const prevPrimariesPromise = []; + for (const prevPrimary of prevPrimaries) { + prevPrimariesPromise.push( + getPrismaClient().email.update({ + where: { + id: prevPrimary.id, + }, + data: { + isPrimary: false, + }, + }), + ); + } + await Promise.all(prevPrimariesPromise); +} + export async function removeEmail(userId: string, email: string) { await getPrismaClient().email.deleteMany({ where: { @@ -581,25 +601,45 @@ export async function addPhone(userId: string, phone: string, isPrimary = false) }); if (isPrimary) { - const prevPrimariesPromise = []; - for (const prevPrimary of prevPrimaries) { - prevPrimariesPromise.push( - getPrismaClient().email.update({ - where: { - id: prevPrimary.id, - }, - data: { - isPrimary: false, - }, - }), - ); - } - await Promise.all(prevPrimariesPromise); + await setPrimaryPhone(userId, phone); } return true; } +export async function setPrimaryPhone(userId: string, phone: string) { + const phones = await getPhones(userId); + + const targetPhone = phones.find((n) => n.phone === phone); + const prevPrimaries = phones.filter((n) => n.isPrimary); + + if (!targetPhone) return false; + + await getPrismaClient().phone.update({ + where: { + id: targetPhone.id, + }, + data: { + isPrimary: true, + }, + }); + + const prevPrimariesPromise = []; + for (const prevPrimary of prevPrimaries) { + prevPrimariesPromise.push( + getPrismaClient().phone.update({ + where: { + id: prevPrimary.id, + }, + data: { + isPrimary: false, + }, + }), + ); + } + await Promise.all(prevPrimariesPromise); +} + export async function removePhone(userId: string, phone: string) { await getPrismaClient().phone.deleteMany({ where: { From 215782330f851fcab369e24a12ddb585354c96fd Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 18 Apr 2022 14:14:53 +0000 Subject: [PATCH 25/95] chore: minimum check --- .../users/actions/emails/actions/index.ts | 20 ++++++++++++++ .../users/actions/phones/actions/index.ts | 26 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/routes/v1/meiling/users/actions/emails/actions/index.ts b/src/routes/v1/meiling/users/actions/emails/actions/index.ts index f8ffe3dc..7f742ee2 100644 --- a/src/routes/v1/meiling/users/actions/emails/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/emails/actions/index.ts @@ -37,10 +37,30 @@ function userEmailActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, rep.send(Meiling.Sanitize.getSanitizedEmail(email)); }); + app.put('/', async (req, rep) => { + const email = (req as any).email as Email; + const userId = (req.params as any)?.userId; + + const body = req.body as { + isPrimary?: boolean; + }; + + if (body.isPrimary) { + await Meiling.Identity.User.setPrimaryEmail(userId, email.email); + } + + rep.send({ success: true }); + }); + app.delete('/', async (req, rep) => { const userId = (req.params as any)?.userId; const email = (req as any).email as Email; + const emails = await Meiling.Identity.User.getEmails(userId); + if (emails.length === 1) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.FORBIDDEN, 'at least one email is required'); + } + await Meiling.Identity.User.removeEmail(userId, email.email); rep.send({ success: true }); }); diff --git a/src/routes/v1/meiling/users/actions/phones/actions/index.ts b/src/routes/v1/meiling/users/actions/phones/actions/index.ts index fc46f041..ee3b2a79 100644 --- a/src/routes/v1/meiling/users/actions/phones/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/phones/actions/index.ts @@ -37,10 +37,36 @@ function userPhoneActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, rep.send(Meiling.Sanitize.getSanitizedPhone(phone)); }); + /* + + // Not implementing this at the moment. + // since this can seriously affect KRID (Stella IT Internal) + + app.put('/', async (req, rep) => { + const phone = (req as any).phone as Phone; + const userId = (req.params as any)?.userId; + + const body = req.body as { + isPrimary?: boolean; + }; + + if (body.isPrimary) { + await Meiling.Identity.User.setPrimaryPhone(userId, phone.phone); + } + + rep.send({ success: true }); + }); + */ + app.delete('/', async (req, rep) => { const userId = (req.params as any)?.userId; const phone = (req as any).phone as Phone; + const phones = await Meiling.Identity.User.getPhones(userId); + if (phones.length === 1) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.FORBIDDEN, 'at least one email is required'); + } + await Meiling.Identity.User.removePhone(userId, phone.phone); rep.send({ success: true }); }); From b0439f172f5022345ac0bc69eea809f4be7e2f4b Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 13:00:01 +0900 Subject: [PATCH 26/95] chore: partially remove hard-coded language --- src/routes/v1/meiling/signin.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index de3d2e49..d6fcb104 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -214,6 +214,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro const to = undefined; await Meiling.V1.Session.setExtendedAuthenticationSessionMethodAndChallenge(req, signinMethod, challenge); + const lang = 'ko'; if (challenge) { if ( @@ -228,7 +229,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro await Notification.sendNotification(Notification.NotificationMethod.ALIMTALK, { type: 'template', templateId: Notification.TemplateId.AUTHENTICATION_CODE, - lang: 'ko', + lang, messages: [ { to, @@ -242,7 +243,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro await Notification.sendNotification(Notification.NotificationMethod.SMS, { type: 'template', templateId: Notification.TemplateId.AUTHENTICATION_CODE, - lang: 'ko', + lang, messages: [ { to, @@ -258,7 +259,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro await Notification.sendNotification(Notification.NotificationMethod.EMAIL, { type: 'template', templateId: Notification.TemplateId.AUTHENTICATION_CODE, - lang: 'ko', + lang, messages: [ { to, From 7ab607c1683773d877d52a55f85a99398b0de19b Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 13:37:33 +0900 Subject: [PATCH 27/95] chore: minimum 15 rounds. to make it secure --- src/routes/v1/meiling/users/actions/security/passwords/put.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/passwords/put.ts b/src/routes/v1/meiling/users/actions/security/passwords/put.ts index c3bf8d4d..4e3634b8 100644 --- a/src/routes/v1/meiling/users/actions/security/passwords/put.ts +++ b/src/routes/v1/meiling/users/actions/security/passwords/put.ts @@ -30,7 +30,7 @@ export async function userPasswordUpdateHandler(req: FastifyRequest, rep: Fastif return; } - const salt = await bcrypt.genSalt(Utils.getCryptoSafeInteger(10) + 5); + const salt = await bcrypt.genSalt(Utils.getCryptoSafeInteger(10) + 15); const hash = await bcrypt.hash(password, salt); const data = { From 89786dce8118a14f7342ab45479638308744fd41 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 13:38:11 +0900 Subject: [PATCH 28/95] chore: too much i guess? use 10 --- src/routes/v1/meiling/users/actions/security/passwords/put.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/passwords/put.ts b/src/routes/v1/meiling/users/actions/security/passwords/put.ts index 4e3634b8..13f534e8 100644 --- a/src/routes/v1/meiling/users/actions/security/passwords/put.ts +++ b/src/routes/v1/meiling/users/actions/security/passwords/put.ts @@ -30,7 +30,7 @@ export async function userPasswordUpdateHandler(req: FastifyRequest, rep: Fastif return; } - const salt = await bcrypt.genSalt(Utils.getCryptoSafeInteger(10) + 15); + const salt = await bcrypt.genSalt(Utils.getCryptoSafeInteger(10) + 10); const hash = await bcrypt.hash(password, salt); const data = { From 873f3f6446ca4698209a178f2122c55bed4aecf7 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 14:20:18 +0900 Subject: [PATCH 29/95] feat: experimental TOTP support --- src/common/meiling/v1/interfaces/session.ts | 6 + .../meiling/users/actions/security/index.ts | 2 + .../actions/security/otp/actions/delete.ts | 48 ++++++++ .../users/actions/security/otp/actions/get.ts | 47 ++++++++ .../actions/security/otp/actions/index.ts | 14 +++ .../actions/security/otp/actions/post.ts | 108 ++++++++++++++++++ .../users/actions/security/otp/actions/put.ts | 59 ++++++++++ .../users/actions/security/otp/index.ts | 45 ++++++++ 8 files changed, 329 insertions(+) create mode 100644 src/routes/v1/meiling/users/actions/security/otp/actions/delete.ts create mode 100644 src/routes/v1/meiling/users/actions/security/otp/actions/get.ts create mode 100644 src/routes/v1/meiling/users/actions/security/otp/actions/index.ts create mode 100644 src/routes/v1/meiling/users/actions/security/otp/actions/post.ts create mode 100644 src/routes/v1/meiling/users/actions/security/otp/actions/put.ts create mode 100644 src/routes/v1/meiling/users/actions/security/otp/index.ts diff --git a/src/common/meiling/v1/interfaces/session.ts b/src/common/meiling/v1/interfaces/session.ts index d2d1632c..17a4ecd9 100644 --- a/src/common/meiling/v1/interfaces/session.ts +++ b/src/common/meiling/v1/interfaces/session.ts @@ -11,12 +11,18 @@ export interface MeilingSession { export interface SessionRegistering { webAuthn?: RegisteringWebAuthn; + otp?: RegisteringOTP; } export interface RegisteringWebAuthn { challenge: string; } +export interface RegisteringOTP { + secret: string; + issuedAt: number; +} + export interface LoggedInUser { id: string; } diff --git a/src/routes/v1/meiling/users/actions/security/index.ts b/src/routes/v1/meiling/users/actions/security/index.ts index 0eb8e94e..43840d28 100644 --- a/src/routes/v1/meiling/users/actions/security/index.ts +++ b/src/routes/v1/meiling/users/actions/security/index.ts @@ -2,11 +2,13 @@ import { FastifyInstance, FastifyPluginOptions } from 'fastify'; import user2FAPlugin from './2fa'; import userPasswordsPlugin from './passwords'; import userPGPPlugin from './pgp'; +import userOTPPlugin from './otp'; import userWebAuthnPlugin from './webauthn'; function userSecurityPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.register(userPasswordsPlugin, { prefix: '/passwords' }); app.register(user2FAPlugin, { prefix: '/2fa' }); + app.register(userOTPPlugin, { prefix: '/otp' }); app.register(userWebAuthnPlugin, { prefix: '/webauthn' }); app.register(userPGPPlugin, { prefix: '/pgp' }); diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/delete.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/delete.ts new file mode 100644 index 00000000..28244395 --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/delete.ts @@ -0,0 +1,48 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { getUserFromActionRequest } from '../../..'; +import { Meiling, Utils } from '../../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../../resources/prisma'; + +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.OTP); + +async function userOTPActionDeleteKey(req: FastifyRequest, rep: FastifyReply): Promise { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + const tokenId = (req.params as any).tokenId; + if (!Utils.isNotBlank(tokenId)) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + return; + } + + const checkExist = + (await getPrismaClient().authentication.count({ + where: { + user: { + id: user.id, + }, + method: dbType, + id: tokenId, + }, + })) > 0; + + if (!checkExist) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + return; + } + + await getPrismaClient().authentication.delete({ + where: { + id: tokenId, + }, + }); + + await Meiling.Identity.User.prevent2FALockout(user.id); + + rep.send({ success: true }); +} + +export default userOTPActionDeleteKey; diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/get.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/get.ts new file mode 100644 index 00000000..83fd790b --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/get.ts @@ -0,0 +1,47 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { getUserFromActionRequest } from '../../..'; +import { Meiling, Utils } from '../../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../../resources/prisma'; + +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.OTP); + +async function userOTPActionGetKey(req: FastifyRequest, rep: FastifyReply): Promise { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + const tokenId = (req.params as any).tokenId; + if (!Utils.isNotBlank(tokenId)) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + return; + } + + const keyData = await getPrismaClient().authentication.findFirst({ + where: { + user: { + id: user.id, + }, + method: dbType, + id: tokenId, + }, + }); + + if (!keyData) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + return; + } + + rep.send({ + id: keyData.id, + createdAt: keyData.createdAt, + name: (keyData.data as any).data.name, + + allowSingleFactor: keyData.allowSingleFactor, + allowTwoFactor: keyData.allowTwoFactor, + allowPasswordReset: keyData.allowPasswordReset, + }); +} + +export default userOTPActionGetKey; diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/index.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/index.ts new file mode 100644 index 00000000..6368c1d3 --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/index.ts @@ -0,0 +1,14 @@ +import { FastifyInstance, FastifyPluginOptions } from 'fastify'; +import userOTPActionDeleteKey from './delete'; +import userOTPActionGetKey from './get'; +import userOTPActionPutKey from './put'; + +function userOTPActionsPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.delete('/', userOTPActionDeleteKey); + app.put('/', userOTPActionPutKey); + app.get('/', userOTPActionGetKey); + + done(); +} + +export default userOTPActionsPlugin; diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts new file mode 100644 index 00000000..32d478b1 --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts @@ -0,0 +1,108 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { getUserFromActionRequest } from '../../..'; +import { Meiling, Utils } from '../../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../../resources/prisma'; +import SpeakEasy from 'speakeasy'; +import config from '../../../../../../../../resources/config'; +import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1/session'; +import { AuthenticationMethod } from '@prisma/client'; + +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.OTP); + +async function userOTPActionPostKey(req: FastifyRequest, rep: FastifyReply): Promise { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + const body = req.body as { challengeResponse?: string; name: string } | undefined; + + const isRegistering = Utils.isNotBlank(body?.challengeResponse); + + const session = await getSessionFromRequest(req); + const otpState = session?.registering?.otp; + + let secret = undefined; + let requireIssue = false; + if (otpState === undefined) { + requireIssue = true; + } else { + // TODO: change this hardcoded value + if (otpState.issuedAt + 1000 * 60 * 5 < new Date().getTime()) { + requireIssue = true; + } else { + secret = otpState.secret; + } + } + + if (isRegistering) { + if (!otpState || !secret) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED); + } else if (requireIssue) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_TIMEOUT); + } + + if (!Utils.isNotBlank(body?.name)) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'missing name'); + } + + const isValid = SpeakEasy.totp.verifyDelta({ + encoding: 'base32', + token: body?.challengeResponse as string, + secret, + window: 2, + }); + + if (!isValid) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_INVALID); + } + + const name = body?.name; + const otpData = await getPrismaClient().authentication.create({ + data: { + user: { + connect: { + id: user.id, + }, + }, + data: { + name, + secret, + }, + method: dbType as AuthenticationMethod, + allowTwoFactor: true, + }, + }); + + rep.send({ + id: otpData.id, + createdAt: otpData.createdAt, + name: (otpData.data as any).data.name, + + allowSingleFactor: otpData.allowSingleFactor, + allowTwoFactor: otpData.allowTwoFactor, + allowPasswordReset: otpData.allowPasswordReset, + }); + } else { + const secret = SpeakEasy.generateSecret(); + const secretSafe = secret.base32; + + await Meiling.V1.Session.setSession(req, { + ...session, + registering: { + ...session?.registering, + otp: { + secret: secretSafe, + issuedAt: new Date().getTime(), + }, + }, + }); + + rep.send({ + otpauth: secret.otpauth_url, + }); + } +} + +export default userOTPActionPostKey; diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/put.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/put.ts new file mode 100644 index 00000000..0410446f --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/put.ts @@ -0,0 +1,59 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { getUserFromActionRequest } from '../../..'; +import { Meiling, Utils } from '../../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../../resources/prisma'; + +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.OTP); + +async function userOTPActionPutKey(req: FastifyRequest, rep: FastifyReply): Promise { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + const tokenId = (req.params as any).tokenId; + if (!Utils.isNotBlank(tokenId)) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + return; + } + + if (!req.body) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + return; + } + + const body = (req.body as any) || {}; + + const keyData = await getPrismaClient().authentication.findFirst({ + where: { + user: { + id: user.id, + }, + method: dbType, + id: tokenId, + }, + }); + + if (!keyData) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + return; + } + + await getPrismaClient().authentication.update({ + where: { + id: tokenId, + }, + data: { + allowPasswordReset: typeof body?.allowPasswordReset === 'boolean' ? body.allowPasswordReset : undefined, + allowSingleFactor: typeof body?.allowSingleFactor === 'boolean' ? body.allowSingleFactor : undefined, + allowTwoFactor: typeof body?.allowTwoFactor === 'boolean' ? body.allowTwoFactor : undefined, + }, + }); + + await Meiling.Identity.User.prevent2FALockout(user.id); + + rep.send({ success: true }); +} + +export default userOTPActionPutKey; diff --git a/src/routes/v1/meiling/users/actions/security/otp/index.ts b/src/routes/v1/meiling/users/actions/security/otp/index.ts new file mode 100644 index 00000000..d5680e4f --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/otp/index.ts @@ -0,0 +1,45 @@ +import { FastifyInstance, FastifyPluginOptions } from 'fastify'; +import { getUserFromActionRequest } from '../..'; +import { Meiling, Utils } from '../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../resources/prisma'; +import crypto from 'crypto'; +import userOTPActionPostKey from './actions/post'; +import userOTPActionsPlugin from './actions'; + +function userOTPPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.get('/', async (req, rep) => { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.OTP); + + const otps = await getPrismaClient().authentication.findMany({ + where: { + user: { + id: user.id, + }, + method: dbType, + }, + }); + + // TODO: Implement sanitizing + rep.send( + otps.map((n) => ({ + id: n.id, + createdAt: n.createdAt, + name: (n.data as any)?.name, + })), + ); + }); + + app.post('/', userOTPActionPostKey); + + app.register(userOTPActionsPlugin, { prefix: '/:tokenId' }); + + done(); +} + +export default userOTPPlugin; From ccbcaf27f3fbf3f5bb3147a95c86897b93f70db6 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 14:47:21 +0900 Subject: [PATCH 30/95] chore: ip logging and rate limiting on session token issuing --- src/common/meiling/v1/error/error.ts | 1 + src/common/meiling/v1/error/type.ts | 1 + src/common/meiling/v1/interfaces/session.ts | 1 + src/common/meiling/v1/session.ts | 43 +++++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/src/common/meiling/v1/error/error.ts b/src/common/meiling/v1/error/error.ts index 1c3fe7c3..438f745a 100644 --- a/src/common/meiling/v1/error/error.ts +++ b/src/common/meiling/v1/error/error.ts @@ -66,6 +66,7 @@ function getMeilingErrorStatusCode(type: ErrorType) { return 410; case ErrorType.AUTHENTICATION_REQUEST_RATE_LIMITED: + case ErrorType.RATE_LIMITED: return 429; case ErrorType.INTERNAL_SERVER_ERROR: diff --git a/src/common/meiling/v1/error/type.ts b/src/common/meiling/v1/error/type.ts index b63cccf3..141f8367 100644 --- a/src/common/meiling/v1/error/type.ts +++ b/src/common/meiling/v1/error/type.ts @@ -37,4 +37,5 @@ export enum ErrorType { PHONE_NOT_ALLOWED = 'phone_not_allowed', EXISTING_USERNAME = 'existing_username', EXISTING_PASSWORD = 'existing_password', + RATE_LIMITED = 'rate_limited', } diff --git a/src/common/meiling/v1/interfaces/session.ts b/src/common/meiling/v1/interfaces/session.ts index 17a4ecd9..651a490e 100644 --- a/src/common/meiling/v1/interfaces/session.ts +++ b/src/common/meiling/v1/interfaces/session.ts @@ -7,6 +7,7 @@ export interface MeilingSession { authenticationStatus?: SessionAuthenticationStatus; passwordReset?: SessionPasswordReset; registering?: SessionRegistering; + ips?: string[]; } export interface SessionRegistering { diff --git a/src/common/meiling/v1/session.ts b/src/common/meiling/v1/session.ts index 9415c52d..4ef6e31b 100644 --- a/src/common/meiling/v1/session.ts +++ b/src/common/meiling/v1/session.ts @@ -30,6 +30,8 @@ let tokenSessions: MeilingV1TokenDataFile = { issuedTokens: [], }; +const lastIssueRequest: Record = {}; + export function loadSessionSaveFiles(): void { if (config.session.v1.storage) { if (config.session.v1.storage.type === 'file') { @@ -136,6 +138,16 @@ export function getTokenFromRequest(req: FastifyRequest): string | undefined { } export async function createToken(req: FastifyRequest): Promise { + // TODO: make this more configurable + if (lastIssueRequest[req.ip] !== undefined) { + const date = lastIssueRequest[req.ip]; + const rateLimitWindow = 100; + + if (date.getTime() + rateLimitWindow > new Date().getTime()) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.RATE_LIMITED); + } + } + const token = Meiling.Authentication.Token.generateToken(); const expiration = new Date(new Date().getTime() + config.session.v1.maxAge * 1000); const userTimeFieldMinimum = new Date().getTime() - config.session.v1.rateLimit.timeframe * 1000; @@ -185,6 +197,7 @@ export async function createToken(req: FastifyRequest): Promise { } } +export async function updateUserIPs(token: string, ip: string): Promise { + if (config.session.v1.storage) { + const tokenData = tokenSessions.issuedTokens.find((n) => n.token === token); + if (tokenData) { + if (!tokenData.session.ips) tokenData.session.ips = []; + if (!tokenData.session.ips.includes(ip)) { + tokenData.session.ips.push(ip); + } + } + } else { + const session = await getPrismaClient().meilingSessionV1Token.findUnique({ where: { token } }); + if (session) { + await getPrismaClient().meilingSessionV1Token.update({ + where: { + token, + }, + data: { + session: { + ...(session.session as any), + ips: + ((session.session as any)?.ips as any) === undefined + ? [ip] + : ((session.session as any).ips as string[]).push(ip), + }, + }, + }); + } + } +} + export async function setSession(req: FastifyRequest, data?: MeilingSession): Promise { if (req.headers.authorization && req.headers.authorization.includes('Bearer')) { const token = await getTokenFromRequest(req); From e4f9a0c0212acda31c59ad7b95cec1277cfc8dd9 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 14:50:21 +0900 Subject: [PATCH 31/95] chore: webauthn support prerequisites --- package.json | 1 + .../actions/security/webauthn/actions/post.ts | 33 +++ .../actions/security/webauthn/actions/put.ts | 2 +- .../users/actions/security/webauthn/index.ts | 38 +-- yarn.lock | 250 ++++++++++++++++++ 5 files changed, 288 insertions(+), 36 deletions(-) create mode 100644 src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts diff --git a/package.json b/package.json index b40271c4..be9538f7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "fastify-formbody": "^5.0.0", "fastify-secure-session": "^2.3.0", "fastify-swagger": "^4.15.0", + "fido2-lib": "^3.1.7", "figlet": "^1.5.0", "jsonwebtoken": "^8.5.1", "libphonenumber-js": "^1.9.49", diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts new file mode 100644 index 00000000..f09c4ece --- /dev/null +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -0,0 +1,33 @@ +import { FastifyReply, FastifyRequest } from 'fastify'; +import { getUserFromActionRequest } from '../../..'; +import { Meiling, Utils } from '../../../../../../../../common'; +import { getPrismaClient } from '../../../../../../../../resources/prisma'; +import { Fido2Lib } from 'fido2-lib'; +import config from '../../../../../../../../resources/config'; + +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); + +async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply): Promise { + const user = await getUserFromActionRequest(req); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); + return; + } + + let hostname = (req.params as any).hostname; + if (!Utils.isNotBlank(hostname)) { + hostname = config.frontend.url[0]; + } + + if (!config.frontend.url.includes(hostname)) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'provided hostname is not supported', + ); + } + + Fido2Lib; + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); +} + +export default userWebAuthnActionPostKey; diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts index b8461990..f8381f28 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts @@ -3,7 +3,7 @@ import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.PGP_SIGNATURE); +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); async function userWebAuthnActionPutKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts index 8b5a42dd..a02abb09 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts @@ -4,6 +4,7 @@ import { Meiling, Utils } from '../../../../../../../common'; import { getPrismaClient } from '../../../../../../../resources/prisma'; import userWebAuthnActionsPlugin from './actions'; import crypto from 'crypto'; +import userWebAuthnActionPostKey from './actions/post'; function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.get('/', async (req, rep) => { @@ -28,46 +29,13 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do rep.send( securityKeys.map((n) => ({ id: n.id, + name: (n.data as any)?.name, createdAt: n.createdAt, })), ); }); - app.post('/', async (req, rep) => { - const body = req.body as any; - const session = await Meiling.V1.Session.getSessionFromRequest(req); - const user = await getUserFromActionRequest(req); - - if (!user || !session) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED); - return; - } - - if (Utils.isNotBlank(body.id, body.hostname, body.response, body.response?.attenationObject, body)) { - // TODO: Implement registration procedure - } else { - const challenge = crypto.randomBytes(64); - - await Meiling.V1.Session.setSession(req, { - ...session, - registering: { - webAuthn: { - challenge: challenge.toString('base64'), - }, - }, - }); - - rep.send({ - user: { - id: user.id, - name: user.username, - displayName: user.name, - icon: user.profileUrl ? user.profileUrl : undefined, - }, - challenge: challenge.toString('base64'), - }); - } - }); + app.post('/', userWebAuthnActionPostKey); app.register(userWebAuthnActionsPlugin, { prefix: '/:tokenId' }); diff --git a/yarn.lock b/yarn.lock index 3085e1f5..930330a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -57,6 +57,11 @@ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d" integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg== +"@hexagon/base64@^1.0.19": + version "1.0.19" + resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.0.19.tgz#2052e7370d49df624e7885c92f7ef3f854f15996" + integrity sha512-+ZJdUaD9sthgMbdEiYZ5jwiTG/ZtILx0/LSDkdxi/pK/BSmJzIAT+IYuMYSKwjPdGk6odwbJVQ9H8HpepDZy9Q== + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -92,6 +97,33 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@peculiar/asn1-schema@^2.1.6": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.1.8.tgz#552300a1ed7991b22c9abf789a3920a3cb94c26b" + integrity sha512-u34H/bpqCdDuqrCVZvH0vpwFBT/dNEdNY+eE8u4IuC26yYnhDkXF4+Hliqca88Avbb7hyN2EF/eokyDdyS7G/A== + dependencies: + asn1js "^3.0.4" + pvtsutils "^1.3.2" + tslib "^2.4.0" + +"@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + +"@peculiar/webcrypto@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz#f941bd95285a0f8a3d2af39ccda5197b80cd32bf" + integrity sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg== + dependencies: + "@peculiar/asn1-schema" "^2.1.6" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.3.2" + tslib "^2.4.0" + webcrypto-core "^1.7.4" + "@prisma/client@^3.9.2": version "3.11.1" resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.11.1.tgz#bde6dec71ae133d04ce1c6658e3d76627a3c6dc7" @@ -527,6 +559,15 @@ asn1@^0.2.4: dependencies: safer-buffer "~2.1.0" +asn1js@^3.0.1, asn1js@^3.0.2, asn1js@^3.0.4, asn1js@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" + integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== + dependencies: + pvtsutils "^1.3.2" + pvutils "^1.1.3" + tslib "^2.4.0" + astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -652,6 +693,11 @@ buildcheck@0.0.3: resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.3.tgz#70451897a95d80f7807e68fc412eb2e7e35ff4d5" integrity sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA== +bytestreamjs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bytestreamjs/-/bytestreamjs-2.0.0.tgz#ee1b3c348967d4c3ffa45911a64e51a1fd24fc3b" + integrity sha512-TyOlxeS92FcMOaJwAVq5gwqW0vfkWUv5W+ErwdbBzolcUN/9XYpCKWvCV21jjzXU550D9Wt4GgE8Pr1vVbR+wQ== + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -680,6 +726,23 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== +cbor-extract@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-1.0.0.tgz#e6c793adc166d7661a0a59b8bf5433b98e202ab9" + integrity sha512-2y71EsPT4dJjtS24JIZfzUodm7kNrJJouIL7U4YiO1bl5QJyCHz9j810x/d+A/L+1BWQCE0771TiBrVmDL0MOA== + dependencies: + nan "^2.14.2" + node-gyp-build "^4.2.3" + +cbor-x@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.2.1.tgz#b621972873a91f9dfd2c905f8b008e4796972958" + integrity sha512-vUgwxN/hCyMUuFsYaMTYhfpK0rwBpGho8CqCLEXSn3tGfaPL3fruB0lrZVGiq1v5EzTrqcrLVxJ2Ul9zqukhMw== + dependencies: + esbuild "^0.13.15" + optionalDependencies: + cbor-extract "^1.0.0" + chalk@2.4.2, chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1066,6 +1129,114 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +esbuild-android-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44" + integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg== + +esbuild-darwin-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72" + integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ== + +esbuild-darwin-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a" + integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ== + +esbuild-freebsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85" + integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA== + +esbuild-freebsd-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52" + integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ== + +esbuild-linux-32@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69" + integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g== + +esbuild-linux-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3" + integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA== + +esbuild-linux-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1" + integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA== + +esbuild-linux-arm@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe" + integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA== + +esbuild-linux-mips64le@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7" + integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg== + +esbuild-linux-ppc64le@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2" + integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ== + +esbuild-netbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038" + integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w== + +esbuild-openbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7" + integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g== + +esbuild-sunos-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4" + integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw== + +esbuild-windows-32@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7" + integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw== + +esbuild-windows-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294" + integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ== + +esbuild-windows-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3" + integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA== + +esbuild@^0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf" + integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw== + optionalDependencies: + esbuild-android-arm64 "0.13.15" + esbuild-darwin-64 "0.13.15" + esbuild-darwin-arm64 "0.13.15" + esbuild-freebsd-64 "0.13.15" + esbuild-freebsd-arm64 "0.13.15" + esbuild-linux-32 "0.13.15" + esbuild-linux-64 "0.13.15" + esbuild-linux-arm "0.13.15" + esbuild-linux-arm64 "0.13.15" + esbuild-linux-mips64le "0.13.15" + esbuild-linux-ppc64le "0.13.15" + esbuild-netbsd-64 "0.13.15" + esbuild-openbsd-64 "0.13.15" + esbuild-sunos-64 "0.13.15" + esbuild-windows-32 "0.13.15" + esbuild-windows-64 "0.13.15" + esbuild-windows-arm64 "0.13.15" + escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -1404,6 +1575,19 @@ fastq@^1.6.0, fastq@^1.6.1: dependencies: reusify "^1.0.4" +fido2-lib@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/fido2-lib/-/fido2-lib-3.1.7.tgz#64637e449d2c37d8b1dd5dd7ab638ee45962c3b6" + integrity sha512-d/umDGlsSRfexIFMzhTmnf264fLyYoynMYWKVAiMEqoUWVqB1m+JaIJNr14cVSEz3zxEl7ryvRTJI7JIp3+1GA== + dependencies: + "@hexagon/base64" "^1.0.19" + "@peculiar/webcrypto" "^1.4.0" + asn1js "^3.0.2" + cbor-x "~1.2.1" + jose "^4.7.0" + pkijs "^3.0.3" + tldts "^5.7.79" + figlet@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" @@ -1854,6 +2038,11 @@ jmespath@^0.15.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= +jose@^4.7.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.8.1.tgz#dc7c2660b115ba29b44880e588c5ac313c158247" + integrity sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw== + joycon@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/joycon/-/joycon-2.2.5.tgz#8d4cf4cbb2544d7b7583c216fcdfec19f6be1615" @@ -2250,6 +2439,11 @@ named-placeholders@^1.1.2: dependencies: lru-cache "^4.1.3" +nan@^2.14.2: + version "2.16.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" + integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== + nan@^2.15.0: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" @@ -2267,6 +2461,11 @@ node-fetch@^2.1.2: dependencies: whatwg-url "^5.0.0" +node-gyp-build@^4.2.3: + version "4.4.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" + integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== + node-gyp-build@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" @@ -2535,6 +2734,17 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" +pkijs@^3.0.3: + version "3.0.5" + resolved "https://registry.yarnpkg.com/pkijs/-/pkijs-3.0.5.tgz#64134f45a92633841b2200b2ece01931209a6c56" + integrity sha512-J6P30yzU7qSbuJIBaclwN93WbyoxjVlkYMgjQmE9wWkPUTHVu2cH6lkjWcIr2WAub5KH38BA1Eyeb4s9apUPTg== + dependencies: + asn1js "^3.0.5" + bytestreamjs "^2.0.0" + pvtsutils "^1.3.2" + pvutils "^1.1.3" + tslib "^2.4.0" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -2627,6 +2837,18 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" +pvtsutils@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.2.tgz#9f8570d132cdd3c27ab7d51a2799239bf8d8d5de" + integrity sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ== + dependencies: + tslib "^2.4.0" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + queue-microtask@^1.1.2, queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -3096,6 +3318,18 @@ tiny-lru@^8.0.1: resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-8.0.2.tgz#812fccbe6e622ded552e3ff8a4c3b5ff34a85e4c" integrity sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg== +tldts-core@^5.7.81: + version "5.7.81" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.7.81.tgz#1beae3fdd959ca9f32a2eb5ac07c4a65a561e65e" + integrity sha512-9i+XjmFvl/eSubippvvxEqIGexT6ALqb7fO3EPQ6yNOMaoRdaDgrMqBCIXSqVY/SckpFm54fksaLVQE6KtlAGA== + +tldts@^5.7.79: + version "5.7.81" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.7.81.tgz#a43aff0de062df106dbc9e3a5b18660b3e497044" + integrity sha512-ulFEOSC+mHmkYwWMeX/ys+n7GFxROldJJVrSxSPASuyigTFvAQAGs1eVy82NFxazoEsCfvuCQrSOzdXLKfvR+A== + dependencies: + tldts-core "^5.7.81" + to-readable-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" @@ -3142,6 +3376,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0, tslib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" @@ -3249,6 +3488,17 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +webcrypto-core@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.5.tgz#c02104c953ca7107557f9c165d194c6316587ca4" + integrity sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A== + dependencies: + "@peculiar/asn1-schema" "^2.1.6" + "@peculiar/json-schema" "^1.1.12" + asn1js "^3.0.1" + pvtsutils "^1.3.2" + tslib "^2.4.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 823407f4688aa4f224ec577baf05b98cfb708511 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 5 Jun 2022 16:35:32 +0900 Subject: [PATCH 32/95] chore: partial implementation of webAuthn challenge exchange --- src/common/meiling/v1/interfaces/session.ts | 2 + .../actions/security/webauthn/actions/post.ts | 67 +++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/common/meiling/v1/interfaces/session.ts b/src/common/meiling/v1/interfaces/session.ts index 651a490e..17c0ba5f 100644 --- a/src/common/meiling/v1/interfaces/session.ts +++ b/src/common/meiling/v1/interfaces/session.ts @@ -16,6 +16,8 @@ export interface SessionRegistering { } export interface RegisteringWebAuthn { + origin: string; + hostname: string; challenge: string; } diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index f09c4ece..cadcc162 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -2,8 +2,10 @@ import { FastifyReply, FastifyRequest } from 'fastify'; import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -import { Fido2Lib } from 'fido2-lib'; +import { AttestationResult, Factor, Fido2Lib } from 'fido2-lib'; import config from '../../../../../../../../resources/config'; +import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1/session'; +import crypto from 'crypto'; const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); @@ -14,8 +16,18 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) return; } - let hostname = (req.params as any).hostname; - if (!Utils.isNotBlank(hostname)) { + const session = await getSessionFromRequest(req); + + const body = req.body as + | { + hostname: string; + challengeResponse?: AttestationResult; + name?: string; + } + | undefined; + + let hostname = body?.hostname; + if (!hostname || !Utils.isNotBlank(hostname)) { hostname = config.frontend.url[0]; } @@ -26,8 +38,53 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) ); } - Fido2Lib; - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); + const challengeResponse = body?.challengeResponse; + + const registering = challengeResponse !== undefined; + const f2l = new Fido2Lib({}); + + if (registering && body) { + const webAuthnObject = session?.registering?.webAuthn; + + if (!webAuthnObject || !Utils.isNotBlank(webAuthnObject.challenge, webAuthnObject.hostname, webAuthnObject.origin)) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED); + + if (!Utils.isNotBlank(body.name)) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + + const attensationExpectations = { + challenge: webAuthnObject.challenge, + origin: webAuthnObject.origin, + factor: 'either' as Factor, + }; + + try { + const result = await f2l.attestationResult(challengeResponse, attensationExpectations); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); + } catch (e) { + // TODO: further debugging required. + throw e; + } + } else { + const challenge = Meiling.Authentication.Token.generateToken(128); + const origin = req.headers.origin ?? hostname; + + await Meiling.V1.Session.setSession(req, { + ...session, + registering: { + ...session?.registering, + webAuthn: { + origin, + hostname, + challenge, + }, + }, + }); + + rep.send({ + challenge, + }); + } } export default userWebAuthnActionPostKey; From e7666742f2d8c45dc92601447a0539321d2c93f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Wed, 8 Jun 2022 22:15:23 +0900 Subject: [PATCH 33/95] chore: change HRPL Filename --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4f898c0..37621477 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,6 @@ These are the documentations for helping you try meiliNG on your hands! ## License Distributed under [MIT License](LICENSE). -If the [MIT License](LICENSE) does not cover you, You can use [Hakurei Reimu Public License](https://github.com/Alex4386/HRPL) instead. [(LICENSE_HRPL)](LICENSE_HRPL) An Open-Source License considering all-beings (such as AI, like GitHub Copilot) +If the [MIT License](LICENSE) does not cover you, You can use [Hakurei Reimu Public License](https://github.com/Alex4386/HRPL) instead. [(EXT_LICENSE)](EXT_LICENSE) An Open-Source License considering all-beings (such as AI, like GitHub Copilot) You can activate License Extension by following this file: [APPLY_EXTENSION.md](APPLY_EXTENSION.md) From 7ccedaf91aab878f4cd4cb4688fdda589d7d2bf1 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Wed, 8 Jun 2022 23:06:06 +0900 Subject: [PATCH 34/95] chore: include user data on login --- src/routes/v1/meiling/signin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index d6fcb104..77a08be1 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -398,5 +398,6 @@ please request this endpoint without challengeResponse field to request challeng rep.status(200).send({ success: true, + data: user, }); } From dce0876d275abb4a36f879a11627c09bc034070d Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 16 Jun 2022 16:46:55 +0900 Subject: [PATCH 35/95] chore: implement administrative login w/o two factor auth --- src/routes/v1/admin/auth/index.ts | 73 +++++++++++++++++++++++++++++++ src/routes/v1/admin/index.ts | 2 + 2 files changed, 75 insertions(+) create mode 100644 src/routes/v1/admin/auth/index.ts diff --git a/src/routes/v1/admin/auth/index.ts b/src/routes/v1/admin/auth/index.ts new file mode 100644 index 00000000..9edc0c82 --- /dev/null +++ b/src/routes/v1/admin/auth/index.ts @@ -0,0 +1,73 @@ +import { getPrismaClient } from '../../../../resources/prisma'; +import { FastifyInstance, FastifyPluginOptions } from 'fastify'; +import { Meiling } from '../../../../common'; + +const authAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { + app.post('/login', async (req, rep) => { + const query = req.query as { + token?: string; + }; + + const body = req.body as { + userId?: string; + skip2FA?: boolean; + }; + + const token = query.token; + const userId = body.userId; + if (!userId || !token) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'Required parameters are missing', + ); + } + + const session = await getPrismaClient().meilingSessionV1Token.findUnique({ + where: { + token, + }, + }); + + if (!session) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'Session was not found'); + } + + const user = await Meiling.Identity.User.getBasicInfo(userId); + if (!user) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'user was not found'); + } + + const sessionData = session.session as Meiling.V1.Interfaces.MeilingSession; + if (!sessionData.previouslyLoggedIn) sessionData.previouslyLoggedIn = []; + if (!sessionData.previouslyLoggedIn.map((n) => n.id).includes(userId)) { + sessionData.previouslyLoggedIn.push({ + id: userId, + }); + } + + if (!sessionData.user) sessionData.user = []; + if (!sessionData.user.map((n) => n.id).includes(userId)) { + sessionData.user.push({ id: userId }); + } + + if (body.skip2FA || !user.useTwoFactor) { + await getPrismaClient().meilingSessionV1Token.update({ + where: { + token, + }, + data: { + session: sessionData as any, + }, + }); + + rep.send({ success: true }); + } else { + // TODO: Implement it properly + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUIRED); + } + }); + + done(); +}; + +export default authAdminHandler; diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index 11f056c8..879dfdd9 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -5,6 +5,7 @@ import { NodeEnvironment } from '../../../interface'; import config from '../../../resources/config'; import { info as packageJson } from '../../../resources/package'; import appsAdminHandler from './apps'; +import authAdminHandler from './auth'; import internalAdminHandler from './internal'; import sessionsAdminHandler from './sessions'; import tokensAdminHandler from './tokens'; @@ -110,6 +111,7 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( app.register(usersAdminHandler, { prefix: '/users' }); app.register(appsAdminHandler, { prefix: '/apps' }); + app.register(authAdminHandler, { prefix: '/auth' }); app.register(tokensAdminHandler, { prefix: '/tokens' }); app.register(sessionsAdminHandler, { prefix: '/sessions' }); app.register(internalAdminHandler, { prefix: '/internal' }); From 0302c15acf3f0607a503ab5924abdae0951404fe Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 16 Jun 2022 16:54:35 +0900 Subject: [PATCH 36/95] chore: change enum to webauthn --- prisma/schema.prisma | 2 +- src/common/meiling/v1/database.ts | 10 +++++----- src/common/meiling/v1/interfaces/query.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 889e5023..83087a49 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -80,7 +80,7 @@ enum AuthenticationMethod { SSH_KEY SMS EMAIL - SECURITY_KEY + WEBAUTHN } model Authentication { diff --git a/src/common/meiling/v1/database.ts b/src/common/meiling/v1/database.ts index 5cddca19..763a6f6d 100644 --- a/src/common/meiling/v1/database.ts +++ b/src/common/meiling/v1/database.ts @@ -6,8 +6,8 @@ export function convertAuthentication(method?: ExtendedAuthMethods): Authenticat switch (method) { case ExtendedAuthMethods.SMS: return 'SMS'; - case ExtendedAuthMethods.SECURITY_KEY: - return 'SECURITY_KEY'; + case ExtendedAuthMethods.WEBAUTHN: + return 'WEBAUTHN'; case ExtendedAuthMethods.PGP_SIGNATURE: return 'PGP_KEY'; case ExtendedAuthMethods.OTP: @@ -27,8 +27,8 @@ export function convertAuthenticationMethod(method: AuthenticationMethod): Exten return ExtendedAuthMethods.OTP; case 'PGP_KEY': return ExtendedAuthMethods.PGP_SIGNATURE; - case 'SECURITY_KEY': - return ExtendedAuthMethods.SECURITY_KEY; + case 'WEBAUTHN': + return ExtendedAuthMethods.WEBAUTHN; case 'SMS': return ExtendedAuthMethods.SMS; default: @@ -41,7 +41,7 @@ export function checkAuthenticationMethod(method: AuthenticationMethod): boolean case 'EMAIL': case 'OTP': case 'PGP_KEY': - case 'SECURITY_KEY': + case 'WEBAUTHN': case 'SMS': case 'PASSWORD': case 'SSH_KEY': diff --git a/src/common/meiling/v1/interfaces/query.ts b/src/common/meiling/v1/interfaces/query.ts index 1a06a67b..cbdbd98c 100644 --- a/src/common/meiling/v1/interfaces/query.ts +++ b/src/common/meiling/v1/interfaces/query.ts @@ -12,7 +12,7 @@ export enum ExtendedAuthMethods { OTP = 'otp', SMS = 'sms', EMAIL = 'email', - SECURITY_KEY = 'security_key', + WEBAUTHN = 'webauthn', } export type SigninBody = SigninUsernameCheck | SigninUsernameAndPassword | SigninExtendedAuthentication; From 9fba3440362da2c36aaa534c00b2737e64faa6b5 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 16 Jun 2022 17:14:33 +0900 Subject: [PATCH 37/95] chore: Refactoring did not work. changing some code --- src/common/meiling/v1/challenge.ts | 10 +++++----- .../users/actions/security/webauthn/actions/delete.ts | 2 +- .../users/actions/security/webauthn/actions/get.ts | 2 +- .../users/actions/security/webauthn/actions/post.ts | 2 +- .../users/actions/security/webauthn/actions/put.ts | 2 +- .../meiling/users/actions/security/webauthn/index.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/common/meiling/v1/challenge.ts b/src/common/meiling/v1/challenge.ts index e036631f..e0af8d91 100644 --- a/src/common/meiling/v1/challenge.ts +++ b/src/common/meiling/v1/challenge.ts @@ -52,7 +52,7 @@ export function isChallengeRateLimited(signinMethod: ExtendedAuthMethods, issued export function generateChallenge(signinMethod: ExtendedAuthMethods): string | undefined { switch (signinMethod) { case ExtendedAuthMethods.PGP_SIGNATURE: - case ExtendedAuthMethods.SECURITY_KEY: + case ExtendedAuthMethods.WEBAUTHN: return Meiling.Authentication.Token.generateToken(); case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.EMAIL: @@ -66,7 +66,7 @@ export function generateChallenge(signinMethod: ExtendedAuthMethods): string | u export function shouldSendChallenge(signinMethod: ExtendedAuthMethods): boolean { switch (signinMethod) { case ExtendedAuthMethods.PGP_SIGNATURE: - case ExtendedAuthMethods.SECURITY_KEY: + case ExtendedAuthMethods.WEBAUTHN: return true; case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.EMAIL: @@ -83,7 +83,7 @@ export function isChallengeMethodAdequate(body: SigninExtendedAuthentication, me if (body.type === SigninType.PASSWORDLESS) { switch (method) { case ExtendedAuthMethods.PGP_SIGNATURE: - case ExtendedAuthMethods.SECURITY_KEY: + case ExtendedAuthMethods.WEBAUTHN: return true; case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.OTP: @@ -95,7 +95,7 @@ export function isChallengeMethodAdequate(body: SigninExtendedAuthentication, me } else if (body.type === SigninType.TWO_FACTOR_AUTH) { switch (method) { case ExtendedAuthMethods.PGP_SIGNATURE: - case ExtendedAuthMethods.SECURITY_KEY: + case ExtendedAuthMethods.WEBAUTHN: case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.OTP: case ExtendedAuthMethods.EMAIL: @@ -122,7 +122,7 @@ export async function verifyChallenge( challengeResponse, (data as AuthenticationPGPSSHKeyObject).data.key, ); - case ExtendedAuthMethods.SECURITY_KEY: + case ExtendedAuthMethods.WEBAUTHN: return false; case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.EMAIL: diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts index 23f5cac4..396b292a 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/delete.ts @@ -3,7 +3,7 @@ import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); async function userWebAuthnActionDeleteKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts index 223ca95c..1cce6711 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/get.ts @@ -3,7 +3,7 @@ import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); async function userWebAuthnActionGetKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index cadcc162..eaf34129 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -7,7 +7,7 @@ import config from '../../../../../../../../resources/config'; import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1/session'; import crypto from 'crypto'; -const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts index f8381f28..d24bc960 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/put.ts @@ -3,7 +3,7 @@ import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); +const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); async function userWebAuthnActionPutKey(req: FastifyRequest, rep: FastifyReply): Promise { const user = await getUserFromActionRequest(req); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts index a02abb09..16b83e18 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts @@ -14,7 +14,7 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do return; } - const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.SECURITY_KEY); + const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); const securityKeys = await getPrismaClient().authentication.findMany({ where: { From 340de33fb428495932eb951b80e1dc999a72d92b Mon Sep 17 00:00:00 2001 From: Baw-Appie Date: Wed, 6 Jul 2022 12:27:32 +0900 Subject: [PATCH 38/95] [Admin] Fix Routing --- src/routes/v1/admin/users/phones.ts | 50 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/routes/v1/admin/users/phones.ts b/src/routes/v1/admin/users/phones.ts index 52a745be..b798ae80 100644 --- a/src/routes/v1/admin/users/phones.ts +++ b/src/routes/v1/admin/users/phones.ts @@ -209,37 +209,37 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, isPrimary: typeof body.isPrimary === 'boolean' ? body.isPrimary : undefined, }, }); + }); - app.delete('/', async (req, rep) => { - const phoneId = (req.params as { phoneId: string }).phoneId; + app.delete('/', async (req, rep) => { + const phoneId = (req.params as { phoneId: string }).phoneId; - const phone = await getPrismaClient().phone.findFirst({ - where: { - user: { - id: uuid, - }, - id: phoneId, + const phone = await getPrismaClient().phone.findFirst({ + where: { + user: { + id: uuid, }, - }); + id: phoneId, + }, + }); - if (phone === null) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); - return; - } + if (phone === null) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND); + return; + } - if (phone.isPrimary) { - throw new Meiling.V1.Error.MeilingError( - Meiling.V1.Error.ErrorType.CONFLICT, - 'you should assign new primary number before deleting it', - ); - return; - } + if (phone.isPrimary) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.CONFLICT, + 'you should assign new primary number before deleting it', + ); + return; + } - await getPrismaClient().phone.delete({ - where: { - id: phoneId, - }, - }); + await getPrismaClient().phone.delete({ + where: { + id: phoneId, + }, }); }); From f85f670700e27071eeaf665d7a52b64ac9a1a364 Mon Sep 17 00:00:00 2001 From: Baw-Appie Date: Wed, 6 Jul 2022 12:29:04 +0900 Subject: [PATCH 39/95] [Admin] Add uuid parameter --- src/routes/v1/admin/users/phones.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/v1/admin/users/phones.ts b/src/routes/v1/admin/users/phones.ts index b798ae80..ebac1400 100644 --- a/src/routes/v1/admin/users/phones.ts +++ b/src/routes/v1/admin/users/phones.ts @@ -212,6 +212,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, }); app.delete('/', async (req, rep) => { + const uuid = (req.params as { uuid: string }).uuid; const phoneId = (req.params as { phoneId: string }).phoneId; const phone = await getPrismaClient().phone.findFirst({ From 138ed0c493c42590b32bb30ad6ebef2240ae6eee Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 7 Jul 2022 20:38:43 +0900 Subject: [PATCH 40/95] chore: mitigated potential prisma query injection and prototype pollution vuln Co-Authored-By: kjsman --- src/common/meiling/authentication/token.ts | 1 + src/common/meiling/identity/user.ts | 16 +++++++++++++++- src/common/meiling/oauth2/client.ts | 4 ++++ src/common/meiling/v1/session.ts | 2 ++ src/common/utils.ts | 3 +++ src/routes/v1/admin/users/emails.ts | 4 ++++ src/routes/v1/admin/users/phones.ts | 4 +++- src/routes/v1/meiling/authentication/issue.ts | 2 +- src/routes/v1/meiling/authentication/verify.ts | 5 +++++ src/routes/v1/meiling/index.ts | 1 + src/routes/v1/meiling/lost-password.ts | 12 ++++++++++-- .../v1/meiling/users/actions/apps/index.ts | 3 +++ src/routes/v1/meiling/users/actions/apps/post.ts | 6 +++++- .../users/actions/phones/actions/index.ts | 1 + src/routes/v1/oauth2/common.ts | 8 ++++++++ src/routes/v1/oauth2/device/code.ts | 11 ++++++++++- src/routes/v1/oauth2/token/authorization_code.ts | 11 +++++++++-- src/routes/v1/oauth2/token/device_code.ts | 2 +- src/routes/v1/oauth2/token/refresh_token.ts | 2 +- src/routes/v1/oauth2/tokeninfo/index.ts | 6 +++--- 20 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/common/meiling/authentication/token.ts b/src/common/meiling/authentication/token.ts index bfeeac7d..18bf5289 100644 --- a/src/common/meiling/authentication/token.ts +++ b/src/common/meiling/authentication/token.ts @@ -136,6 +136,7 @@ export async function getAuthorizedPermissions( } export async function getData(token: string, type?: OAuthTokenType): Promise { + if (typeof token !== 'string') return undefined; const tokenData = await getPrismaClient().oAuthToken.findUnique({ where: { token, diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 38515185..8020c444 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -346,6 +346,7 @@ export function sanitizeMetadata(metadata?: any, _scopes: string[] | boolean = [ } export async function checkPassword(user: UserModel | string, password: string) { + if (typeof password !== 'string') return []; const passwords = await getPasswords(user); const passwordCheckPromise = passwords.map(async (passwordDB) => { @@ -394,6 +395,7 @@ export async function hasAuthorizedClient(user: UserModel | string, clientId: st } export async function getClientAuthorizations(user: UserModel | string, clientId?: string) { + if (clientId && typeof clientId !== 'string') return undefined; const authorizations = await getPrismaClient().oAuthClientAuthorization.findMany({ where: { userId: getUserId(user), @@ -426,6 +428,7 @@ export async function getClientAuthorizedPermissions(user: UserModel | string, c } export async function findByUsername(username: string): Promise { + if (typeof username !== 'string') return []; return await getPrismaClient().user.findMany({ where: { username: username.toLowerCase(), @@ -434,6 +437,8 @@ export async function findByUsername(username: string): Promise { } export async function findByEmail(email: string, verified: boolean | undefined = true): Promise { + if (typeof email !== 'string') return []; + const emails = await getPrismaClient().email.findMany({ where: { email: email.toLowerCase(), @@ -474,6 +479,8 @@ export async function findByCommonUsername(username: string): Promise n.phone === phone); diff --git a/src/common/meiling/oauth2/client.ts b/src/common/meiling/oauth2/client.ts index 6d27fbb6..2746b37a 100644 --- a/src/common/meiling/oauth2/client.ts +++ b/src/common/meiling/oauth2/client.ts @@ -14,6 +14,8 @@ import { getPrismaClient } from '../../../resources/prisma'; import { ClientACLRules, getAccessControlRules } from './clientAccessControls'; export async function getByClientId(clientId: string): Promise { + if (typeof clientId !== 'string') return null; + const client = await getPrismaClient().oAuthClient.findFirst({ where: { id: clientId, @@ -24,6 +26,8 @@ export async function getByClientId(clientId: string): Promise { + if (typeof clientId !== 'string') return []; + const owners = await getPrismaClient().user.findMany({ where: { ownedClients: { diff --git a/src/common/meiling/v1/session.ts b/src/common/meiling/v1/session.ts index 4ef6e31b..d9aca920 100644 --- a/src/common/meiling/v1/session.ts +++ b/src/common/meiling/v1/session.ts @@ -83,6 +83,8 @@ export async function garbageCollect(): Promise { } export async function isValid(token: string): Promise { + if (typeof token !== 'string') return false; + let matchedToken: MeilingSessionV1Token | MeilingV1TokenData | null; if (config.session.v1.storage) { const matchedTokens = tokenSessions.issuedTokens.filter((t) => t.token === token); diff --git a/src/common/utils.ts b/src/common/utils.ts index 0c33584d..3181ca62 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -39,6 +39,7 @@ export function isNotBlank(...values: (string | undefined | null)[]): boolean { let isValid = true; for (const value of values) { if (!value) return false; + if (typeof value !== 'string') return false; isValid = isValid && !(value === undefined || value === null || value === '' || value.trim().length === 0); if (!isValid) return false; @@ -108,6 +109,8 @@ export function isValidPassword(password: string): boolean { } export function isValidEmail(email: string): boolean { + if (typeof email !== 'string') return false; + emailRegex.lastIndex = 0; return emailRegex.test(email); } diff --git a/src/routes/v1/admin/users/emails.ts b/src/routes/v1/admin/users/emails.ts index 67c48125..ece3788f 100644 --- a/src/routes/v1/admin/users/emails.ts +++ b/src/routes/v1/admin/users/emails.ts @@ -35,10 +35,14 @@ const userEmailsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions if (typeof body.isVerified === 'string') { body.isVerified = /^true$/gi.test(body.isVerified); + } else if (typeof body.isVerified === 'object') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); } if (typeof body.isPrimary === 'string') { body.isPrimary = /^true$/gi.test(body.isPrimary); + } else if (typeof body.isVerified === 'object') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); } const email = body.email.trim(); diff --git a/src/routes/v1/admin/users/phones.ts b/src/routes/v1/admin/users/phones.ts index ebac1400..8ead1a4a 100644 --- a/src/routes/v1/admin/users/phones.ts +++ b/src/routes/v1/admin/users/phones.ts @@ -36,6 +36,8 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions if (typeof body.isPrimary === 'string') { body.isPrimary = /^true$/gi.test(body.isPrimary); + } else if (typeof body.isPrimary === 'object') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); } const phone = libPhoneNumberJs(body.phone); @@ -99,7 +101,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions }, }, phone: phone.formatInternational(), - isPrimary: body.isPrimary || false, + isPrimary: body.isPrimary ? true : false, }, }); diff --git a/src/routes/v1/meiling/authentication/issue.ts b/src/routes/v1/meiling/authentication/issue.ts index cedd5af8..8ad67a90 100644 --- a/src/routes/v1/meiling/authentication/issue.ts +++ b/src/routes/v1/meiling/authentication/issue.ts @@ -27,7 +27,7 @@ export async function meilingV1SessionAuthnIssueHandler(req: FastifyRequest, rep const createdAt = new Date(); const challenge = Meiling.Authentication.Token.generateToken(6, '0123456789'); - const lang = body.lang ? body.lang : 'ko'; + const lang = body.lang && typeof body.lang === 'string' ? body.lang : 'ko'; try { if (body.type === 'email') { diff --git a/src/routes/v1/meiling/authentication/verify.ts b/src/routes/v1/meiling/authentication/verify.ts index ed4ff81b..f9f33192 100644 --- a/src/routes/v1/meiling/authentication/verify.ts +++ b/src/routes/v1/meiling/authentication/verify.ts @@ -54,6 +54,8 @@ export async function meilingV1SessionAuthnVerifyHandler(req: FastifyRequest, re const token = (body as MeilingV1EmailVerificationTokenQuery).token; if (code) { + if (typeof code !== 'string') throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + if (!session.authenticationStatus.email) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED); return; @@ -62,6 +64,9 @@ export async function meilingV1SessionAuthnVerifyHandler(req: FastifyRequest, re verified = session.authenticationStatus.email.challenge.challenge == code; createdAt = session.authenticationStatus.email.challenge.challengeCreatedAt; } else if (token) { + if (typeof token !== 'string') + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + const data = await getPrismaClient().meilingV1Verification.findUnique({ where: { token, diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index f9634f3b..b00882e6 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -83,6 +83,7 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, } (req as FastifyRequestWithSession).session = session; + Object.freeze(session); }); app.addSchema({ diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 2fcc1dae..da7e4e9a 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -19,6 +19,10 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply } if (body.password) { + if (typeof body.password !== 'string') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + } + if (!session.passwordReset?.isVerified || !session.passwordReset.passwordResetUser) { throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED, @@ -55,8 +59,8 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply const username = body?.context?.username; - if (!username) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'username is missing'); + if (!username || typeof username !== 'string') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'username is invalid'); return; } @@ -90,6 +94,10 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply return; } + if (typeof body.method !== 'string') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid method'); + } + if (!body.data?.challengeResponse) { const methods = await Meiling.V1.User.getAvailableExtendedAuthenticationMethods(user, 'password_reset'); diff --git a/src/routes/v1/meiling/users/actions/apps/index.ts b/src/routes/v1/meiling/users/actions/apps/index.ts index a50c8952..a6f42a8c 100644 --- a/src/routes/v1/meiling/users/actions/apps/index.ts +++ b/src/routes/v1/meiling/users/actions/apps/index.ts @@ -54,6 +54,9 @@ export function userAppsActionsPlugin(app: FastifyInstance, opts: FastifyPluginO }; (req as MeilingV1ClientRequest).client = client; + + Object.freeze((req as MeilingV1ClientRequest).status); + Object.freeze((req as MeilingV1ClientRequest).client); }); app.get('/', appGetHandler); diff --git a/src/routes/v1/meiling/users/actions/apps/post.ts b/src/routes/v1/meiling/users/actions/apps/post.ts index f6b5c57c..0473107a 100644 --- a/src/routes/v1/meiling/users/actions/apps/post.ts +++ b/src/routes/v1/meiling/users/actions/apps/post.ts @@ -25,7 +25,7 @@ async function appCreateHandler(req: FastifyRequest, rep: FastifyReply): Promise return; } - if (!Utils.isValidValue(body?.name, body?.image, body?.privacy, body?.terms, body?.accessControl?.permissions)) { + if (!Utils.isNotBlank(body?.name, body?.image, body?.privacy, body?.terms)) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); return; } @@ -48,6 +48,10 @@ async function appCreateHandler(req: FastifyRequest, rep: FastifyReply): Promise const permissionsPromises = []; for (const permission of permissions) { + if (typeof permission !== 'string') { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + } + permissionsPromises.push( await getPrismaClient().permission.findUnique({ where: { diff --git a/src/routes/v1/meiling/users/actions/phones/actions/index.ts b/src/routes/v1/meiling/users/actions/phones/actions/index.ts index ee3b2a79..70e93b53 100644 --- a/src/routes/v1/meiling/users/actions/phones/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/phones/actions/index.ts @@ -29,6 +29,7 @@ function userPhoneActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, } (req as any).phone = matchingPhone; + Object.freeze((req as any).phone); }); app.get('/', async (req, rep) => { diff --git a/src/routes/v1/oauth2/common.ts b/src/routes/v1/oauth2/common.ts index 578e85a4..29f79ff0 100644 --- a/src/routes/v1/oauth2/common.ts +++ b/src/routes/v1/oauth2/common.ts @@ -60,6 +60,14 @@ export function parseClientInfo(req: FastifyRequest): clientId = body.client_id; clientSecret = body.client_secret; + + if (typeof clientId !== 'string') { + clientId = undefined; + } + + if (typeof clientSecret !== 'string') { + clientSecret = undefined; + } } if (clientId) { diff --git a/src/routes/v1/oauth2/device/code.ts b/src/routes/v1/oauth2/device/code.ts index 17861550..50243170 100644 --- a/src/routes/v1/oauth2/device/code.ts +++ b/src/routes/v1/oauth2/device/code.ts @@ -22,7 +22,7 @@ export async function meilingV1OAuth2DeviceCodeHandler(req: FastifyRequest, rep: const body = req.body as DeviceCodeRequestBody; const type = 'DEVICE_CODE'; - if (!Utils.isValidValue(body, clientId, body.scope)) { + if (!Utils.isValidValue(body, clientId, body.scope) && Utils.isNotBlank(clientId)) { Meiling.OAuth2.Error.sendOAuth2Error(rep, Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST); return; } @@ -46,6 +46,15 @@ export async function meilingV1OAuth2DeviceCodeHandler(req: FastifyRequest, rep: }, }; + if (typeof body.scope !== 'string') { + Meiling.OAuth2.Error.sendOAuth2Error( + rep, + Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, + 'scope is not a valid string', + ); + return; + } + // check permissions are valid or not const scopes = Utils.getUnique(body.scope.split(' '), (m, n) => m === n); diff --git a/src/routes/v1/oauth2/token/authorization_code.ts b/src/routes/v1/oauth2/token/authorization_code.ts index ec1115fb..f60fb9f4 100644 --- a/src/routes/v1/oauth2/token/authorization_code.ts +++ b/src/routes/v1/oauth2/token/authorization_code.ts @@ -27,8 +27,7 @@ export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: F return; } - // check token is valid - if (!Utils.isValidValue(token)) { + if (typeof token !== 'string') { Meiling.OAuth2.Error.sendOAuth2Error(rep, Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, 'invalid token'); return; } @@ -99,6 +98,14 @@ export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: F const challenge = metadataV1.options.code_challenge; if (body.code_verifier) { const code_verifier = body.code_verifier; + if (typeof code_verifier !== 'string') { + return Meiling.OAuth2.Error.sendOAuth2Error( + rep, + Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, + 'invalid code_verifier', + ); + } + if (challenge.method === 'plain') { if (challenge.challenge !== code_verifier) { Meiling.OAuth2.Error.sendOAuth2Error( diff --git a/src/routes/v1/oauth2/token/device_code.ts b/src/routes/v1/oauth2/token/device_code.ts index a24f3903..fc6da308 100644 --- a/src/routes/v1/oauth2/token/device_code.ts +++ b/src/routes/v1/oauth2/token/device_code.ts @@ -27,7 +27,7 @@ export async function oAuth2DeviceCodeHandler(req: FastifyRequest, rep: FastifyR } // check token is valid - if (!Utils.isValidValue(token)) { + if (typeof token !== 'string') { Meiling.OAuth2.Error.sendOAuth2Error(rep, Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, 'invalid token'); return; } diff --git a/src/routes/v1/oauth2/token/refresh_token.ts b/src/routes/v1/oauth2/token/refresh_token.ts index a81546bd..fd02bd99 100644 --- a/src/routes/v1/oauth2/token/refresh_token.ts +++ b/src/routes/v1/oauth2/token/refresh_token.ts @@ -27,7 +27,7 @@ export async function oAuth2RefreshTokenHandler(req: FastifyRequest, rep: Fastif } // check token is valid - if (!Utils.isValidValue(token)) { + if (typeof token !== 'string') { Meiling.OAuth2.Error.sendOAuth2Error(rep, Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, 'invalid token'); return; } diff --git a/src/routes/v1/oauth2/tokeninfo/index.ts b/src/routes/v1/oauth2/tokeninfo/index.ts index eb7ca9ea..324a23ad 100644 --- a/src/routes/v1/oauth2/tokeninfo/index.ts +++ b/src/routes/v1/oauth2/tokeninfo/index.ts @@ -14,11 +14,11 @@ interface OAuth2QueryTokenInfoBody { export async function oAuth2TokenInfoHandler(req: FastifyRequest, rep: FastifyReply): Promise { const body = (req.body ? req.body : req.query) as OAuth2QueryTokenInfoBody; - if (body?.id_token) { + if (typeof body?.id_token === 'string') { await idTokenInfoHandler(body.id_token, rep); - } else if (body?.access_token) { + } else if (typeof body?.access_token === 'string') { await accessTokenInfoHandler(body.access_token, rep); - } else if (body?.refresh_token) { + } else if (typeof body?.refresh_token === 'string') { await refreshTokenInfoHandler(body.refresh_token, rep); } else { Meiling.OAuth2.Error.sendOAuth2Error(rep, Meiling.OAuth2.Error.ErrorType.INVALID_REQUEST, 'missing proper query'); From c816d942d437ad6185b6daf02ad171d7124e2ea3 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 7 Jul 2022 20:50:58 +0900 Subject: [PATCH 41/95] chore: do not convert to other types than string! [Object object] is better. --- src/routes/v1/admin/apps/index.ts | 4 +++- src/routes/v1/admin/sessions/index.ts | 4 +++- src/routes/v1/admin/users/index.ts | 8 ++++++-- src/routes/v1/admin/users/sessions.ts | 4 +++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/admin/apps/index.ts b/src/routes/v1/admin/apps/index.ts index 2dd9b2a2..dd940d23 100644 --- a/src/routes/v1/admin/apps/index.ts +++ b/src/routes/v1/admin/apps/index.ts @@ -12,7 +12,9 @@ function queryBuilder(query: string) { const appsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { app.get('/', async (req, rep) => { - const { query, pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + let { query } = (req.query as any) || {}; + const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + if (typeof query !== 'string') query = query.toString(); const paginationDetails: { skip?: number; diff --git a/src/routes/v1/admin/sessions/index.ts b/src/routes/v1/admin/sessions/index.ts index 1c91c438..2a1110fe 100644 --- a/src/routes/v1/admin/sessions/index.ts +++ b/src/routes/v1/admin/sessions/index.ts @@ -21,7 +21,9 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, return; } - const { query, pageSize = 20, page = 1 } = (req.query as any) || {}; + let { query } = (req.query as any) || {}; + const { pageSize = 20, page = 1 } = (req.query as any) || {}; + if (typeof query !== 'string') query = query.toString(); const paginationDetails: { skip?: number; diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index 283dff2d..aad9cc18 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -56,7 +56,9 @@ const queryBuilder = (query: string) => ({ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { app.get('/', async (req, rep) => { - const { query, pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + let { query } = (req.query as any) || {}; + const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + if (typeof query !== 'string') query = query.toString(); const paginationDetails: { skip?: number; @@ -130,7 +132,9 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don }); app.get('/count', async (req, rep) => { - const { query, rawQuery = false } = (req.query as any) || {}; + let { query } = (req.query as any) || {}; + const { rawQuery = false } = (req.query as any) || {}; + if (typeof query === 'number') query = query.toString(); let prismaQuery = undefined; diff --git a/src/routes/v1/admin/users/sessions.ts b/src/routes/v1/admin/users/sessions.ts index 77d1d642..0efb8ebb 100644 --- a/src/routes/v1/admin/users/sessions.ts +++ b/src/routes/v1/admin/users/sessions.ts @@ -11,7 +11,9 @@ const userSessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptio throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } - const { query, pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + let { query } = (req.query as any) || {}; + const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; + if (typeof query !== 'string') query = query.toString(); const paginationDetails: { skip?: number; From 0ec30670aa2a2c1715db18c042d96525c6b58a09 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Thu, 7 Jul 2022 21:46:43 +0900 Subject: [PATCH 42/95] fix: `/v1/admin/users/:userId/phones` issue reported by @Baw-Appie --- src/routes/v1/admin/users/phones.ts | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/routes/v1/admin/users/phones.ts b/src/routes/v1/admin/users/phones.ts index 8ead1a4a..b1cfdf98 100644 --- a/src/routes/v1/admin/users/phones.ts +++ b/src/routes/v1/admin/users/phones.ts @@ -14,7 +14,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions app.get('/', async (req, rep) => { const uuid = (req.params as { uuid: string }).uuid; - const emails = await getPrismaClient().email.findMany({ + const phones = await getPrismaClient().phone.findMany({ where: { user: { id: uuid, @@ -22,7 +22,7 @@ const userPhonesAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions }, }); - rep.send(emails); + rep.send(phones); }); app.post('/', async (req, rep) => { @@ -143,7 +143,7 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, isPrimary?: boolean; }; - const phone = await getPrismaClient().phone.findFirst({ + let phone = await getPrismaClient().phone.findFirst({ where: { user: { id: uuid, @@ -211,13 +211,23 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, isPrimary: typeof body.isPrimary === 'boolean' ? body.isPrimary : undefined, }, }); + + phone = await getPrismaClient().phone.findFirst({ + where: { + user: { + id: uuid, + }, + id: phoneId, + }, + }); + rep.send(phone); }); app.delete('/', async (req, rep) => { const uuid = (req.params as { uuid: string }).uuid; const phoneId = (req.params as { phoneId: string }).phoneId; - const phone = await getPrismaClient().phone.findFirst({ + let phone = await getPrismaClient().phone.findFirst({ where: { user: { id: uuid, @@ -244,6 +254,16 @@ const userPhoneAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, id: phoneId, }, }); + + phone = await getPrismaClient().phone.findFirst({ + where: { + user: { + id: uuid, + }, + id: phoneId, + }, + }); + rep.send({ success: true }); }); done(); From 5a58261b17f24fdf241e7f3ee541ebc0399a9da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Mon, 18 Jul 2022 00:22:25 +0900 Subject: [PATCH 43/95] chore: includeDeleted true --- src/routes/v1/admin/users/index.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index aad9cc18..939f23d5 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -94,7 +94,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don rep.send( await Promise.all( users.map(async (user) => { - return await Meiling.Identity.User.getDetailedInfo(user); + return await Meiling.Identity.User.getDetailedInfo(user, { includeDeleted: true }); }), ), ); @@ -128,7 +128,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don }, }); - rep.send(await Meiling.Identity.User.getDetailedInfo(user)); + rep.send(await Meiling.Identity.User.getDetailedInfo(user, { includeDeleted: true })); }); app.get('/count', async (req, rep) => { @@ -169,7 +169,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done app.addHook('onRequest', async (req, rep) => { const uuid = (req.params as { uuid: string }).uuid; - const user = await Meiling.Identity.User.getDetailedInfo(uuid); + const user = await Meiling.Identity.User.getDetailedInfo(uuid, { includeDeleted: true }); if (!user) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } @@ -178,7 +178,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done app.get('/', async (req, rep) => { const uuid = (req.params as { uuid: string }).uuid; - const user = await Meiling.Identity.User.getDetailedInfo(uuid); + const user = await Meiling.Identity.User.getDetailedInfo(uuid, { includeDeleted: true }); if (!user) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } @@ -192,7 +192,7 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done const uuid = (req.params as { uuid: string }).uuid; const body = req.body as any; - const user = await Meiling.Identity.User.getInfo(uuid); + const user = await Meiling.Identity.User.getInfo(uuid, { includeDeleted: true }); if (!user) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_FOUND, 'User was not found'); } From c68c93ef034038f0e58554d8b1dd884159795a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Mon, 18 Jul 2022 08:14:42 +0900 Subject: [PATCH 44/95] chore: recurse queryOptions --- src/common/meiling/identity/user.ts | 50 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 8020c444..7e672fab 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -83,17 +83,17 @@ export async function getBasicInfo( const deletedQuery = queryOptions?.includeDeleted ? {} : { - OR: [ - { - deletedAt: null, - }, - { - deletedAt: { - gte: new Date(), - }, + OR: [ + { + deletedAt: null, + }, + { + deletedAt: { + gte: new Date(), }, - ], - }; + }, + ], + }; const prismaQuery = { ...deletedQuery, }; @@ -156,7 +156,7 @@ export async function getDetailedInfo( const baseUser = await getInfo(user, queryOptions); if (!baseUser) return; - const [authorizedAppsRaw, ownedAppsRaw] = await Promise.all([getAuthorizedApps(user), getOwnedApps(user)]); + const [authorizedAppsRaw, ownedAppsRaw] = await Promise.all([getAuthorizedApps(user, queryOptions), getOwnedApps(user, queryOptions)]); if (!authorizedAppsRaw || !ownedAppsRaw) return; @@ -172,8 +172,11 @@ export async function getDetailedInfo( return userObj; } -export async function getAuthorizedApps(user: UserModel | string): Promise { - const baseUser = await getInfo(user); +export async function getAuthorizedApps( + user: UserModel | string, + queryOptions?: UserQueryOptions, +): Promise { + const baseUser = await getInfo(user, queryOptions); if (!baseUser) return; const authRaw = await getPrismaClient().oAuthClientAuthorization.findMany({ @@ -191,8 +194,11 @@ export async function getAuthorizedApps(user: UserModel | string): Promise n !== null) as OAuthClient[]; } -export async function getOwnedApps(user: UserModel | string): Promise { - const baseUser = await getInfo(user); +export async function getOwnedApps( + user: UserModel | string, + queryOptions?: UserQueryOptions, +): Promise { + const baseUser = await getInfo(user, queryOptions); if (!baseUser) return; const raw = await getPrismaClient().oAuthClient.findMany({ @@ -452,10 +458,10 @@ export async function findByEmail(email: string, verified: boolean | undefined = n.userId === undefined || n.userId === null ? undefined : getPrismaClient().user.findFirst({ - where: { - id: n.userId, - }, - }), + where: { + id: n.userId, + }, + }), ) .filter((n) => n !== undefined && n !== null); @@ -738,9 +744,9 @@ export async function createIDToken( const key = config.openid.jwt.privateKey.passphrase !== undefined ? { - key: config.openid.jwt.privateKey.key, - passphrase: config.openid.jwt.privateKey.passphrase, - } + key: config.openid.jwt.privateKey.key, + passphrase: config.openid.jwt.privateKey.passphrase, + } : config.openid.jwt.privateKey.key; // edge case handling From 25f53b0488f63e2ab04fe03984090f4055db6080 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 03:50:50 +0000 Subject: [PATCH 45/95] chore: let-za-go --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index be9538f7..6107eeff 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "author": "Alex4386 ", "license": "MIT", "dependencies": { - "@prisma/client": "^3.9.2", + "@prisma/client": "4", "@xmldom/xmldom": "^0.8.0", "ansi-regex": "^6.0.1", "axios": "^0.21.2", @@ -51,7 +51,7 @@ "husky": "^4.3.0", "lint-staged": "^10.5.1", "prettier": "^2.1.2", - "prisma": "^3.9.2", + "prisma": "4", "ts-node": "^9.0.0" }, "scripts": { diff --git a/yarn.lock b/yarn.lock index 930330a2..e6e55691 100644 --- a/yarn.lock +++ b/yarn.lock @@ -124,22 +124,22 @@ tslib "^2.4.0" webcrypto-core "^1.7.4" -"@prisma/client@^3.9.2": - version "3.11.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.11.1.tgz#bde6dec71ae133d04ce1c6658e3d76627a3c6dc7" - integrity sha512-B3C7zQG4HbjJzUr2Zg9UVkBJutbqq9/uqkl1S138+keZCubJrwizx3RuIvGwI+s+pm3qbsyNqXiZgL3Ir0fSng== +"@prisma/client@4": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.1.1.tgz#dcb1118397deb8247fbe39a1f3eee5606648adf8" + integrity sha512-2pXuIUYxHv5H9o6QTa1VIsl4yMgsAjKQOitlo8WVTB+vo73rmMJITBPavdGUZSWUc7adMkFzEV3y5rVTUQr77Q== dependencies: - "@prisma/engines-version" "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" + "@prisma/engines-version" "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8" -"@prisma/engines-version@3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9": - version "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz#81a1835b495ad287ad7824dbd62f74e9eee90fb9" - integrity sha512-HkcsDniA4iNb/gi0iuyOJNAM7nD/LwQ0uJm15v360O5dee3TM4lWdSQiTYBMK6FF68ACUItmzSur7oYuUZ2zkQ== +"@prisma/engines-version@4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8": + version "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8.tgz#ce00e6377126e491a8b1e0e2039c97e2924bd6d9" + integrity sha512-cRRJwpHFGFJZvtHbY3GZjMffNBEjjZk68ztn+S2hDgPCGB4H66IK26roK94GJxBodSehwRJ0wGyebC2GoIH1JQ== -"@prisma/engines@3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9": - version "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz#09ac23f8f615a8586d8d44538060ada199fe872c" - integrity sha512-MILbsGnvmnhCbFGa2/iSnsyGyazU3afzD7ldjCIeLIGKkNBMSZgA2IvpYsAXl+6qFHKGrS3B2otKfV31dwMSQw== +"@prisma/engines@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.1.1.tgz#a6a75870618bbd19ff734c51af7dbe9f362c3265" + integrity sha512-DCw8L/SS0IXqmj5IW/fMxOXiifnsfjBzDfRhf0j3NFWqvMCh9OtfjmXQZxVgI2mwvJLc/5jzXhkiWT39qS09dA== "@sindresorhus/is@^0.14.0": version "0.14.0" @@ -2774,12 +2774,12 @@ prettier@^2.1.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== -prisma@^3.9.2: - version "3.11.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.11.1.tgz#fff9c0bcf83cb30c2e1d650882d5eb3c5565e028" - integrity sha512-aYn8bQwt1xwR2oSsVNHT4PXU7EhsThIwmpNB/MNUaaMx5OPLTro6VdNJe/sJssXFLxhamfWeMjwmpXjljo6xkg== +prisma@4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.1.1.tgz#41c2e19896357f484ef21567165d762908376fca" + integrity sha512-yw50J8If2dKP4wYIi695zthsCASQFHiogGvUHHWd3falx/rpsD6Sb1LMLRV9nO3iGG3lozxNJ2PSINxK7xwdpg== dependencies: - "@prisma/engines" "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9" + "@prisma/engines" "4.1.1" process-warning@^1.0.0: version "1.0.0" From 08adb8e8c832dea2c8b1aaadadb5bed5292d5663 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 04:15:52 +0000 Subject: [PATCH 46/95] chore: bump up deps version --- package.json | 10 +- src/common/meiling/identity/user.ts | 39 +-- yarn.lock | 363 +++++++++++----------------- 3 files changed, 173 insertions(+), 239 deletions(-) diff --git a/package.json b/package.json index be9538f7..d0978753 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "pino-pretty": "^4.3.0", "prompts": "^2.4.1", "speakeasy": "^2.0.0", - "typescript": "^4.5.5" + "typescript": "^4.7.4" }, "devDependencies": { "@swc/cli": "^0.1.51", @@ -42,10 +42,10 @@ "@types/node": "^14.14.7", "@types/openpgp": "^4.4.14", "@types/speakeasy": "^2.0.5", - "@typescript-eslint/eslint-plugin": "^4.7.0", - "@typescript-eslint/parser": "^4.7.0", - "@typescript-eslint/typescript-estree": "^5.11.0", - "eslint": "^7.13.0", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "@typescript-eslint/typescript-estree": "^5.0.0", + "eslint": "^8.0.0", "eslint-config-prettier": "^6.15.0", "eslint-plugin-prettier": "^3.1.4", "husky": "^4.3.0", diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 7e672fab..046a331e 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -83,17 +83,17 @@ export async function getBasicInfo( const deletedQuery = queryOptions?.includeDeleted ? {} : { - OR: [ - { - deletedAt: null, - }, - { - deletedAt: { - gte: new Date(), + OR: [ + { + deletedAt: null, }, - }, - ], - }; + { + deletedAt: { + gte: new Date(), + }, + }, + ], + }; const prismaQuery = { ...deletedQuery, }; @@ -156,7 +156,10 @@ export async function getDetailedInfo( const baseUser = await getInfo(user, queryOptions); if (!baseUser) return; - const [authorizedAppsRaw, ownedAppsRaw] = await Promise.all([getAuthorizedApps(user, queryOptions), getOwnedApps(user, queryOptions)]); + const [authorizedAppsRaw, ownedAppsRaw] = await Promise.all([ + getAuthorizedApps(user, queryOptions), + getOwnedApps(user, queryOptions), + ]); if (!authorizedAppsRaw || !ownedAppsRaw) return; @@ -458,10 +461,10 @@ export async function findByEmail(email: string, verified: boolean | undefined = n.userId === undefined || n.userId === null ? undefined : getPrismaClient().user.findFirst({ - where: { - id: n.userId, - }, - }), + where: { + id: n.userId, + }, + }), ) .filter((n) => n !== undefined && n !== null); @@ -744,9 +747,9 @@ export async function createIDToken( const key = config.openid.jwt.privateKey.passphrase !== undefined ? { - key: config.openid.jwt.privateKey.key, - passphrase: config.openid.jwt.privateKey.passphrase, - } + key: config.openid.jwt.privateKey.key, + passphrase: config.openid.jwt.privateKey.passphrase, + } : config.openid.jwt.privateKey.key; // edge case handling diff --git a/yarn.lock b/yarn.lock index 930330a2..5e1ada42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,13 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.0.0": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" @@ -21,7 +14,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.16.7": version "7.16.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== @@ -30,19 +23,19 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" "@fastify/ajv-compiler@^1.0.0": @@ -62,16 +55,16 @@ resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.0.19.tgz#2052e7370d49df624e7885c92f7ef3f854f15996" integrity sha512-+ZJdUaD9sthgMbdEiYZ5jwiTG/ZtILx0/LSDkdxi/pK/BSmJzIAT+IYuMYSKwjPdGk6odwbJVQ9H8HpepDZy9Q== -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": +"@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== @@ -264,7 +257,7 @@ resolved "https://registry.yarnpkg.com/@types/figlet/-/figlet-1.5.4.tgz#54a426d63e921a9bca44102c5b1b1f206fa56d93" integrity sha512-cskPTju7glYgzvkJy/hftqw7Fen3fsd0yrPOqcbBLJu+YdDQuA438akS1g+2XVKGzsQOnXGV2I9ePv6xUBnKMQ== -"@types/json-schema@^7.0.7": +"@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -305,101 +298,85 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^4.7.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== +"@typescript-eslint/eslint-plugin@^5.0.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe" + integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ== dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/type-utils" "5.31.0" + "@typescript-eslint/utils" "5.31.0" + debug "^4.3.4" functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== +"@typescript-eslint/parser@^5.0.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" + integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" + debug "^4.3.4" -"@typescript-eslint/parser@^4.7.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/types@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f" - integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw== - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" +"@typescript-eslint/scope-manager@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" + integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== + dependencies: + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" + +"@typescript-eslint/type-utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9" + integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w== + dependencies: + "@typescript-eslint/utils" "5.31.0" + debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@^5.11.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488" - integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg== +"@typescript-eslint/types@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" + integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== + +"@typescript-eslint/typescript-estree@5.31.0", "@typescript-eslint/typescript-estree@^5.0.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" + integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== dependencies: - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/visitor-keys" "5.17.0" - debug "^4.3.2" - globby "^11.0.4" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" + debug "^4.3.4" + globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.5" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== +"@typescript-eslint/utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd" + integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg== dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128" - integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA== +"@typescript-eslint/visitor-keys@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" + integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== dependencies: - "@typescript-eslint/types" "5.17.0" - eslint-visitor-keys "^3.0.0" + "@typescript-eslint/types" "5.31.0" + eslint-visitor-keys "^3.3.0" "@xmldom/xmldom@^0.8.0": version "0.8.1" @@ -416,15 +393,15 @@ abstract-logging@^2.0.0: resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.7.1: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== aggregate-error@^3.0.0: version "3.1.0" @@ -444,7 +421,7 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1, ajv@^8.1.0: +ajv@^8.1.0: version "8.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== @@ -515,13 +492,6 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -978,7 +948,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2: +debug@^4.0.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1115,7 +1085,7 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enquirer@^2.3.5, enquirer@^2.3.6: +enquirer@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -1279,12 +1249,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -1293,80 +1264,65 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0: +eslint-visitor-keys@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^7.13.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint@^8.0.0: + version "8.20.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" + integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" + regexpp "^3.2.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -1718,6 +1674,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3, glob@^7.1.4: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -1737,14 +1700,14 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" -globals@^13.6.0, globals@^13.9.0: - version "13.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" - integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== +globals@^13.15.0: + version "13.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== dependencies: type-fest "^0.20.2" -globby@^11.0.3, globby@^11.0.4: +globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -1868,12 +1831,7 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -2053,15 +2011,7 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.0.0: +js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -2269,11 +2219,6 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - log-symbols@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" @@ -2386,7 +2331,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@^3.0.4: +minimatch@^3.0.4, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2786,11 +2731,6 @@ process-warning@^1.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - prompts@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -2890,7 +2830,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regexpp@^3.1.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -3044,13 +2984,20 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@^7.3.2, semver@^7.3.4: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" +semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + send@^0.17.1: version "0.17.2" resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" @@ -3195,11 +3142,6 @@ split2@^3.1.1: dependencies: readable-stream "^3.0.0" -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - sqlstring@^2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" @@ -3231,7 +3173,7 @@ string-similarity@^4.0.1: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3292,17 +3234,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^6.0.9: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" From 3bac9245edfbbe3d2d869dfabf6587d6bf775e43 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 04:24:40 +0000 Subject: [PATCH 47/95] chore: implement user deletion --- src/routes/v1/admin/users/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index 939f23d5..8a776896 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -223,6 +223,8 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done }, }); + const permanent = (req.query as any).permanent === 'true'; + if (user) { await getPrismaClient().user.update({ where: { @@ -259,6 +261,16 @@ const userAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done }), ); + // actually delete if admin requested permanent deletion + // note: this could lead possible uuid collision for other apps. + if (permanent) { + await getPrismaClient().user.delete({ + where: { + id: uuid, + }, + }); + } + rep.send({ success: true }); return; } else { From 093d58a2d30e8d48bd9353e0a24d626a9d269520 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 05:40:32 +0000 Subject: [PATCH 48/95] chore: server side payload --- .../actions/security/webauthn/actions/post.ts | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index eaf34129..b5e691ba 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -18,13 +18,16 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) const session = await getSessionFromRequest(req); - const body = req.body as - | { - hostname: string; - challengeResponse?: AttestationResult; - name?: string; - } - | undefined; + interface RegisterRequest { + hostname: string; + name?: string; + id?: string; + } + + type RegisterProcess = RegisterRequest & AttestationResult; + type RegisterBody = RegisterRequest | RegisterProcess; + + const body = req.body as RegisterBody | undefined; let hostname = body?.hostname; if (!hostname || !Utils.isNotBlank(hostname)) { @@ -38,9 +41,9 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) ); } - const challengeResponse = body?.challengeResponse; + const challengeResponse = body as RegisterProcess; - const registering = challengeResponse !== undefined; + const registering = challengeResponse.response !== undefined; const f2l = new Fido2Lib({}); if (registering && body) { @@ -59,10 +62,14 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) }; try { - const result = await f2l.attestationResult(challengeResponse, attensationExpectations); + const result = await f2l.attestationResult(challengeResponse as AttestationResult, attensationExpectations); + console.log('FIDO Attestation Result', result); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); } catch (e) { // TODO: further debugging required. + console.error('FIDO Attestation Error', e); + throw e; } } else { From 866883f9617c8fb4eb75713c808aa0e89d9ad4b9 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 05:46:57 +0000 Subject: [PATCH 49/95] chore: convert rawId --- .../meiling/users/actions/security/webauthn/actions/post.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index b5e691ba..0b5c0e9b 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -55,6 +55,11 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) if (!Utils.isNotBlank(body.name)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + if (!Utils.checkBase64(challengeResponse.rawId as unknown as string)) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + + challengeResponse.rawId = Buffer.from(challengeResponse.rawId as unknown as string, 'base64'); + const attensationExpectations = { challenge: webAuthnObject.challenge, origin: webAuthnObject.origin, From 790e5354cb1fd1fe58715794feccfbe4d606fc0c Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:00:31 +0000 Subject: [PATCH 50/95] chore: allowedHostnames --- .../users/actions/security/webauthn/actions/post.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 0b5c0e9b..95764f93 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -31,10 +31,13 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) let hostname = body?.hostname; if (!hostname || !Utils.isNotBlank(hostname)) { - hostname = config.frontend.url[0]; + hostname = new URL(config.frontend.url[0]).hostname; } - if (!config.frontend.url.includes(hostname)) { + const allowedHostnames = config.frontend.url.map((n) => new URL(n).hostname); + console.log(allowedHostnames); + + if (!allowedHostnames.includes(hostname)) { throw new Meiling.V1.Error.MeilingError( Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'provided hostname is not supported', @@ -55,11 +58,6 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) if (!Utils.isNotBlank(body.name)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); - if (!Utils.checkBase64(challengeResponse.rawId as unknown as string)) - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); - - challengeResponse.rawId = Buffer.from(challengeResponse.rawId as unknown as string, 'base64'); - const attensationExpectations = { challenge: webAuthnObject.challenge, origin: webAuthnObject.origin, From 31b8b0cf34b249a288bc687cd26bf2fe75390111 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:03:40 +0000 Subject: [PATCH 51/95] chore: webauthn --- .../users/actions/security/webauthn/actions/post.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 95764f93..42b45e12 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -56,7 +56,16 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_GENERATED); if (!Utils.isNotBlank(body.name)) - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'missing webauthn token name', + ); + + if (!Utils.isNotBlank(challengeResponse.id)) + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'malformed challengeResponse', + ); const attensationExpectations = { challenge: webAuthnObject.challenge, @@ -65,6 +74,8 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) }; try { + challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64'); + const result = await f2l.attestationResult(challengeResponse as AttestationResult, attensationExpectations); console.log('FIDO Attestation Result', result); From 38829806408cef433b831903739241d3e278e8c5 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:05:21 +0000 Subject: [PATCH 52/95] chore: return underlying buffer --- .../v1/meiling/users/actions/security/webauthn/actions/post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 42b45e12..c8361ef8 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -74,7 +74,7 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) }; try { - challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64'); + challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64').buffer; const result = await f2l.attestationResult(challengeResponse as AttestationResult, attensationExpectations); console.log('FIDO Attestation Result', result); From d4eff29b6049e947d101dd8d2e89ea627c8be463 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:07:33 +0000 Subject: [PATCH 53/95] chore: challenge mismatch --- .../meiling/users/actions/security/webauthn/actions/post.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index c8361ef8..9da662d9 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -81,6 +81,10 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); } catch (e) { + if ((e as Error).name.includes('clientData challenge mismatch')) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'challenge mismatch'); + } + // TODO: further debugging required. console.error('FIDO Attestation Error', e); From f30df878f6c06444a7debee5d3ff01aaad4bcf94 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:19:17 +0000 Subject: [PATCH 54/95] chore: debug expectation logging --- .../v1/meiling/users/actions/security/webauthn/actions/post.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 9da662d9..63d3249f 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -76,6 +76,8 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) try { challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64').buffer; + console.log('Expecting:', attensationExpectations); + const result = await f2l.attestationResult(challengeResponse as AttestationResult, attensationExpectations); console.log('FIDO Attestation Result', result); From 3533114e0dce10cf1cc956cf76dfc9c19304c50d Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 06:26:22 +0000 Subject: [PATCH 55/95] chore: umm --- .../users/actions/security/webauthn/actions/post.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 63d3249f..c2a68992 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -67,8 +67,10 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) 'malformed challengeResponse', ); - const attensationExpectations = { - challenge: webAuthnObject.challenge, + const attestationExpectations = { + // Note: this should be matched with clientDataJSON. + // basically fido2-lib is only doing string comparison + challenge: Buffer.from(webAuthnObject.challenge).toString('base64url'), origin: webAuthnObject.origin, factor: 'either' as Factor, }; @@ -76,14 +78,14 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) try { challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64').buffer; - console.log('Expecting:', attensationExpectations); + console.log('Expecting:', attestationExpectations); - const result = await f2l.attestationResult(challengeResponse as AttestationResult, attensationExpectations); + const result = await f2l.attestationResult(challengeResponse as AttestationResult, attestationExpectations); console.log('FIDO Attestation Result', result); throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); } catch (e) { - if ((e as Error).name.includes('clientData challenge mismatch')) { + if ((e as Error).message.includes('clientData challenge mismatch')) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'challenge mismatch'); } From e1212e214edcbca9da22ab858f047d8c9302d1d6 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 07:12:29 +0000 Subject: [PATCH 56/95] chore: base64url --- .../v1/meiling/users/actions/security/webauthn/actions/post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index c2a68992..936a2af3 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -76,7 +76,7 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) }; try { - challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64').buffer; + challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64url').buffer; console.log('Expecting:', attestationExpectations); From 9e6d1561d145492762ab63c5c904251bac1910b6 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 07:14:26 +0000 Subject: [PATCH 57/95] chore: bump up fido2-lib --- package.json | 2 +- yarn.lock | 253 ++++++++++++++++++--------------------------------- 2 files changed, 88 insertions(+), 167 deletions(-) diff --git a/package.json b/package.json index f4a75e5e..64913dec 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "fastify-formbody": "^5.0.0", "fastify-secure-session": "^2.3.0", "fastify-swagger": "^4.15.0", - "fido2-lib": "^3.1.7", + "fido2-lib": "3.2.5", "figlet": "^1.5.0", "jsonwebtoken": "^8.5.1", "libphonenumber-js": "^1.9.49", diff --git a/yarn.lock b/yarn.lock index 519c432f..5e5c597d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,36 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@cbor-extract/cbor-extract-darwin-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76" + integrity sha512-jebtLrruvsBbGMsUn0QxZW/8Z7caS9OkszVKZ64WTWajUkyohmolUdKL2nbfaTyyi3ABJrxVNM4YO1pvMsNI1g== + +"@cbor-extract/cbor-extract-darwin-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.0.0.tgz#7bc01e7911b97eee4c78ae074bd3108f2ff208c3" + integrity sha512-LGYjdlyqANBqCDzBujCqXpPcK70rvaQgw98/aquzBuEmK0KXS7i579CoVG1yS/eb3bMqiVPevBri45jbR6Tlsg== + +"@cbor-extract/cbor-extract-linux-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.0.0.tgz#e40608afed5f373091560fa9dcd19c7f52f510b0" + integrity sha512-c1rbQcSF01yVgbG60zEfHNsUkXiEEQRNdYqm5qpqEAkLx4gA6DDU91IQbalkqXfwDuQzcMovOc1TC3uJJIi2OQ== + +"@cbor-extract/cbor-extract-linux-arm@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.0.0.tgz#f52a7580fb23e305370e66ae9ff136de3729c4b8" + integrity sha512-cOGHEIif5rPbpix6qhpuatrZzm6HeC5rT0nXt8ynLTc7PzfXmovswD9x6d9h5NcHswkV5y3PbkNbpel/tLADYg== + +"@cbor-extract/cbor-extract-linux-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.0.0.tgz#8c936b8a93f915bf3c2459d5b4b78d244bda0f26" + integrity sha512-WYeE1b5WGf9pbbQH3qeNBXq710gGsuVFUiP148RY8In+2pCp/fxjBpe701ngam9/fF5D+gJs8B1i5wv/PN7JZA== + +"@cbor-extract/cbor-extract-win32-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.0.0.tgz#4d4ad91527a8313c3db1e2167a8821dfae9d6211" + integrity sha512-XqVuJEnE0jpl/RkuSp04FF2UE73gY52Y4nZaIE6j9GAeSH2cHYU5CCd4TaVMDi2M18ZpZv7XhL/k+nneQzyJpQ== + "@eslint/eslintrc@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" @@ -50,10 +80,10 @@ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d" integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg== -"@hexagon/base64@^1.0.19": - version "1.0.19" - resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.0.19.tgz#2052e7370d49df624e7885c92f7ef3f854f15996" - integrity sha512-+ZJdUaD9sthgMbdEiYZ5jwiTG/ZtILx0/LSDkdxi/pK/BSmJzIAT+IYuMYSKwjPdGk6odwbJVQ9H8HpepDZy9Q== +"@hexagon/base64@~1.1.21": + version "1.1.22" + resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.1.22.tgz#ee1dfb8d80e6b4c8ff5480711cdc070f72c5a1f5" + integrity sha512-Yh289WXFCAe1NvrUYG/MWv6fbTFrJ5Wq4F0A9Klbp22RQy7g13FlUqwVqyKfMQ2jFwgN3Jf1Bk6MaOEvhwQVcQ== "@humanwhocodes/config-array@^0.9.2": version "0.9.5" @@ -106,7 +136,7 @@ dependencies: tslib "^2.0.0" -"@peculiar/webcrypto@^1.4.0": +"@peculiar/webcrypto@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz#f941bd95285a0f8a3d2af39ccda5197b80cd32bf" integrity sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg== @@ -529,7 +559,7 @@ asn1@^0.2.4: dependencies: safer-buffer "~2.1.0" -asn1js@^3.0.1, asn1js@^3.0.2, asn1js@^3.0.4, asn1js@^3.0.5: +asn1js@^3.0.1, asn1js@^3.0.4, asn1js@^3.0.5, asn1js@~3.0.2: version "3.0.5" resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== @@ -696,22 +726,26 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -cbor-extract@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-1.0.0.tgz#e6c793adc166d7661a0a59b8bf5433b98e202ab9" - integrity sha512-2y71EsPT4dJjtS24JIZfzUodm7kNrJJouIL7U4YiO1bl5QJyCHz9j810x/d+A/L+1BWQCE0771TiBrVmDL0MOA== - dependencies: - nan "^2.14.2" - node-gyp-build "^4.2.3" - -cbor-x@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.2.1.tgz#b621972873a91f9dfd2c905f8b008e4796972958" - integrity sha512-vUgwxN/hCyMUuFsYaMTYhfpK0rwBpGho8CqCLEXSn3tGfaPL3fruB0lrZVGiq1v5EzTrqcrLVxJ2Ul9zqukhMw== +cbor-extract@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-2.0.2.tgz#8e45339627fb8b47071e8e71138c630019125939" + integrity sha512-QoLGEgPff03ad/L66P91ci5Zmf7Woq8bh4H5XT3+D5annlrPH5ObHf2Yvo53eDQaDkQtF9tJwMKSWANGXDmwUA== dependencies: - esbuild "^0.13.15" + node-gyp-build-optional-packages "5.0.3" + optionalDependencies: + "@cbor-extract/cbor-extract-darwin-arm64" "2.0.0" + "@cbor-extract/cbor-extract-darwin-x64" "2.0.0" + "@cbor-extract/cbor-extract-linux-arm" "2.0.0" + "@cbor-extract/cbor-extract-linux-arm64" "2.0.0" + "@cbor-extract/cbor-extract-linux-x64" "2.0.0" + "@cbor-extract/cbor-extract-win32-x64" "2.0.0" + +cbor-x@~1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.3.2.tgz#280a56d93390e01583ad92d78302152beb250421" + integrity sha512-sntNPdI5OaOC+MWfQVHwXmvNJmbNYvwwRPWhoGjISz9yeGYgh7oLsQdo+RMmgLkD+aGsx7z2xHDyrBaBLFNT9w== optionalDependencies: - cbor-extract "^1.0.0" + cbor-extract "^2.0.2" chalk@2.4.2, chalk@^2.0.0: version "2.4.2" @@ -1099,114 +1133,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -esbuild-android-arm64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44" - integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg== - -esbuild-darwin-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72" - integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ== - -esbuild-darwin-arm64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a" - integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ== - -esbuild-freebsd-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85" - integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA== - -esbuild-freebsd-arm64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52" - integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ== - -esbuild-linux-32@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69" - integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g== - -esbuild-linux-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3" - integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA== - -esbuild-linux-arm64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1" - integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA== - -esbuild-linux-arm@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe" - integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA== - -esbuild-linux-mips64le@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7" - integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg== - -esbuild-linux-ppc64le@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2" - integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ== - -esbuild-netbsd-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038" - integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w== - -esbuild-openbsd-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7" - integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g== - -esbuild-sunos-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4" - integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw== - -esbuild-windows-32@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7" - integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw== - -esbuild-windows-64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294" - integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ== - -esbuild-windows-arm64@0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3" - integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA== - -esbuild@^0.13.15: - version "0.13.15" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf" - integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw== - optionalDependencies: - esbuild-android-arm64 "0.13.15" - esbuild-darwin-64 "0.13.15" - esbuild-darwin-arm64 "0.13.15" - esbuild-freebsd-64 "0.13.15" - esbuild-freebsd-arm64 "0.13.15" - esbuild-linux-32 "0.13.15" - esbuild-linux-64 "0.13.15" - esbuild-linux-arm "0.13.15" - esbuild-linux-arm64 "0.13.15" - esbuild-linux-mips64le "0.13.15" - esbuild-linux-ppc64le "0.13.15" - esbuild-netbsd-64 "0.13.15" - esbuild-openbsd-64 "0.13.15" - esbuild-sunos-64 "0.13.15" - esbuild-windows-32 "0.13.15" - esbuild-windows-64 "0.13.15" - esbuild-windows-arm64 "0.13.15" - escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -1531,18 +1457,18 @@ fastq@^1.6.0, fastq@^1.6.1: dependencies: reusify "^1.0.4" -fido2-lib@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/fido2-lib/-/fido2-lib-3.1.7.tgz#64637e449d2c37d8b1dd5dd7ab638ee45962c3b6" - integrity sha512-d/umDGlsSRfexIFMzhTmnf264fLyYoynMYWKVAiMEqoUWVqB1m+JaIJNr14cVSEz3zxEl7ryvRTJI7JIp3+1GA== +fido2-lib@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/fido2-lib/-/fido2-lib-3.2.5.tgz#2682592898e5f50594bcc6788a6ffd7654025e41" + integrity sha512-uDJsf/WNm74uos7baaxbK6vOjIZPOHUhal6FBKgy1ok1y3INI9kfUVkjVs5A7FF5WbUnpqoDEJXmhASZfl7AKw== dependencies: - "@hexagon/base64" "^1.0.19" - "@peculiar/webcrypto" "^1.4.0" - asn1js "^3.0.2" - cbor-x "~1.2.1" - jose "^4.7.0" - pkijs "^3.0.3" - tldts "^5.7.79" + "@hexagon/base64" "~1.1.21" + "@peculiar/webcrypto" "~1.4.0" + asn1js "~3.0.2" + cbor-x "~1.3.1" + jose "~4.8.3" + pkijs "~3.0.5" + tldts "~5.7.82" figlet@^1.5.0: version "1.5.2" @@ -1996,10 +1922,10 @@ jmespath@^0.15.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= -jose@^4.7.0: - version "4.8.1" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.8.1.tgz#dc7c2660b115ba29b44880e588c5ac313c158247" - integrity sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw== +jose@~4.8.3: + version "4.8.3" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.8.3.tgz#5a754fb4aa5f2806608d083f438e6916b11087da" + integrity sha512-7rySkpW78d8LBp4YU70Wb7+OTgE3OwAALNVZxhoIhp4Kscp+p/fBkdpxGAMKxvCAMV4QfXBU9m6l9nX/vGwd2g== joycon@^2.2.5: version "2.2.5" @@ -2384,11 +2310,6 @@ named-placeholders@^1.1.2: dependencies: lru-cache "^4.1.3" -nan@^2.14.2: - version "2.16.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" - integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== - nan@^2.15.0: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" @@ -2406,10 +2327,10 @@ node-fetch@^2.1.2: dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.2.3: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== +node-gyp-build-optional-packages@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" + integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== node-gyp-build@^4.3.0: version "4.3.0" @@ -2679,7 +2600,7 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" -pkijs@^3.0.3: +pkijs@~3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/pkijs/-/pkijs-3.0.5.tgz#64134f45a92633841b2200b2ece01931209a6c56" integrity sha512-J6P30yzU7qSbuJIBaclwN93WbyoxjVlkYMgjQmE9wWkPUTHVu2cH6lkjWcIr2WAub5KH38BA1Eyeb4s9apUPTg== @@ -3249,17 +3170,17 @@ tiny-lru@^8.0.1: resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-8.0.2.tgz#812fccbe6e622ded552e3ff8a4c3b5ff34a85e4c" integrity sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg== -tldts-core@^5.7.81: - version "5.7.81" - resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.7.81.tgz#1beae3fdd959ca9f32a2eb5ac07c4a65a561e65e" - integrity sha512-9i+XjmFvl/eSubippvvxEqIGexT6ALqb7fO3EPQ6yNOMaoRdaDgrMqBCIXSqVY/SckpFm54fksaLVQE6KtlAGA== +tldts-core@^5.7.84: + version "5.7.84" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.7.84.tgz#0e128f7d70c0b91741156e1d3ce072fac687ef2a" + integrity sha512-1qKxwSDjmWdqG81cnXGvKI+FHPiVRT6w5DORjp2+YVqDdzFUZO0oQoWu0zbDtWA6HXVk+B15yY9DKbVKZ6fRLg== -tldts@^5.7.79: - version "5.7.81" - resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.7.81.tgz#a43aff0de062df106dbc9e3a5b18660b3e497044" - integrity sha512-ulFEOSC+mHmkYwWMeX/ys+n7GFxROldJJVrSxSPASuyigTFvAQAGs1eVy82NFxazoEsCfvuCQrSOzdXLKfvR+A== +tldts@~5.7.82: + version "5.7.84" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.7.84.tgz#c22e8824545ece1cac0a909692d12378b39429d1" + integrity sha512-PGkhyObqEEntI/xUDJdagtvNW+O7+5j8vbXSOXL+563At8gH/4LHxHjdPNv7qrahYuL6y6ZgjBxcvWdut7/LtA== dependencies: - tldts-core "^5.7.81" + tldts-core "^5.7.84" to-readable-stream@^1.0.0: version "1.0.0" @@ -3353,10 +3274,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.5.5: - version "4.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" - integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== +typescript@^4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== undefsafe@^2.0.5: version "2.0.5" From bd068a9d0acfd9cd7d914b93215f1cd5c80b0894 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 07:52:48 +0000 Subject: [PATCH 58/95] chore: rpId --- .../users/actions/security/webauthn/actions/post.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 936a2af3..91d9bdaa 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -34,6 +34,14 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) hostname = new URL(config.frontend.url[0]).hostname; } + try { + if (hostname !== new URL('https://' + hostname).hostname) { + throw new Error(); + } + } catch (e) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid hostname'); + } + const allowedHostnames = config.frontend.url.map((n) => new URL(n).hostname); console.log(allowedHostnames); @@ -47,7 +55,9 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) const challengeResponse = body as RegisterProcess; const registering = challengeResponse.response !== undefined; - const f2l = new Fido2Lib({}); + const f2l = new Fido2Lib({ + rpId: 'https://' + hostname, + }); if (registering && body) { const webAuthnObject = session?.registering?.webAuthn; From 6a06e2c4c82656e0cb0fb1bea99cafa58cf082b3 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 08:38:00 +0000 Subject: [PATCH 59/95] chore: just change the module --- package.json | 3 +- .../actions/security/webauthn/actions/post.ts | 30 +-- yarn.lock | 242 +++++++----------- 3 files changed, 112 insertions(+), 163 deletions(-) diff --git a/package.json b/package.json index 64913dec..2578e58e 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "license": "MIT", "dependencies": { "@prisma/client": "4", + "@simplewebauthn/server": "^5.4.0", "@xmldom/xmldom": "^0.8.0", "ansi-regex": "^6.0.1", "axios": "^0.21.2", @@ -19,7 +20,6 @@ "fastify-formbody": "^5.0.0", "fastify-secure-session": "^2.3.0", "fastify-swagger": "^4.15.0", - "fido2-lib": "3.2.5", "figlet": "^1.5.0", "jsonwebtoken": "^8.5.1", "libphonenumber-js": "^1.9.49", @@ -34,6 +34,7 @@ "typescript": "^4.7.4" }, "devDependencies": { + "@simplewebauthn/typescript-types": "^5.4.0", "@swc/cli": "^0.1.51", "@swc/core": "^1.2.138", "@types/bcryptjs": "^2.4.2", diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 91d9bdaa..c7b2c299 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -2,10 +2,11 @@ import { FastifyReply, FastifyRequest } from 'fastify'; import { getUserFromActionRequest } from '../../..'; import { Meiling, Utils } from '../../../../../../../../common'; import { getPrismaClient } from '../../../../../../../../resources/prisma'; -import { AttestationResult, Factor, Fido2Lib } from 'fido2-lib'; import config from '../../../../../../../../resources/config'; import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1/session'; import crypto from 'crypto'; +import SimpleWebAuthnServer from '@simplewebauthn/server'; +import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); @@ -21,10 +22,9 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) interface RegisterRequest { hostname: string; name?: string; - id?: string; } - type RegisterProcess = RegisterRequest & AttestationResult; + type RegisterProcess = RegisterRequest & RegistrationCredentialJSON; type RegisterBody = RegisterRequest | RegisterProcess; const body = req.body as RegisterBody | undefined; @@ -55,9 +55,6 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) const challengeResponse = body as RegisterProcess; const registering = challengeResponse.response !== undefined; - const f2l = new Fido2Lib({ - rpId: 'https://' + hostname, - }); if (registering && body) { const webAuthnObject = session?.registering?.webAuthn; @@ -77,20 +74,15 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) 'malformed challengeResponse', ); - const attestationExpectations = { - // Note: this should be matched with clientDataJSON. - // basically fido2-lib is only doing string comparison - challenge: Buffer.from(webAuthnObject.challenge).toString('base64url'), - origin: webAuthnObject.origin, - factor: 'either' as Factor, - }; - try { - challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64url').buffer; - - console.log('Expecting:', attestationExpectations); - - const result = await f2l.attestationResult(challengeResponse as AttestationResult, attestationExpectations); + if (!challengeResponse.rawId) + challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64url').toString('base64url'); + + const result = await SimpleWebAuthnServer.verifyRegistrationResponse({ + credential: challengeResponse, + expectedChallenge: webAuthnObject.challenge, + expectedOrigin: webAuthnObject.origin, + }); console.log('FIDO Attestation Result', result); throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); diff --git a/yarn.lock b/yarn.lock index 5e5c597d..383f3c6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,36 +23,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@cbor-extract/cbor-extract-darwin-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76" - integrity sha512-jebtLrruvsBbGMsUn0QxZW/8Z7caS9OkszVKZ64WTWajUkyohmolUdKL2nbfaTyyi3ABJrxVNM4YO1pvMsNI1g== - -"@cbor-extract/cbor-extract-darwin-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.0.0.tgz#7bc01e7911b97eee4c78ae074bd3108f2ff208c3" - integrity sha512-LGYjdlyqANBqCDzBujCqXpPcK70rvaQgw98/aquzBuEmK0KXS7i579CoVG1yS/eb3bMqiVPevBri45jbR6Tlsg== - -"@cbor-extract/cbor-extract-linux-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.0.0.tgz#e40608afed5f373091560fa9dcd19c7f52f510b0" - integrity sha512-c1rbQcSF01yVgbG60zEfHNsUkXiEEQRNdYqm5qpqEAkLx4gA6DDU91IQbalkqXfwDuQzcMovOc1TC3uJJIi2OQ== - -"@cbor-extract/cbor-extract-linux-arm@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.0.0.tgz#f52a7580fb23e305370e66ae9ff136de3729c4b8" - integrity sha512-cOGHEIif5rPbpix6qhpuatrZzm6HeC5rT0nXt8ynLTc7PzfXmovswD9x6d9h5NcHswkV5y3PbkNbpel/tLADYg== - -"@cbor-extract/cbor-extract-linux-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.0.0.tgz#8c936b8a93f915bf3c2459d5b4b78d244bda0f26" - integrity sha512-WYeE1b5WGf9pbbQH3qeNBXq710gGsuVFUiP148RY8In+2pCp/fxjBpe701ngam9/fF5D+gJs8B1i5wv/PN7JZA== - -"@cbor-extract/cbor-extract-win32-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.0.0.tgz#4d4ad91527a8313c3db1e2167a8821dfae9d6211" - integrity sha512-XqVuJEnE0jpl/RkuSp04FF2UE73gY52Y4nZaIE6j9GAeSH2cHYU5CCd4TaVMDi2M18ZpZv7XhL/k+nneQzyJpQ== - "@eslint/eslintrc@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" @@ -80,11 +50,6 @@ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d" integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg== -"@hexagon/base64@~1.1.21": - version "1.1.22" - resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.1.22.tgz#ee1dfb8d80e6b4c8ff5480711cdc070f72c5a1f5" - integrity sha512-Yh289WXFCAe1NvrUYG/MWv6fbTFrJ5Wq4F0A9Klbp22RQy7g13FlUqwVqyKfMQ2jFwgN3Jf1Bk6MaOEvhwQVcQ== - "@humanwhocodes/config-array@^0.9.2": version "0.9.5" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" @@ -120,32 +85,34 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@peculiar/asn1-schema@^2.1.6": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.1.8.tgz#552300a1ed7991b22c9abf789a3920a3cb94c26b" - integrity sha512-u34H/bpqCdDuqrCVZvH0vpwFBT/dNEdNY+eE8u4IuC26yYnhDkXF4+Hliqca88Avbb7hyN2EF/eokyDdyS7G/A== +"@peculiar/asn1-android@^2.1.7": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-android/-/asn1-android-2.2.0.tgz#23ed1f0a57bee2fe0e2ecb7e112e2bded130c386" + integrity sha512-YqbKhWvecnuxcFqyel4GCTORDu5B3BOcvbOtaDfhiVDxZP0zgnw3cxGQtE5/wGmVehvgr3+bLBo1Bu27FcQBAA== dependencies: - asn1js "^3.0.4" - pvtsutils "^1.3.2" + "@peculiar/asn1-schema" "^2.2.0" + asn1js "^3.0.5" tslib "^2.4.0" -"@peculiar/json-schema@^1.1.12": - version "1.1.12" - resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" - integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== +"@peculiar/asn1-schema@^2.1.7", "@peculiar/asn1-schema@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz#d8a54527685c8dee518e6448137349444310ad64" + integrity sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg== dependencies: - tslib "^2.0.0" + asn1js "^3.0.5" + pvtsutils "^1.3.2" + tslib "^2.4.0" -"@peculiar/webcrypto@~1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz#f941bd95285a0f8a3d2af39ccda5197b80cd32bf" - integrity sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg== +"@peculiar/asn1-x509@^2.1.7": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.2.0.tgz#aba335e1264f8e2eea8f39f5157c421e3fb32c8a" + integrity sha512-YORcf7XFy9TKWGnPmK2MNQqAJgIvGNaCrK8vUF/ZRO+BnahZJOgX2HuEiEmoAozZpSlyJnI6CGJOABOjPiDucA== dependencies: - "@peculiar/asn1-schema" "^2.1.6" - "@peculiar/json-schema" "^1.1.12" + "@peculiar/asn1-schema" "^2.2.0" + asn1js "^3.0.5" + ipaddr.js "^2.0.1" pvtsutils "^1.3.2" tslib "^2.4.0" - webcrypto-core "^1.7.4" "@prisma/client@4": version "4.1.1" @@ -164,6 +131,29 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.1.1.tgz#a6a75870618bbd19ff734c51af7dbe9f362c3265" integrity sha512-DCw8L/SS0IXqmj5IW/fMxOXiifnsfjBzDfRhf0j3NFWqvMCh9OtfjmXQZxVgI2mwvJLc/5jzXhkiWT39qS09dA== +"@simplewebauthn/server@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/server/-/server-5.4.0.tgz#f6a6d21620110fa3ad653e53758ffc1eb73a8c01" + integrity sha512-uFL7v6KMW4E1sg6NnK0qIoQXX0a3Vh4AgYkj9IhFyiblXaGbSPO2HhaQfkmLTFcBj1IXwiZcI2qcoltxT0GOeA== + dependencies: + "@peculiar/asn1-android" "^2.1.7" + "@peculiar/asn1-schema" "^2.1.7" + "@peculiar/asn1-x509" "^2.1.7" + "@simplewebauthn/typescript-types" "^5.4.0" + base64url "^3.0.1" + cbor "^5.1.0" + debug "^4.3.2" + elliptic "^6.5.3" + jsrsasign "^10.4.0" + jwk-to-pem "^2.0.4" + node-fetch "^2.6.0" + node-rsa "^1.1.1" + +"@simplewebauthn/typescript-types@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/typescript-types/-/typescript-types-5.4.0.tgz#533b28e7cabcc092396ecd07bbb953b71e7696b6" + integrity sha512-LeJq6Jx+o7D6iIlCy8CH5jCjwVcUvAReEo66VcF3nysfc/yKW5yCAPLSRmPITF4CRZTfnVPxUBUcveUQL6aBMA== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -542,7 +532,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -asn1.js@^5.0.0, asn1.js@^5.2.0: +asn1.js@^5.0.0, asn1.js@^5.2.0, asn1.js@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== @@ -559,7 +549,7 @@ asn1@^0.2.4: dependencies: safer-buffer "~2.1.0" -asn1js@^3.0.1, asn1js@^3.0.4, asn1js@^3.0.5, asn1js@~3.0.2: +asn1js@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== @@ -605,6 +595,11 @@ base32.js@0.0.1: resolved "https://registry.yarnpkg.com/base32.js/-/base32.js-0.0.1.tgz#d045736a57b1f6c139f0c7df42518a84e91bb2ba" integrity sha1-0EVzalex9sE58MffQlGKhOkbsro= +base64url@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + bcrypt-pbkdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" @@ -617,6 +612,11 @@ bcryptjs@^2.4.3: resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= +bignumber.js@^9.0.1: + version "9.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" + integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -693,11 +693,6 @@ buildcheck@0.0.3: resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.3.tgz#70451897a95d80f7807e68fc412eb2e7e35ff4d5" integrity sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA== -bytestreamjs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bytestreamjs/-/bytestreamjs-2.0.0.tgz#ee1b3c348967d4c3ffa45911a64e51a1fd24fc3b" - integrity sha512-TyOlxeS92FcMOaJwAVq5gwqW0vfkWUv5W+ErwdbBzolcUN/9XYpCKWvCV21jjzXU550D9Wt4GgE8Pr1vVbR+wQ== - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -726,26 +721,13 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -cbor-extract@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-2.0.2.tgz#8e45339627fb8b47071e8e71138c630019125939" - integrity sha512-QoLGEgPff03ad/L66P91ci5Zmf7Woq8bh4H5XT3+D5annlrPH5ObHf2Yvo53eDQaDkQtF9tJwMKSWANGXDmwUA== +cbor@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" + integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== dependencies: - node-gyp-build-optional-packages "5.0.3" - optionalDependencies: - "@cbor-extract/cbor-extract-darwin-arm64" "2.0.0" - "@cbor-extract/cbor-extract-darwin-x64" "2.0.0" - "@cbor-extract/cbor-extract-linux-arm" "2.0.0" - "@cbor-extract/cbor-extract-linux-arm64" "2.0.0" - "@cbor-extract/cbor-extract-linux-x64" "2.0.0" - "@cbor-extract/cbor-extract-win32-x64" "2.0.0" - -cbor-x@~1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.3.2.tgz#280a56d93390e01583ad92d78302152beb250421" - integrity sha512-sntNPdI5OaOC+MWfQVHwXmvNJmbNYvwwRPWhoGjISz9yeGYgh7oLsQdo+RMmgLkD+aGsx7z2xHDyrBaBLFNT9w== - optionalDependencies: - cbor-extract "^2.0.2" + bignumber.js "^9.0.1" + nofilter "^1.0.4" chalk@2.4.2, chalk@^2.0.0: version "2.4.2" @@ -1084,7 +1066,7 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -elliptic@^6.4.0: +elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -1457,19 +1439,6 @@ fastq@^1.6.0, fastq@^1.6.1: dependencies: reusify "^1.0.4" -fido2-lib@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fido2-lib/-/fido2-lib-3.2.5.tgz#2682592898e5f50594bcc6788a6ffd7654025e41" - integrity sha512-uDJsf/WNm74uos7baaxbK6vOjIZPOHUhal6FBKgy1ok1y3INI9kfUVkjVs5A7FF5WbUnpqoDEJXmhASZfl7AKw== - dependencies: - "@hexagon/base64" "~1.1.21" - "@peculiar/webcrypto" "~1.4.0" - asn1js "~3.0.2" - cbor-x "~1.3.1" - jose "~4.8.3" - pkijs "~3.0.5" - tldts "~5.7.82" - figlet@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" @@ -1813,6 +1782,11 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -1922,11 +1896,6 @@ jmespath@^0.15.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= -jose@~4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.8.3.tgz#5a754fb4aa5f2806608d083f438e6916b11087da" - integrity sha512-7rySkpW78d8LBp4YU70Wb7+OTgE3OwAALNVZxhoIhp4Kscp+p/fBkdpxGAMKxvCAMV4QfXBU9m6l9nX/vGwd2g== - joycon@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/joycon/-/joycon-2.2.5.tgz#8d4cf4cbb2544d7b7583c216fcdfec19f6be1615" @@ -1994,6 +1963,11 @@ jsonwebtoken@^8.5.1: ms "^2.1.1" semver "^5.6.0" +jsrsasign@^10.4.0: + version "10.5.26" + resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.5.26.tgz#bc36d4c4019c83f144066725ea0ca6ab306702fc" + integrity sha512-TjEu1yPdI+8whpe6CA/6XNb7U1sm9+PUItOUfSThOLvx7JCfYHIfuvZK2Egz2DWUKioafn98LPuk+geLGckxMg== + jwa@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -2003,6 +1977,15 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" +jwk-to-pem@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906" + integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A== + dependencies: + asn1.js "^5.3.0" + elliptic "^6.5.4" + safe-buffer "^5.0.1" + jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" @@ -2320,18 +2303,13 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -node-fetch@^2.1.2: +node-fetch@^2.1.2, node-fetch@^2.6.0: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-gyp-build-optional-packages@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" - integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== - node-gyp-build@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" @@ -2344,6 +2322,13 @@ node-localstorage@~1.3.0: dependencies: write-file-atomic "^1.1.4" +node-rsa@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d" + integrity sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw== + dependencies: + asn1 "^0.2.4" + node-ssh@^12.0.3: version "12.0.4" resolved "https://registry.yarnpkg.com/node-ssh/-/node-ssh-12.0.4.tgz#92ac845c9bc9715f2fcf907ff7c9973ca51fd5c0" @@ -2372,6 +2357,11 @@ nodemon@^2.0.14: undefsafe "^2.0.5" update-notifier "^5.1.0" +nofilter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" + integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -2600,17 +2590,6 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" -pkijs@~3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/pkijs/-/pkijs-3.0.5.tgz#64134f45a92633841b2200b2ece01931209a6c56" - integrity sha512-J6P30yzU7qSbuJIBaclwN93WbyoxjVlkYMgjQmE9wWkPUTHVu2cH6lkjWcIr2WAub5KH38BA1Eyeb4s9apUPTg== - dependencies: - asn1js "^3.0.5" - bytestreamjs "^2.0.0" - pvtsutils "^1.3.2" - pvutils "^1.1.3" - tslib "^2.4.0" - please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -3170,18 +3149,6 @@ tiny-lru@^8.0.1: resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-8.0.2.tgz#812fccbe6e622ded552e3ff8a4c3b5ff34a85e4c" integrity sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg== -tldts-core@^5.7.84: - version "5.7.84" - resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.7.84.tgz#0e128f7d70c0b91741156e1d3ce072fac687ef2a" - integrity sha512-1qKxwSDjmWdqG81cnXGvKI+FHPiVRT6w5DORjp2+YVqDdzFUZO0oQoWu0zbDtWA6HXVk+B15yY9DKbVKZ6fRLg== - -tldts@~5.7.82: - version "5.7.84" - resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.7.84.tgz#c22e8824545ece1cac0a909692d12378b39429d1" - integrity sha512-PGkhyObqEEntI/xUDJdagtvNW+O7+5j8vbXSOXL+563At8gH/4LHxHjdPNv7qrahYuL6y6ZgjBxcvWdut7/LtA== - dependencies: - tldts-core "^5.7.84" - to-readable-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" @@ -3228,16 +3195,16 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - tslib@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -3340,17 +3307,6 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -webcrypto-core@^1.7.4: - version "1.7.5" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.5.tgz#c02104c953ca7107557f9c165d194c6316587ca4" - integrity sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A== - dependencies: - "@peculiar/asn1-schema" "^2.1.6" - "@peculiar/json-schema" "^1.1.12" - asn1js "^3.0.1" - pvtsutils "^1.3.2" - tslib "^2.4.0" - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 962fd7db53680dc63d2e179d9a33a408e9be0ec3 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 08:41:27 +0000 Subject: [PATCH 60/95] chore: don't use namespace --- .../meiling/users/actions/security/webauthn/actions/post.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index c7b2c299..3ec06831 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -5,7 +5,7 @@ import { getPrismaClient } from '../../../../../../../../resources/prisma'; import config from '../../../../../../../../resources/config'; import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1/session'; import crypto from 'crypto'; -import SimpleWebAuthnServer from '@simplewebauthn/server'; +import { verifyRegistrationResponse } from '@simplewebauthn/server'; import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); @@ -78,7 +78,7 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) if (!challengeResponse.rawId) challengeResponse.rawId = Buffer.from(challengeResponse.id as string, 'base64url').toString('base64url'); - const result = await SimpleWebAuthnServer.verifyRegistrationResponse({ + const result = await verifyRegistrationResponse({ credential: challengeResponse, expectedChallenge: webAuthnObject.challenge, expectedOrigin: webAuthnObject.origin, From b38c934d51e221535f332a0ef062d37d95ee2d5a Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 08:56:11 +0000 Subject: [PATCH 61/95] chore: base64url --- .../users/actions/security/webauthn/actions/post.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 3ec06831..410d3cc6 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -80,21 +80,14 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) const result = await verifyRegistrationResponse({ credential: challengeResponse, - expectedChallenge: webAuthnObject.challenge, + expectedChallenge: Buffer.from(webAuthnObject.challenge).toString('base64url'), expectedOrigin: webAuthnObject.origin, }); console.log('FIDO Attestation Result', result); throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); } catch (e) { - if ((e as Error).message.includes('clientData challenge mismatch')) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.UNAUTHORIZED, 'challenge mismatch'); - } - - // TODO: further debugging required. - console.error('FIDO Attestation Error', e); - - throw e; + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, (e as Error).message); } } else { const challenge = Meiling.Authentication.Token.generateToken(128); From 22001bee58b282ce8bae012ea3aafb111bd122eb Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 10:15:44 +0000 Subject: [PATCH 62/95] chore: remove deps to notification api --- config.env.js | 1 + config.example.js | 7 +++++++ src/common/notification.ts | 2 ++ src/interface.ts | 1 + src/routes/v1/meiling/authentication/verify.ts | 9 +++++++++ src/routes/v1/meiling/signup/signup.ts | 2 -- 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/config.env.js b/config.env.js index c9bc9c8f..ccdcd093 100644 --- a/config.env.js +++ b/config.env.js @@ -103,6 +103,7 @@ module.exports = { }, }, notificationApi: { + enable: !/^false/gi.test(process.env.NOTIFICATION_API_ENABLE), version: Number(process.env.NOTIFICATION_API_VERSION) || 1, host: process.env.NOTIFICATION_API_HOST || 'https://notification.meili.ng', key: process.env.NOTIFICATION_API_KEY || 'YOUR NOTIFICATION API KEY', diff --git a/config.example.js b/config.example.js index 66ed0b65..389cbd91 100644 --- a/config.example.js +++ b/config.example.js @@ -67,6 +67,11 @@ module.exports = { email: false, phone: false, }, + /** Signup configuration - meiliNG Internal */ + signup: { + /** Enable meiliNG Internal Signup? set it to false to disable (e.g. only use custom signup process) */ + enabled: /^true$/gi.test(process.env.MEILING_SIGNUP_ENABLED) || true, + }, }, session: { /** Configures Version 1 of the meiliNG Session */ @@ -115,6 +120,8 @@ module.exports = { }, }, notificationApi: { + /** Use notification api? (Stella IT Proprietary, Set it to false if you don't use one.) */ + enable: true, version: 1, host: 'https://notification.stella-api.dev', key: 'YOUR NOTIFICATION API KEY', diff --git a/src/common/notification.ts b/src/common/notification.ts index 3271b03f..0f65c432 100644 --- a/src/common/notification.ts +++ b/src/common/notification.ts @@ -59,6 +59,8 @@ export async function sendNotification(method: NotificationMethod, query: Notifi throw new Error('Notification API was not configured properly.'); } + if (!notificationApi.enable) return; + const version = notificationApi.version; const host = notificationApi.host; diff --git a/src/interface.ts b/src/interface.ts index 78f0695c..4615cf63 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -105,6 +105,7 @@ export interface ConfigInterface { }; }; notificationApi?: { + enable: boolean; version: 1; host: string; key: string; diff --git a/src/routes/v1/meiling/authentication/verify.ts b/src/routes/v1/meiling/authentication/verify.ts index f9f33192..1455a478 100644 --- a/src/routes/v1/meiling/authentication/verify.ts +++ b/src/routes/v1/meiling/authentication/verify.ts @@ -35,6 +35,8 @@ export async function meilingV1SessionAuthnVerifyHandler(req: FastifyRequest, re return; } + const notificationApiEnabled = config.notificationApi?.enable; + let verified = false; let createdAt = undefined; let expiresAt = undefined; @@ -95,6 +97,13 @@ export async function meilingV1SessionAuthnVerifyHandler(req: FastifyRequest, re return; } + // bypass notification api and authentication issuing + if (!notificationApiEnabled) { + if (body.type === 'phone' || body.type === 'email') { + verified = true; + } + } + if (verified) { if (new Date().getTime() < expiresAt.getTime()) { let to = undefined; diff --git a/src/routes/v1/meiling/signup/signup.ts b/src/routes/v1/meiling/signup/signup.ts index 249715f7..be674a15 100644 --- a/src/routes/v1/meiling/signup/signup.ts +++ b/src/routes/v1/meiling/signup/signup.ts @@ -19,7 +19,6 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro const body = req.body as MeilingV1Signup; // Validation no longer required - const signupChallenge = await Meiling.V1.Session.getAuthenticationStatus(req); if (signupChallenge === undefined) { @@ -47,7 +46,6 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro } // check with validation. - if (!(signupChallenge.email?.isVerified && signupChallenge.phone?.isVerified)) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.AUTHENTICATION_REQUEST_NOT_COMPLETED); return; From db4d0a548ed35ff7d07816a6241109b4d09ad265 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 30 Jul 2022 11:48:43 +0000 Subject: [PATCH 63/95] chore: PoC implementation of WebAuthn support Help --- src/common/meiling/authentication/validate.ts | 74 ++++++++++ src/common/meiling/identity/user.ts | 49 ++++++- src/common/meiling/v1/challenge.ts | 11 +- src/common/meiling/v1/interfaces/query.ts | 2 +- src/routes/v1/meiling/lost-password.ts | 60 +++++++- src/routes/v1/meiling/signin.ts | 130 +++++++++++++++--- .../actions/security/webauthn/actions/post.ts | 26 +++- 7 files changed, 325 insertions(+), 27 deletions(-) diff --git a/src/common/meiling/authentication/validate.ts b/src/common/meiling/authentication/validate.ts index 5399d2c4..573ef45e 100644 --- a/src/common/meiling/authentication/validate.ts +++ b/src/common/meiling/authentication/validate.ts @@ -1,7 +1,11 @@ +import { verifyAuthenticationResponse } from '@simplewebauthn/server/./dist'; import { PhoneNumber } from 'libphonenumber-js'; import * as OpenPGP from 'openpgp'; import * as SpeakEasy from 'speakeasy'; +import config from '../../../resources/config'; +import { getPrismaClient } from '../../../resources/prisma'; import * as Notification from '../../notification'; +import { AuthenticationWebAuthnObject } from '../identity/user'; export async function validatePGPSign( challenge: string, @@ -35,6 +39,76 @@ export async function validatePGPSign( return recoveredChallenge.trim() == challenge.trim() && isSignaturesValid; } +export async function validateWebAuthn( + challenge: string, + challengeResponse: any, + data: AuthenticationWebAuthnObject, +): Promise { + const hostnames = config.frontend.url + .map((n) => { + try { + return new URL(n).hostname; + } catch (e) { + return; + } + }) + .filter((n) => n !== undefined) as string[]; + + const res = await verifyAuthenticationResponse({ + credential: challengeResponse, + expectedChallenge: Buffer.from(challenge).toString('base64url'), + authenticator: { + credentialID: Buffer.from(data.data.key.id, 'base64'), + credentialPublicKey: Buffer.from(data.data.key.publicKey, 'base64'), + counter: data.data.key.counter, + }, + expectedOrigin: hostnames.map((n) => 'https://' + n), + expectedRPID: hostnames, + }); + + if (res.verified) { + // TODO: mitigate very unlikely situation when webauthn id collision occurrs. + const updateTargets = await getPrismaClient().authentication.findMany({ + where: { + data: { + path: '$.data.key.id', + equals: data.data.key.id, + }, + method: 'WEBAUTHN', + }, + }); + + const affected = updateTargets.filter((n) => { + const localData = n.data as unknown as AuthenticationWebAuthnObject; + if (localData.data.key.counter === data.data.key.counter) { + return true; + } + }); + + if (affected.length > 1) { + // oops. this is bad. + throw new Error('authentication processing error'); + } + + const toUpdate = affected[0]; + const updateData = toUpdate.data as unknown as AuthenticationWebAuthnObject; + + updateData.data.key.counter = res.authenticationInfo.newCounter; + await getPrismaClient().authentication.update({ + where: { + id: toUpdate.id, + }, + data: { + data: updateData as any, + }, + }); + + return true; + } + + return false; +} + export function validateOTP(challengeResponse: string, secret: string) { return SpeakEasy.totp.verify({ secret, diff --git a/src/common/meiling/identity/user.ts b/src/common/meiling/identity/user.ts index 046a331e..32f382a4 100644 --- a/src/common/meiling/identity/user.ts +++ b/src/common/meiling/identity/user.ts @@ -1,4 +1,7 @@ import { Email, Group, OAuthTokenType, Phone, prisma, User as UserModel, OAuthClient } from '@prisma/client'; +import { VerifiedAuthenticationResponse, VerifiedRegistrationResponse } from '@simplewebauthn/server/./dist'; +import { AttestationFormat } from '@simplewebauthn/server/dist/helpers/decodeAttestationObject'; +import { CredentialDeviceType } from '@simplewebauthn/typescript-types'; import bcrypt from 'bcryptjs'; import JWT from 'jsonwebtoken'; import { OAuth2 } from '..'; @@ -22,7 +25,24 @@ export type AuthenticationJSONObject = | AuthenticationPasswordObject | AuthenticationPGPSSHKeyObject | AuthenticationOTPObject - | AuthenticationEmailSMSObject; + | AuthenticationEmailSMSObject + | AuthenticationWebAuthnObject; + +export interface AuthenticationWebAuthnObject { + type: 'WEBAUTHN'; + data: { + name: string; + key: { + fmt: AttestationFormat; + aaguid: string; + id: string; + publicKey: string; + deviceType: CredentialDeviceType; + isBackedUp: boolean; + counter: number; + }; + }; +} interface AuthenticationPasswordObject { type: 'PASSWORD'; @@ -56,6 +76,32 @@ interface UserQueryOptions { export function getUserId(user: UserModel | string) { return typeof user === 'string' ? user : user.id; } + +export function convertToWebAuthnJSONObject( + name: string, + payload: VerifiedRegistrationResponse, +): AuthenticationWebAuthnObject | undefined { + if (payload.verified && payload.registrationInfo) { + return { + type: 'WEBAUTHN', + data: { + name, + key: { + fmt: payload.registrationInfo.fmt, + aaguid: payload.registrationInfo.aaguid, + id: payload.registrationInfo.credentialID.toString('base64'), + publicKey: payload.registrationInfo.credentialPublicKey.toString('base64'), + deviceType: payload.registrationInfo.credentialDeviceType, + isBackedUp: payload.registrationInfo.credentialBackedUp, + counter: payload.registrationInfo.counter, + }, + }, + }; + } else { + return; + } +} + export async function updateLastAuthenticated(user: UserModel | string) { await getPrismaClient().user.update({ where: { @@ -66,6 +112,7 @@ export async function updateLastAuthenticated(user: UserModel | string) { }, }); } + export async function updateLastSignIn(user: UserModel | string) { await getPrismaClient().user.update({ where: { diff --git a/src/common/meiling/v1/challenge.ts b/src/common/meiling/v1/challenge.ts index e0af8d91..fcdf379e 100644 --- a/src/common/meiling/v1/challenge.ts +++ b/src/common/meiling/v1/challenge.ts @@ -1,8 +1,13 @@ import { Authentication } from '@prisma/client'; import { Meiling } from '../..'; import { ExtendedAuthMethods, SigninType, SigninExtendedAuthentication } from './interfaces'; -import { AuthenticationJSONObject, AuthenticationOTPObject, AuthenticationPGPSSHKeyObject } from '../identity/user'; -import { validateOTP, validatePGPSign } from '../authentication/validate'; +import { + AuthenticationJSONObject, + AuthenticationOTPObject, + AuthenticationPGPSSHKeyObject, + AuthenticationWebAuthnObject, +} from '../identity/user'; +import { validateOTP, validatePGPSign, validateWebAuthn } from '../authentication/validate'; import config from '../../../resources/config'; export function getMeilingAvailableAuthMethods( @@ -123,7 +128,7 @@ export async function verifyChallenge( (data as AuthenticationPGPSSHKeyObject).data.key, ); case ExtendedAuthMethods.WEBAUTHN: - return false; + return await validateWebAuthn(challenge as string, challengeResponse, data as AuthenticationWebAuthnObject); case ExtendedAuthMethods.SMS: case ExtendedAuthMethods.EMAIL: return (challenge as string).trim() === challengeResponse.trim(); diff --git a/src/common/meiling/v1/interfaces/query.ts b/src/common/meiling/v1/interfaces/query.ts index cbdbd98c..4b4109ad 100644 --- a/src/common/meiling/v1/interfaces/query.ts +++ b/src/common/meiling/v1/interfaces/query.ts @@ -60,6 +60,6 @@ interface SigninPasswordLess { interface SigninAuthenticationData { method?: ExtendedAuthMethods; - challengeResponse?: string; + challengeResponse?: any; challengeContext?: any; } diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index da7e4e9a..084996e0 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -6,6 +6,7 @@ import { Meiling, Utils, Notification } from '../../../common'; import config from '../../../resources/config'; import { getPrismaClient } from '../../../resources/prisma'; import { Event } from '../../../common'; +import { AuthenticationJSONObject } from '../../../common/meiling/identity/user'; export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply): Promise { const session = (req as FastifyRequestWithSession).session; @@ -152,9 +153,6 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply ); return; } - } else { - // TODO: Create Lost Password flow for other method. - // but I think common flow can cover this? } if (to !== undefined) { @@ -207,9 +205,43 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply passwordResetUser: user.id, }); + const extras = { + challenge: Meiling.V1.Challenge.shouldSendChallenge(body.method) ? challenge : undefined, + + // Webauthn only. + webauthn: + currentMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN + ? { + allowCredentials: ( + await getPrismaClient().authentication.findMany({ + where: { + user: { + id: user.id, + }, + method: 'WEBAUTHN', + allowPasswordReset: true, + }, + }) + ) + .map((n) => { + const data = n.data as unknown as AuthenticationJSONObject; + if (data.type !== 'WEBAUTHN') { + return; + } + + return { + id: data.data.key.id, + type: 'public-key', + }; + }) + .filter((n) => n !== undefined), + } + : undefined, + }; + rep.send({ success: true, - challenge: Meiling.V1.Challenge.shouldSendChallenge(body.method) ? challenge : undefined, + ...extras, }); return; } @@ -253,10 +285,30 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply return; } + let data = undefined; + if (passwordReset.method === Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN) { + const id = (passwordReset.challenge as any).id; + data = await getPrismaClient().authentication.findFirst({ + where: { + user: { + id: user.id, + }, + method: 'WEBAUTHN', + allowPasswordReset: true, + data: { + path: '$.data.key.id', + equals: id, + }, + }, + }); + data = data?.data; + } + const isValid = await Meiling.V1.Challenge.verifyChallenge( passwordReset.method, passwordReset.challenge, body.data.challengeResponse, + data as unknown as AuthenticationJSONObject | undefined, ); if (!isValid) { throw new Meiling.V1.Error.MeilingError( diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index 77a08be1..52a7f9ea 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -5,6 +5,9 @@ import { FastifyRequestWithSession } from '.'; import { Meiling, Utils, Event, Notification } from '../../../common'; import config from '../../../resources/config'; import libmobilephoneJs from 'libphonenumber-js'; +import { ExtendedAuthMethods, SigninType } from '../../../common/meiling/v1/interfaces'; +import { getPrismaClient } from '../../../resources/prisma'; +import { AuthenticationJSONObject } from '../../../common/meiling/identity/user'; export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Promise { const session = (req as FastifyRequestWithSession).session; @@ -109,6 +112,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro ) { const signinMethod = body?.data?.method; const authMethods = []; + const targetUsers = []; if (body.type === Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH) { if (session.extendedAuthentication?.type !== Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH) { @@ -139,6 +143,8 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro return; } + targetUsers.push(user); + authMethods.push( ...(await Meiling.V1.User.getAvailableExtendedAuthenticationMethods(user, body.type, signinMethod)), ); @@ -152,6 +158,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.WRONG_USERNAME, 'Wrong username.'); return; } + targetUsers.push(...users); for (const user of users) { const thisMethods = await Meiling.V1.User.getAvailableExtendedAuthenticationMethods(user, body.type); @@ -274,10 +281,50 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro } } - rep.send({ + const extras = { + // SMS, Email flows. that requires which phone did the caller sent to, - type: body.type, + + // some that requires challenges to be received challenge: Meiling.V1.Challenge.shouldSendChallenge(signinMethod) ? challenge : undefined, + + // Webauthn only. + webauthn: + signinMethod === ExtendedAuthMethods.WEBAUTHN + ? { + allowCredentials: ( + await getPrismaClient().authentication.findMany({ + where: { + user: { + id: { + in: targetUsers.filter((n) => n !== undefined).map((n) => (n as UserModel).id), + }, + }, + method: 'WEBAUTHN', + allowSingleFactor: body.type === SigninType.PASSWORDLESS, + allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH, + }, + }) + ) + .map((n) => { + const data = n.data as unknown as AuthenticationJSONObject; + if (data.type !== 'WEBAUTHN') { + return; + } + + return { + id: data.data.key.id, + type: 'public-key', + }; + }) + .filter((n) => n !== undefined), + } + : undefined, + }; + + rep.send({ + type: body.type, + ...extras, }); return; } @@ -328,23 +375,74 @@ please request this endpoint without challengeResponse field to request challeng const authMethodCheckPromises = []; const authMethodCheckUsers: string[] = []; - // authMethod - for (const authMethod of authMethods) { - // if authMethod is current authMethod: - if (Meiling.V1.Database.convertAuthenticationMethod(authMethod.method) === signinMethod) { - // check database is not corrupted. - if (authMethod.data !== null) { - const data = Utils.convertJsonIfNot(authMethod.data); - - if (authMethod.userId !== null) { - // add promise to array - authMethodCheckPromises.push( - Meiling.V1.Challenge.verifyChallenge(signinMethod, challenge, challengeResponse, data), - ); - authMethodCheckUsers.push(authMethod.userId); + if (signinMethod !== ExtendedAuthMethods.WEBAUTHN) { + // authMethod + for (const authMethod of authMethods) { + // if authMethod is current authMethod: + if (Meiling.V1.Database.convertAuthenticationMethod(authMethod.method) === signinMethod) { + // check database is not corrupted. + if (authMethod.data !== null) { + const data = Utils.convertJsonIfNot(authMethod.data); + + if (authMethod.userId !== null) { + // add promise to array + authMethodCheckPromises.push( + Meiling.V1.Challenge.verifyChallenge(signinMethod, challenge, challengeResponse, data), + ); + authMethodCheckUsers.push(authMethod.userId); + } } } } + } else { + if (typeof challengeResponse !== 'object') + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'invalid challengeResponse type', + ); + + const id = challengeResponse.id; + if (typeof id !== 'string') + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); + + const webauthn = await getPrismaClient().authentication.findFirst({ + where: { + user: { + id: { + in: targetUsers.filter((n) => n !== undefined).map((n) => (n as UserModel).id), + }, + }, + method: 'WEBAUTHN', + allowSingleFactor: body.type === SigninType.PASSWORDLESS, + allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH, + data: { + path: '$.data.key.id', + equals: id, + }, + }, + }); + + if (!webauthn) + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'WebAuthn token with specified id was not found', + ); + + if (!webauthn.userId) + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.NOT_FOUND, + 'WebAuthn token with specified id has no user to authorize with', + ); + + authMethodCheckPromises.push( + Meiling.V1.Challenge.verifyChallenge( + signinMethod, + challenge, + challengeResponse, + webauthn.data as unknown as AuthenticationJSONObject, + ), + ); + authMethodCheckUsers.push(webauthn.userId); } const authMethodCheckResults = await Promise.all(authMethodCheckPromises); diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts index 410d3cc6..c357af81 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/actions/post.ts @@ -7,6 +7,7 @@ import { getSessionFromRequest } from '../../../../../../../../common/meiling/v1 import crypto from 'crypto'; import { verifyRegistrationResponse } from '@simplewebauthn/server'; import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; +import { AuthenticationMethod } from '@prisma/client'; const dbType = Meiling.V1.Database.convertAuthentication(Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN); @@ -21,7 +22,7 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) interface RegisterRequest { hostname: string; - name?: string; + name: string; } type RegisterProcess = RegisterRequest & RegistrationCredentialJSON; @@ -85,7 +86,28 @@ async function userWebAuthnActionPostKey(req: FastifyRequest, rep: FastifyReply) }); console.log('FIDO Attestation Result', result); - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.NOT_IMPLEMENTED); + const converted = Meiling.Identity.User.convertToWebAuthnJSONObject(body.name, result); + if (!converted) { + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.UNAUTHORIZED, + 'failed to verify webauthn registration request', + ); + } + + const keyData = await getPrismaClient().authentication.create({ + data: { + user: { + connect: { id: user.id }, + }, + method: dbType as AuthenticationMethod, + allowPasswordReset: true, + allowTwoFactor: true, + allowSingleFactor: true, + data: converted as any, + }, + }); + + rep.send({ success: true }); } catch (e) { throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, (e as Error).message); } From ecbd6f877a9110994a68dcc6bc0c5d5fdde25547 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 03:49:00 +0000 Subject: [PATCH 64/95] fix: missing name on security key --- src/routes/v1/meiling/users/actions/security/webauthn/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts index 16b83e18..0c44f23d 100644 --- a/src/routes/v1/meiling/users/actions/security/webauthn/index.ts +++ b/src/routes/v1/meiling/users/actions/security/webauthn/index.ts @@ -29,7 +29,7 @@ function userWebAuthnPlugin(app: FastifyInstance, opts: FastifyPluginOptions, do rep.send( securityKeys.map((n) => ({ id: n.id, - name: (n.data as any)?.name, + name: (n.data as any)?.data?.name, createdAt: n.createdAt, })), ); From 0426452333ef8efd6021bef28c9a5c945a70442c Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 04:17:14 +0000 Subject: [PATCH 65/95] fix: signin webauthn --- src/routes/v1/meiling/signin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index 52a7f9ea..e1069299 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -301,8 +301,8 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro }, }, method: 'WEBAUTHN', - allowSingleFactor: body.type === SigninType.PASSWORDLESS, - allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH, + allowSingleFactor: body.type === SigninType.PASSWORDLESS ? true : undefined, + allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH ? true : undefined, }, }) ) From 1b0f6c817a77ebe4cc5d2a23ad41b1c9d24f5e8c Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 04:50:03 +0000 Subject: [PATCH 66/95] chore: convert to Date --- src/routes/v1/meiling/lost-password.ts | 6 ++++++ src/routes/v1/meiling/signin.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 084996e0..78b0c6cf 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -260,6 +260,12 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply return; } + if (session.passwordReset && typeof session.passwordReset?.challengeCreatedAt !== 'object') { + session.passwordReset.challengeCreatedAt = new Date( + session.passwordReset.challengeCreatedAt as unknown as string | number, + ); + } + const passwordReset = session.passwordReset as Meiling.V1.Interfaces.SessionPasswordReset; if ( !passwordReset.method || diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index e1069299..f0570f97 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -351,6 +351,12 @@ please request this endpoint without challengeResponse field to request challeng // is challenge expired if (extendedAuthSession.challengeCreatedAt) { + if (typeof extendedAuthSession.challengeCreatedAt !== 'object') { + extendedAuthSession.challengeCreatedAt = new Date( + extendedAuthSession.challengeCreatedAt as unknown as string | number, + ); + } + if ( new Date().getTime() > extendedAuthSession.challengeCreatedAt.getTime() + config.token.invalidate.meiling.CHALLENGE_TOKEN * 1000 From fa031d65cc12b2139358c4f320072ab4d8e89a3f Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:06:40 +0000 Subject: [PATCH 67/95] chore: remove api endpoint for now --- src/routes/v1/meiling/index.ts | 167 +-------------------------------- 1 file changed, 2 insertions(+), 165 deletions(-) diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index b00882e6..b01b3f3e 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -96,174 +96,11 @@ function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, }, }); - app.post( - '/signin', - { - schema: { - description: 'Endpoint to sign-in current session into specified account', - tags: ['meiling'], - summary: 'Signin', - security: [{ sessionV1: [] }], - params: {}, - body: { - oneOf: [ - { - type: 'object', - properties: { - type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.USERNAME_CHECK] }, - data: { - type: 'object', - properties: { - username: { type: 'string' }, - }, - }, - }, - }, - { - type: 'object', - properties: { - type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.USERNAME_AND_PASSWORD] }, - data: { - type: 'object', - properties: { - username: { type: 'string' }, - password: { type: 'string' }, - }, - }, - }, - }, - { - type: 'object', - properties: { - type: { type: 'string', enum: [Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH] }, - data: { - $ref: 'MeilingV1SigninAuthnData#', - }, - }, - }, - ], - }, - response: { - 200: { - oneOf: [ - { - type: 'object', - description: - '(on username check) When the user was previously logged in and matches only one user, returns abstract user info.', - properties: { - success: { type: 'boolean' }, - data: { - type: 'object', - description: 'abstract user data', - properties: { - id: { type: 'string', format: 'uuid' }, - profileId: { type: 'string', format: 'uri', nullable: true }, - name: { type: 'string', nullable: true }, - username: { type: 'string' }, - }, - nullable: true, - }, - }, - }, - { - type: 'object', - description: '(on 2fa session) When user requests available 2fa methods, this is how meiliNG returns.', - properties: { - methods: { - type: 'array', - items: { - type: 'string', - enum: Object.values(Meiling.V1.Interfaces.ExtendedAuthMethods), - }, - }, - }, - }, - { - type: 'object', - description: - '(on 2fa session) When user requests challenge of 2fa, this is how server provides challenge or request user to reply with challenge', - properties: { - to: { type: 'string', nullable: true }, - type: { - type: 'string', - enum: [ - Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH, - Meiling.V1.Interfaces.SigninType.PASSWORDLESS, - ], - }, - challenge: { $ref: 'Any#' }, - }, - }, - ], - }, - '4xx': { - $ref: 'MeilingV1Error#', - }, - '5xx': { - $ref: 'MeilingV1Error#', - }, - }, - }, - }, - signinHandler, - ); + app.post('/signin', signinHandler); app.register(signupPlugin, { prefix: '/signup' }); - app.post( - '/lost-password', - { - schema: { - summary: 'Password Recovery (Lost Password)', - description: 'Provides Password recovery flow', - tags: ['meiling'], - security: [{ sessionV1: [] }], - params: {}, - body: { - oneOf: [ - { - type: 'object', - properties: { - password: { type: 'string' }, - }, - required: ['password'], - }, - { - type: 'object', - properties: { - context: { - type: 'object', - properties: { - username: { type: 'string' }, - }, - required: ['username'], - }, - method: { - type: 'string', - enum: Object.values(Meiling.V1.Interfaces.ExtendedAuthMethods), - nullable: true, - }, - data: { - type: 'object', - }, - }, - required: ['context'], - }, - // {}, - ], - }, - response: { - '4xx': { - $ref: 'MeilingV1Error#', - }, - '5xx': { - $ref: 'MeilingV1Error#', - }, - }, - }, - }, - lostPasswordHandler, - ); + app.post('/lost-password', lostPasswordHandler); app.register(signoutPlugin, { prefix: '/signout' }); From 41bb284ec5a3b01002d582c8496fb46783c16c8b Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:17:36 +0000 Subject: [PATCH 68/95] chore: oops --- src/routes/v1/meiling/lost-password.ts | 8 +++++++- src/routes/v1/meiling/signin.ts | 10 ++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 78b0c6cf..9a75c28a 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -292,8 +292,14 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply } let data = undefined; + if (passwordReset.method === Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN) { - const id = (passwordReset.challenge as any).id; + const idRaw = (passwordReset.challenge as any).id; + if (typeof idRaw !== 'string' || !Utils.checkBase64(idRaw)) + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); + + const id = Buffer.from(idRaw, 'base64url').toString('base64'); + data = await getPrismaClient().authentication.findFirst({ where: { user: { diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index f0570f97..ef0b986f 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -407,10 +407,12 @@ please request this endpoint without challengeResponse field to request challeng 'invalid challengeResponse type', ); - const id = challengeResponse.id; - if (typeof id !== 'string') + const idRaw = challengeResponse.id; + if (typeof idRaw !== 'string' || !Utils.checkBase64(idRaw)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); + const id = Buffer.from(idRaw, 'base64url').toString('base64'); + const webauthn = await getPrismaClient().authentication.findFirst({ where: { user: { @@ -419,8 +421,8 @@ please request this endpoint without challengeResponse field to request challeng }, }, method: 'WEBAUTHN', - allowSingleFactor: body.type === SigninType.PASSWORDLESS, - allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH, + allowSingleFactor: body.type === SigninType.PASSWORDLESS ? true : undefined, + allowTwoFactor: body.type === SigninType.TWO_FACTOR_AUTH ? true : undefined, data: { path: '$.data.key.id', equals: id, From 161fc407b6655585672a4a3cd603b8e5f6b0c609 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:27:36 +0000 Subject: [PATCH 69/95] chore: shortened Base64URLs --- src/common/utils.ts | 12 ++++++++++++ src/routes/v1/meiling/lost-password.ts | 2 +- src/routes/v1/meiling/signin.ts | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/common/utils.ts b/src/common/utils.ts index 3181ca62..31e04b75 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -142,6 +142,18 @@ export function checkBase64(string: string) { return regex.test(convertedString); } +export function checkShortenedBase64(string: string) { + let convertedString = string; + if (string.includes('-') || string.includes('_')) { + convertedString = convertedString.replace(/\-/g, '+').replace(/\_/g, '/'); + convertedString = convertedString.padEnd(Math.ceil(convertedString.length / 4) * 4, '='); + console.log(convertedString); + } + + const regex = /^([A-Za-z0-9+/=]+)$/; + return regex.test(convertedString); +} + export function convertDateToISO8601Date(date: Date) { return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date .getDate() diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 9a75c28a..3f21a5a6 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -295,7 +295,7 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply if (passwordReset.method === Meiling.V1.Interfaces.ExtendedAuthMethods.WEBAUTHN) { const idRaw = (passwordReset.challenge as any).id; - if (typeof idRaw !== 'string' || !Utils.checkBase64(idRaw)) + if (typeof idRaw !== 'string' || !Utils.checkShortenedBase64(idRaw)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); const id = Buffer.from(idRaw, 'base64url').toString('base64'); diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index ef0b986f..cff0d7c4 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -408,7 +408,7 @@ please request this endpoint without challengeResponse field to request challeng ); const idRaw = challengeResponse.id; - if (typeof idRaw !== 'string' || !Utils.checkBase64(idRaw)) + if (typeof idRaw !== 'string' || !Utils.checkShortenedBase64(idRaw)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); const id = Buffer.from(idRaw, 'base64url').toString('base64'); From a9e63ca36b1b60e02196a9a3d1713dc2205fbea0 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:36:44 +0000 Subject: [PATCH 70/95] chore: debug logging --- src/routes/v1/meiling/signin.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index cff0d7c4..71cc6fd4 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -8,6 +8,7 @@ import libmobilephoneJs from 'libphonenumber-js'; import { ExtendedAuthMethods, SigninType } from '../../../common/meiling/v1/interfaces'; import { getPrismaClient } from '../../../resources/prisma'; import { AuthenticationJSONObject } from '../../../common/meiling/identity/user'; +import { NodeEnvironment } from '../../../interface'; export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Promise { const session = (req as FastifyRequestWithSession).session; @@ -458,6 +459,18 @@ please request this endpoint without challengeResponse field to request challeng .map((n, i) => (n === true ? i : undefined)) .filter((n) => n !== undefined) as number[]; + if (config.node.environment === NodeEnvironment.Development) { + console.log( + 'signin debug: ', + 'idx', + authMethodCheckIndex, + 'results', + authMethodCheckResults, + 'users', + authMethodCheckUsers, + ); + } + for (const index of authMethodCheckIndex) { const userId = authMethodCheckUsers[index]; From f276e09bb42328a38dea1a74f1832b0e4e83627d Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:42:19 +0000 Subject: [PATCH 71/95] chore: error logging --- src/common/meiling/v1/challenge.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/meiling/v1/challenge.ts b/src/common/meiling/v1/challenge.ts index fcdf379e..bc72cee1 100644 --- a/src/common/meiling/v1/challenge.ts +++ b/src/common/meiling/v1/challenge.ts @@ -9,6 +9,7 @@ import { } from '../identity/user'; import { validateOTP, validatePGPSign, validateWebAuthn } from '../authentication/validate'; import config from '../../../resources/config'; +import { NodeEnvironment } from '../../../interface'; export function getMeilingAvailableAuthMethods( authMethods: Authentication[], @@ -136,6 +137,8 @@ export async function verifyChallenge( return validateOTP(challengeResponse, (data as AuthenticationOTPObject).data.secret); } } catch (e) { + if (config.node.environment === NodeEnvironment.Development) + console.error('challenge validation failed with error:', e); return false; } } From a2114484248ea2d30da30d599d85bb41d634773d Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:47:49 +0000 Subject: [PATCH 72/95] fix: imports --- src/common/meiling/authentication/validate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/meiling/authentication/validate.ts b/src/common/meiling/authentication/validate.ts index 573ef45e..ff9b01d8 100644 --- a/src/common/meiling/authentication/validate.ts +++ b/src/common/meiling/authentication/validate.ts @@ -1,4 +1,3 @@ -import { verifyAuthenticationResponse } from '@simplewebauthn/server/./dist'; import { PhoneNumber } from 'libphonenumber-js'; import * as OpenPGP from 'openpgp'; import * as SpeakEasy from 'speakeasy'; @@ -6,6 +5,7 @@ import config from '../../../resources/config'; import { getPrismaClient } from '../../../resources/prisma'; import * as Notification from '../../notification'; import { AuthenticationWebAuthnObject } from '../identity/user'; +import SimpleWebAuthn, { verifyAuthenticationResponse } from '@simplewebauthn/server'; export async function validatePGPSign( challenge: string, From 3e0c25b7d903982867b802b53adf54e4ab8099cb Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:52:29 +0000 Subject: [PATCH 73/95] chore: even more validations --- src/routes/v1/meiling/lost-password.ts | 11 +++++++++++ src/routes/v1/meiling/signin.ts | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/routes/v1/meiling/lost-password.ts b/src/routes/v1/meiling/lost-password.ts index 3f21a5a6..028a42e8 100644 --- a/src/routes/v1/meiling/lost-password.ts +++ b/src/routes/v1/meiling/lost-password.ts @@ -316,6 +316,17 @@ export async function lostPasswordHandler(req: FastifyRequest, rep: FastifyReply data = data?.data; } + const challengeResponse = body.data.challengeResponse; + if (typeof challengeResponse !== 'object') + throw new Meiling.V1.Error.MeilingError( + Meiling.V1.Error.ErrorType.INVALID_REQUEST, + 'invalid challengeResponse type', + ); + + if (challengeResponse.type !== 'public-key') { + challengeResponse.type = 'public-key'; + } + const isValid = await Meiling.V1.Challenge.verifyChallenge( passwordReset.method, passwordReset.challenge, diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index 71cc6fd4..b4e26bb2 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -408,6 +408,10 @@ please request this endpoint without challengeResponse field to request challeng 'invalid challengeResponse type', ); + if (challengeResponse.type !== 'public-key') { + challengeResponse.type = 'public-key'; + } + const idRaw = challengeResponse.id; if (typeof idRaw !== 'string' || !Utils.checkShortenedBase64(idRaw)) throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, 'invalid WebAuthn ID'); From 05e135b9a3a6f8891f0508229148de129b648c9e Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 07:55:59 +0000 Subject: [PATCH 74/95] chore: remove debug stuff --- src/common/meiling/v1/challenge.ts | 2 ++ src/routes/v1/meiling/signin.ts | 12 ------------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/common/meiling/v1/challenge.ts b/src/common/meiling/v1/challenge.ts index bc72cee1..de391478 100644 --- a/src/common/meiling/v1/challenge.ts +++ b/src/common/meiling/v1/challenge.ts @@ -137,8 +137,10 @@ export async function verifyChallenge( return validateOTP(challengeResponse, (data as AuthenticationOTPObject).data.secret); } } catch (e) { + /* if (config.node.environment === NodeEnvironment.Development) console.error('challenge validation failed with error:', e); + */ return false; } } diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index b4e26bb2..0a64dcb8 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -463,18 +463,6 @@ please request this endpoint without challengeResponse field to request challeng .map((n, i) => (n === true ? i : undefined)) .filter((n) => n !== undefined) as number[]; - if (config.node.environment === NodeEnvironment.Development) { - console.log( - 'signin debug: ', - 'idx', - authMethodCheckIndex, - 'results', - authMethodCheckResults, - 'users', - authMethodCheckUsers, - ); - } - for (const index of authMethodCheckIndex) { const userId = authMethodCheckUsers[index]; From c4480d420aa4a4e6d3bdc90daebccced461eb3bc Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 6 Aug 2022 13:38:46 +0000 Subject: [PATCH 75/95] fix: unreachable code --- src/routes/v1/index.ts | 2 +- src/routes/v1/meiling/signin.ts | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/index.ts b/src/routes/v1/index.ts index 6eba483c..269d7621 100644 --- a/src/routes/v1/index.ts +++ b/src/routes/v1/index.ts @@ -8,7 +8,7 @@ function v1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => app.get('/', (req, rep) => { rep.send({ version: 1, - engine: 'Meiling Project', + engine: 'meiliNG', }); }); diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index 0a64dcb8..c44cb7ca 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -219,7 +219,7 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro } const challenge = Meiling.V1.Challenge.generateChallenge(signinMethod); - const to = undefined; + let to: string | undefined = undefined; await Meiling.V1.Session.setExtendedAuthenticationSessionMethodAndChallenge(req, signinMethod, challenge); const lang = 'ko'; @@ -229,6 +229,17 @@ export async function signinHandler(req: FastifyRequest, rep: FastifyReply): Pro signinMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.EMAIL || signinMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.SMS ) { + if (!to) { + if (targetUsers.length === 1) { + const user = targetUsers[0] as UserModel; + if (signinMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.EMAIL) { + to = (await Meiling.Identity.User.getPrimaryEmail(user.id))?.email; + } else if (signinMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.SMS) { + to = (await Meiling.Identity.User.getPrimaryPhone(user.id))?.phone; + } + } + } + if (to) { if (signinMethod === Meiling.V1.Interfaces.ExtendedAuthMethods.SMS) { const phone = libmobilephoneJs(to); From b2f216783c5264d4403c7f34db7446b84798d9de Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 13:25:37 +0000 Subject: [PATCH 76/95] chore: i don't know at this point --- src/common/meiling/authentication/token.ts | 6 ++++-- src/common/meiling/oauth2/clientAuthorization.ts | 12 ++++++++++-- .../v1/meiling/users/actions/auth/device/auth.ts | 10 +--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/common/meiling/authentication/token.ts b/src/common/meiling/authentication/token.ts index 18bf5289..9fe29f38 100644 --- a/src/common/meiling/authentication/token.ts +++ b/src/common/meiling/authentication/token.ts @@ -4,6 +4,7 @@ import { OAuthToken, OAuthTokenType, Permission, + Prisma, User as UserModel, } from '@prisma/client'; import { FastifyRequest } from 'fastify'; @@ -205,16 +206,17 @@ export async function getMetadata(token: string, type?: OAuthTokenType): Promise } } -export async function setMetadata(token: string, metadata: Token.TokenMetadata): Promise { +export async function setMetadata(token: string, metadata?: Token.TokenMetadata): Promise { await getPrismaClient().oAuthToken.update({ where: { token, }, data: { - metadata: metadata as any, + metadata: !metadata ? Prisma.DbNull : (metadata as any), }, }); } + export function getValidTimeByType(type: OAuthTokenType): number { return config?.token?.invalidate?.oauth[type] === undefined ? Number.MAX_SAFE_INTEGER diff --git a/src/common/meiling/oauth2/clientAuthorization.ts b/src/common/meiling/oauth2/clientAuthorization.ts index c982d629..b1cae45d 100644 --- a/src/common/meiling/oauth2/clientAuthorization.ts +++ b/src/common/meiling/oauth2/clientAuthorization.ts @@ -1,4 +1,12 @@ -import { OAuthClient, OAuthClientAuthorization, OAuthToken, OAuthTokenType, Permission, User } from '@prisma/client'; +import { + OAuthClient, + OAuthClientAuthorization, + OAuthToken, + OAuthTokenType, + Permission, + Prisma, + User, +} from '@prisma/client'; import { Authentication } from '..'; import { getPrismaClient } from '../../../resources/prisma'; @@ -191,7 +199,7 @@ export async function createToken( token: tokenKey, // TODO: FIX LATER. I KNOW THIS IS BAD! - metadata: metadata as any, + metadata: !metadata ? Prisma.DbNull : (metadata as any), }, }); diff --git a/src/routes/v1/meiling/users/actions/auth/device/auth.ts b/src/routes/v1/meiling/users/actions/auth/device/auth.ts index e55a5514..643650e1 100644 --- a/src/routes/v1/meiling/users/actions/auth/device/auth.ts +++ b/src/routes/v1/meiling/users/actions/auth/device/auth.ts @@ -119,15 +119,7 @@ export async function deviceCodeAuthorizeHandler(req: FastifyRequest, rep: Fasti } metadata.data.deviceCode.isAuthorized = true; - - await getPrismaClient().oAuthToken.update({ - where: { - token: userCode.token, - }, - data: { - metadata: metadata as any, - }, - }); + await Meiling.Authentication.Token.setMetadata(userCode.token, metadata); rep.send({ success: true, From c58411f310d2ca43ce903f42deb53722c791c36f Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 15:08:57 +0000 Subject: [PATCH 77/95] chore: add sentry support --- package.json | 2 + src/common/sentry/tracer.ts | 139 ++++++++++++++++++ src/interface.ts | 4 + src/routes/v1/meiling/users/actions/index.ts | 11 ++ .../v1/oauth2/token/authorization_code.ts | 10 ++ src/routes/v1/oauth2/token/device_code.ts | 10 ++ src/routes/v1/oauth2/token/refresh_token.ts | 10 ++ src/routes/v1/oauth2/userinfo.ts | 10 ++ yarn.lock | 94 ++++++++++-- 9 files changed, 281 insertions(+), 9 deletions(-) create mode 100644 src/common/sentry/tracer.ts diff --git a/package.json b/package.json index 2578e58e..162756cc 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "license": "MIT", "dependencies": { "@prisma/client": "4", + "@sentry/node": "^7.9.0", + "@sentry/tracing": "^7.9.0", "@simplewebauthn/server": "^5.4.0", "@xmldom/xmldom": "^0.8.0", "ansi-regex": "^6.0.1", diff --git a/src/common/sentry/tracer.ts b/src/common/sentry/tracer.ts new file mode 100644 index 00000000..1533381e --- /dev/null +++ b/src/common/sentry/tracer.ts @@ -0,0 +1,139 @@ +import { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; +import * as Sentry from '@sentry/node'; +import Tracing, { Transaction } from '@sentry/tracing'; +import config from '../../resources/config'; +import { FastifyRequestWithSession } from '../../routes/v1/meiling'; +import { getSessionFromRequest } from '../meiling/v1/session'; +import { Meiling } from '..'; + +const DEFAULT_REQUEST_KEYS = ['headers', 'method', 'query_string', 'url']; + +/** + * Function copied from + * https://github.com/getsentry/sentry-javascript/blob/master/packages/node/src/handlers.ts + * and mofidied for Fastify + * + * Data (req.body) isn't available in onRequest hook, + * as it is parsed later in the fastify lifecycle + * https://www.fastify.io/docs/latest/Hooks/#onrequest + */ +function convertReq4Sentry(req: FastifyRequest, keys: string[] = DEFAULT_REQUEST_KEYS) { + if (!keys || keys.length <= 0 || typeof keys !== 'object') { + keys = DEFAULT_REQUEST_KEYS; + } + const requestData = {} as any; + + const headers = req.headers || {}; + const method = req.method; + const host = req.hostname; + const protocol = req.protocol; + const originalUrl = req.url; + const absoluteUrl = protocol + '://' + host + originalUrl; + + keys.forEach(function (key: string) { + switch (key) { + case 'headers': + requestData.headers = headers; + break; + case 'method': + requestData.method = method; + break; + case 'url': + requestData.url = absoluteUrl; + break; + case 'query_string': + requestData.query_string = Object.assign({}, req.query); + break; + default: + if ({}.hasOwnProperty.call(req, key)) { + requestData[key] = (req as any)[key]; + } + } + }); + + return requestData; +} + +export function registerSentryTransaction(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void) { + if (!isSentryAvailable()) { + done(); + return; + } + + Sentry.init({ + serverName: config.sentry?.serverName, + dsn: config.sentry?.dsn, + attachStacktrace: true, + integrations: [new Sentry.Integrations.Http({ tracing: true })], + }); + + app.addHook('onRequest', async (req) => { + let traceData; + if (req.headers && typeof req.headers['sentry-trace'] === 'string') { + const traceKey = req.headers['sentry-trace']; + traceData = Tracing.extractTraceparentData(traceKey); + } + + const req4Sentry = convertReq4Sentry(req); + + (req as any).sentryTransaction = Sentry.startTransaction( + { + op: 'http.server', + name: `${req.method} ${req.url}`, + ...traceData, + }, + { + request: req4Sentry, + }, + ); + + Sentry.setUser({ + ip_address: req.ip, + }); + }); + + app.addHook('onResponse', async (req, rep) => { + setImmediate(() => { + const tx = getSentryTransaction(req); + if (tx) { + tx.setData('url', req.url); + tx.setData('query', req.query); + if (typeof req.body === 'object') { + tx.setData('body', req.body); + } + tx.setHttpStatus(rep.statusCode); + + if ((req as FastifyRequestWithSession).session) { + tx.setData('session', getSessionFromRequest(req)); + } + + tx.finish(); + } + }); + }); +} + +export function sentryErrorHandler(error: Error, req: FastifyRequest, rep: FastifyReply) { + Sentry.withScope((scope) => { + if ((error as Meiling.V1.Error.MeilingError)._isMeiling === true) { + scope.setTag('is_meiling', true); + Sentry.captureException(error); + } + }); +} + +export function isSentryAvailable() { + if (config && config.sentry && typeof config.sentry.dsn === 'string' && config.sentry.dsn.trim() !== '') { + return true; + } + + return false; +} + +export function getSentryTransaction(req: FastifyRequest): Transaction | undefined { + if (isSentryAvailable()) { + return (req as any).sentryTransaction as Transaction; + } + + return; +} diff --git a/src/interface.ts b/src/interface.ts index 4615cf63..b5485400 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -113,6 +113,10 @@ export interface ConfigInterface { useAlimtalkForSouthKorea?: boolean; }; }; + sentry?: { + serverName?: string; + dsn: string; + }; baridegiApi?: { version: 1; host: string; diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index 68c3966a..8e0b78d3 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -9,6 +9,8 @@ import { userUpdateInfo } from './info/put'; import userPhonesPlugin from './phones'; import userSecurityPlugin from './security'; import userPasswordsPlugin from './security/passwords'; +import * as Sentry from '@sentry/node'; +import { isSentryAvailable } from '../../../../../common/sentry/tracer'; export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void) { // /v1/meiling/user/:userId/action @@ -23,6 +25,15 @@ export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOpti 'you are not logged in as specified user.', ); } + + if (isSentryAvailable()) { + Sentry.setUser({ + id: userBase.id, + username: userBase.username, + email: userBase.emails.find((n) => n.isPrimary)?.email, + ip_address: req.ip, + }); + } }); app.get('/', userGetInfo); diff --git a/src/routes/v1/oauth2/token/authorization_code.ts b/src/routes/v1/oauth2/token/authorization_code.ts index f60fb9f4..01f4ff60 100644 --- a/src/routes/v1/oauth2/token/authorization_code.ts +++ b/src/routes/v1/oauth2/token/authorization_code.ts @@ -1,7 +1,9 @@ import crypto from 'crypto'; import { FastifyReply, FastifyRequest } from 'fastify'; import { Meiling, Utils } from '../../../../common'; +import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; +import * as Sentry from '@sentry/node'; export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -59,6 +61,14 @@ export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: F return; } + if (isSentryAvailable()) { + Sentry.setUser({ + id: user.id, + username: user.username, + ip_address: req.ip, + }); + } + const authorization = await Meiling.Authentication.Token.getAuthorization(token, type); if (!authorization) { Meiling.OAuth2.Error.sendOAuth2Error( diff --git a/src/routes/v1/oauth2/token/device_code.ts b/src/routes/v1/oauth2/token/device_code.ts index fc6da308..e0d96380 100644 --- a/src/routes/v1/oauth2/token/device_code.ts +++ b/src/routes/v1/oauth2/token/device_code.ts @@ -1,6 +1,8 @@ import { FastifyReply, FastifyRequest } from 'fastify'; import { Meiling, Utils } from '../../../../common'; +import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; +import * as Sentry from '@sentry/node'; export async function oAuth2DeviceCodeHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -87,6 +89,14 @@ export async function oAuth2DeviceCodeHandler(req: FastifyRequest, rep: FastifyR return; } + if (isSentryAvailable()) { + Sentry.setUser({ + id: user.id, + username: user.username, + ip_address: req.ip, + }); + } + const scope = permissions.map((p) => p.name).join(' '); const scopes = scope.split(' '); diff --git a/src/routes/v1/oauth2/token/refresh_token.ts b/src/routes/v1/oauth2/token/refresh_token.ts index fd02bd99..b999cbb5 100644 --- a/src/routes/v1/oauth2/token/refresh_token.ts +++ b/src/routes/v1/oauth2/token/refresh_token.ts @@ -1,6 +1,8 @@ import { FastifyReply, FastifyRequest } from 'fastify'; import { Meiling, Utils } from '../../../../common'; +import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; +import * as Sentry from '@sentry/node'; export async function oAuth2RefreshTokenHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -48,6 +50,14 @@ export async function oAuth2RefreshTokenHandler(req: FastifyRequest, rep: Fastif return; } + if (isSentryAvailable()) { + Sentry.setUser({ + id: user.id, + username: user.username, + ip_address: req.ip, + }); + } + const authorization = await Meiling.Authentication.Token.getAuthorization(token, type); if (!authorization) { Meiling.OAuth2.Error.sendOAuth2Error( diff --git a/src/routes/v1/oauth2/userinfo.ts b/src/routes/v1/oauth2/userinfo.ts index e127aec0..642cab19 100644 --- a/src/routes/v1/oauth2/userinfo.ts +++ b/src/routes/v1/oauth2/userinfo.ts @@ -1,6 +1,8 @@ import { FastifyReply, FastifyRequest } from 'fastify'; import JWT from 'jsonwebtoken'; import { Meiling } from '../../../common'; +import * as Sentry from '@sentry/node'; +import { isSentryAvailable } from '../../../common/sentry/tracer'; export async function oAuth2UserInfoHandler(req: FastifyRequest, rep: FastifyReply): Promise { const type = 'ACCESS_TOKEN'; @@ -39,6 +41,14 @@ export async function oAuth2UserInfoHandler(req: FastifyRequest, rep: FastifyRep return; } + if (isSentryAvailable()) { + Sentry.setUser({ + id: user.id, + username: user.username, + ip_address: req.ip, + }); + } + const isValid = await Meiling.Authentication.Token.isValid(token.token, type); if (!isValid) { Meiling.OAuth2.Error.sendOAuth2Error( diff --git a/yarn.lock b/yarn.lock index 383f3c6f..3c039be5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -131,6 +131,62 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.1.1.tgz#a6a75870618bbd19ff734c51af7dbe9f362c3265" integrity sha512-DCw8L/SS0IXqmj5IW/fMxOXiifnsfjBzDfRhf0j3NFWqvMCh9OtfjmXQZxVgI2mwvJLc/5jzXhkiWT39qS09dA== +"@sentry/core@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.9.0.tgz#fb9308e067a4b5794eb49f8bac303bb9c627b1a9" + integrity sha512-WVGd2hV7Clcpl7/GL8LsRr4Zk9o/7o4rZHfs1Qed5lMRNYcxiMwucC1CYILVpJqVfY+8vIRP9v9Ss9ta2VUikw== + dependencies: + "@sentry/hub" "7.9.0" + "@sentry/types" "7.9.0" + "@sentry/utils" "7.9.0" + tslib "^1.9.3" + +"@sentry/hub@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.9.0.tgz#29d4c796006282a20e5f78a1bb156d8f5eacd772" + integrity sha512-KzPbGCB5mONgsXEzqHy6uOaOuqLnhmFmSpGg+M03J6UJnJaNM7nrNp80MhStmjLMq6whEYVE07DrMAn3+iaQdg== + dependencies: + "@sentry/types" "7.9.0" + "@sentry/utils" "7.9.0" + tslib "^1.9.3" + +"@sentry/node@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.9.0.tgz#2ce1f9336a22cee3530ccd472081f71073af5116" + integrity sha512-MeggSCLyhUhsX3gRRvDhTADKYshuWjTRO/dUv3Jw+2xToSDvSWXJXDkIg5mCdlyOhh9/G+5xdWY58CfomzPZgg== + dependencies: + "@sentry/core" "7.9.0" + "@sentry/hub" "7.9.0" + "@sentry/types" "7.9.0" + "@sentry/utils" "7.9.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.9.0.tgz#0cbbf5b61ee76b934d2e4160a0ad3daf0001237b" + integrity sha512-X4HQ7jjP7qyc4saCtq31kLqQzcBpRNifE9KccgEbNXAkKoMrg5F22oUlfN2EcEWy0vm1C23juseDsOSSMXAM+A== + dependencies: + "@sentry/hub" "7.9.0" + "@sentry/types" "7.9.0" + "@sentry/utils" "7.9.0" + tslib "^1.9.3" + +"@sentry/types@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.9.0.tgz#8fa952865fda76f7c7c7fc6c84043979a22043ae" + integrity sha512-VGnUgELVMpGJCYW1triO+5XSyaPjB2Zu6esUgbb8iJ5bi+OWtxklixXgwhdaTb0FDzmRL/T/pckmrIuBTLySHQ== + +"@sentry/utils@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.9.0.tgz#497c41efe1b32974208ca68570e42c853b874f77" + integrity sha512-4f9TZvAVopgG7Lp1TcPSekSX1Ashk68Et4T8Y+60EVX5se19i0hpytbHWWwrXSrb3w0KpGANk0byoZkdaTgkYA== + dependencies: + "@sentry/types" "7.9.0" + tslib "^1.9.3" + "@simplewebauthn/server@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@simplewebauthn/server/-/server-5.4.0.tgz#f6a6d21620110fa3ad653e53758ffc1eb73a8c01" @@ -423,6 +479,13 @@ acorn@^8.7.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -879,7 +942,7 @@ cookie-signature@^1.1.0: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.0.tgz#4deed303f5f095e7a02c979e3fcb19157f5eaeea" integrity sha512-R0BOPfLGTitaKhgKROKZQN6iyq2iDQcH1DOF8nJoaWapguX5bC2w+Q/I9NmmM5lfcvEarnLZr+cCvmEYYSXvYA== -cookie@^0.4.0: +cookie@^0.4.0, cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== @@ -957,6 +1020,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +debug@4, debug@^4.0.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -964,13 +1034,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -1693,6 +1756,14 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -2176,6 +2247,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -3190,7 +3266,7 @@ ts-node@^9.0.0: source-map-support "^0.5.17" yn "3.1.1" -tslib@^1.8.1: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== From 29fda548e24e03278702b98902839fadb63e58ff Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 15:12:16 +0000 Subject: [PATCH 78/95] chore: add example --- config.env.js | 4 ++++ config.example.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config.env.js b/config.env.js index ccdcd093..1e0918db 100644 --- a/config.env.js +++ b/config.env.js @@ -112,6 +112,10 @@ module.exports = { /^true$/gi.test(process.env.NOTIFICATION_API_SETTINGS_USE_ALIMTALK_FOR_SOUTH_KOREA) || false, }, }, + sentry: { + serverName: process.env.SENTRY_SERVERNAME || undefined, + dsn: process.env.SENTRY_DSN || undefined, + }, baridegiApi: { version: Number(process.env.BARIDEGI_API_VERSION) || 1, host: process.env.BARIDEGI_API_HOST || 'https://baridegi.stella-api.dev', diff --git a/config.example.js b/config.example.js index 389cbd91..fa257ede 100644 --- a/config.example.js +++ b/config.example.js @@ -119,6 +119,10 @@ module.exports = { }, }, }, + sentry: { + serverName: undefined, + dsn: 'https://this-is-example-dsn.ingest.sentry.io/sample-baby', + }, notificationApi: { /** Use notification api? (Stella IT Proprietary, Set it to false if you don't use one.) */ enable: true, From 983f2781985237fbae685f2c2f7fc31be0f9fb0e Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 15:16:35 +0000 Subject: [PATCH 79/95] feat: sentry error handler --- src/index.ts | 6 ++++++ src/routes/v1/admin/index.ts | 3 +++ src/routes/v1/meiling/index.ts | 3 +++ 3 files changed, 12 insertions(+) diff --git a/src/index.ts b/src/index.ts index 04cdc6db..6627aebb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ import fastifyFormbody from 'fastify-formbody'; import fs from 'fs'; import { Meiling, Startup, Terminal } from './common'; import { setupSwaggerUI } from './common/fastify'; +import { isSentryAvailable, registerSentryTransaction } from './common/sentry/tracer'; import config from './resources/config'; import meilingPlugin from './routes'; @@ -32,6 +33,11 @@ const main = async () => { Terminal.Log.info('Preparing SwaggerUI for API Docs...'); setupSwaggerUI(app); + if (isSentryAvailable()) { + Terminal.Log.info('Registering Sentry...'); + app.register(registerSentryTransaction); + } + Terminal.Log.info('Initiating database connection...'); if (!(await Meiling.Database.testDatabase())) { Terminal.Log.error('Failed to connect! Please check if database is online.'); diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index 879dfdd9..256e5091 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -1,6 +1,7 @@ import { FastifyInstance, FastifyPluginOptions } from 'fastify'; import fastifyCors from 'fastify-cors'; import { Meiling, Utils } from '../../../common'; +import { sentryErrorHandler } from '../../../common/sentry/tracer'; import { NodeEnvironment } from '../../../interface'; import config from '../../../resources/config'; import { info as packageJson } from '../../../resources/package'; @@ -14,6 +15,8 @@ import usersAdminHandler from './users'; const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { app.setErrorHandler(async (_err, req, rep) => { const err = _err as Error; + sentryErrorHandler(err, req, rep); + if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { const mlError = err as Meiling.V1.Error.MeilingError; diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index b01b3f3e..8c6bc771 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -11,6 +11,7 @@ import { signinHandler } from './signin'; import { signoutPlugin } from './signout'; import { signupPlugin } from './signup/'; import { userPlugin } from './users'; +import { sentryErrorHandler } from '../../../common/sentry/tracer'; export interface FastifyRequestWithSession extends FastifyRequest { session: Meiling.V1.Interfaces.MeilingSession; @@ -33,6 +34,8 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: app.setErrorHandler(async (_err, req, rep) => { const err = _err as Error; + sentryErrorHandler(err, req, rep); + if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { const mlError = err as Meiling.V1.Error.MeilingError; From 0b6198a25858a3c5183efd08b3ab7837a995a53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Mon, 8 Aug 2022 00:31:07 +0900 Subject: [PATCH 80/95] chore: oops --- src/common/sentry/tracer.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/sentry/tracer.ts b/src/common/sentry/tracer.ts index 1533381e..f05b62ac 100644 --- a/src/common/sentry/tracer.ts +++ b/src/common/sentry/tracer.ts @@ -111,6 +111,8 @@ export function registerSentryTransaction(app: FastifyInstance, opts: FastifyPlu } }); }); + + done(); } export function sentryErrorHandler(error: Error, req: FastifyRequest, rep: FastifyReply) { From 6efa686c252cc0a1216e1d62e0801a9e2074d070 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 22:31:17 +0000 Subject: [PATCH 81/95] chore: prevent error handler from triggered from usual expected errors --- src/routes/v1/admin/index.ts | 4 +++- src/routes/v1/meiling/index.ts | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index 256e5091..2c39e338 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -15,11 +15,12 @@ import usersAdminHandler from './users'; const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void => { app.setErrorHandler(async (_err, req, rep) => { const err = _err as Error; - sentryErrorHandler(err, req, rep); if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { const mlError = err as Meiling.V1.Error.MeilingError; + if (mlError.type === Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR) sentryErrorHandler(err, req, rep); + return mlError.sendFastify(rep); } else { // This is internal server error. @@ -33,6 +34,7 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); error.loadError(_err); + sentryErrorHandler(err, req, rep); return error.sendFastify(rep); } } diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index 8c6bc771..81326f29 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -17,6 +17,10 @@ export interface FastifyRequestWithSession extends FastifyRequest { session: Meiling.V1.Interfaces.MeilingSession; } +export interface FastifyRequestWithUser extends FastifyRequestWithSession { + user: Meiling.Identity.User.UserInfoObject; +} + function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { app.addSchema({ $id: 'MeilingV1Error', @@ -34,11 +38,12 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: app.setErrorHandler(async (_err, req, rep) => { const err = _err as Error; - sentryErrorHandler(err, req, rep); if ((err as Meiling.V1.Error.MeilingError)._isMeiling === true) { const mlError = err as Meiling.V1.Error.MeilingError; + if (mlError.type === Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR) sentryErrorHandler(err, req, rep); + return mlError.sendFastify(rep); } else { // This is internal server error. @@ -52,6 +57,8 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); error.loadError(_err); + sentryErrorHandler(err, req, rep); + return error.sendFastify(rep); } } From f508260f944b88acb5525632faa8be18232c75cf Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sun, 7 Aug 2022 22:54:57 +0000 Subject: [PATCH 82/95] chore: use contexts --- src/common/sentry/tracer.ts | 86 +++++++++++++------ src/routes/v1/meiling/index.ts | 3 +- src/routes/v1/meiling/users/actions/index.ts | 10 +-- .../v1/oauth2/token/authorization_code.ts | 9 +- src/routes/v1/oauth2/token/device_code.ts | 9 +- src/routes/v1/oauth2/token/refresh_token.ts | 9 +- src/routes/v1/oauth2/userinfo.ts | 9 +- 7 files changed, 74 insertions(+), 61 deletions(-) diff --git a/src/common/sentry/tracer.ts b/src/common/sentry/tracer.ts index f05b62ac..bb298e9e 100644 --- a/src/common/sentry/tracer.ts +++ b/src/common/sentry/tracer.ts @@ -2,7 +2,7 @@ import { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } f import * as Sentry from '@sentry/node'; import Tracing, { Transaction } from '@sentry/tracing'; import config from '../../resources/config'; -import { FastifyRequestWithSession } from '../../routes/v1/meiling'; +import { FastifyRequestWithSession, FastifyRequestWithUser } from '../../routes/v1/meiling'; import { getSessionFromRequest } from '../meiling/v1/session'; import { Meiling } from '..'; @@ -86,41 +86,79 @@ export function registerSentryTransaction(app: FastifyInstance, opts: FastifyPlu request: req4Sentry, }, ); - - Sentry.setUser({ - ip_address: req.ip, - }); }); app.addHook('onResponse', async (req, rep) => { - setImmediate(() => { - const tx = getSentryTransaction(req); - if (tx) { - tx.setData('url', req.url); - tx.setData('query', req.query); - if (typeof req.body === 'object') { - tx.setData('body', req.body); - } - tx.setHttpStatus(rep.statusCode); - - if ((req as FastifyRequestWithSession).session) { - tx.setData('session', getSessionFromRequest(req)); + Sentry.withScope(async (scope) => { + setImmediate(async () => { + const tx = getSentryTransaction(req); + + if (tx) { + const session = (req as FastifyRequestWithSession).session; + if (session) { + const userBase = (req as FastifyRequestWithUser).user; + + if (userBase) { + const user = await Meiling.Identity.User.getDetailedInfo(userBase); + scope.setUser({ + id: user?.id, + ip: req.ip, + username: user?.username, + email: user?.emails.find((n) => n.isPrimary)?.email, + }); + } + + tx.setData('session', session); + } + + tx.setData('url', req.url); + tx.setData('query', req.query); + + if (typeof req.body === 'object') { + tx.setData('body', req.body); + } + + tx.setHttpStatus(rep.statusCode); + + tx.finish(); } - - tx.finish(); - } + }); }); }); - + done(); } export function sentryErrorHandler(error: Error, req: FastifyRequest, rep: FastifyReply) { - Sentry.withScope((scope) => { + Sentry.withScope(async (scope) => { + const session = (req as FastifyRequestWithSession).session; + if (session) { + const userBase = (req as FastifyRequestWithUser).user; + + if (userBase) { + const user = await Meiling.Identity.User.getDetailedInfo(userBase); + scope.setUser({ + id: user?.id, + ip: req.ip, + username: user?.username, + email: user?.emails.find((n) => n.isPrimary)?.email, + }); + } else { + scope.setUser({ + ip: req.ip, + }); + } + scope.setTag('path', req.url); + scope.setContext('query', req.query || ({} as any)); + + scope.setContext('session', session as any); + } + if ((error as Meiling.V1.Error.MeilingError)._isMeiling === true) { - scope.setTag('is_meiling', true); - Sentry.captureException(error); + scope.setTag('meiling', true); } + + Sentry.captureException(error); }); } diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index 81326f29..83950e0e 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -12,13 +12,14 @@ import { signoutPlugin } from './signout'; import { signupPlugin } from './signup/'; import { userPlugin } from './users'; import { sentryErrorHandler } from '../../../common/sentry/tracer'; +import { User as UserModel } from '@prisma/client'; export interface FastifyRequestWithSession extends FastifyRequest { session: Meiling.V1.Interfaces.MeilingSession; } export interface FastifyRequestWithUser extends FastifyRequestWithSession { - user: Meiling.Identity.User.UserInfoObject; + user: UserModel; } function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index 8e0b78d3..b3424aa4 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -11,6 +11,7 @@ import userSecurityPlugin from './security'; import userPasswordsPlugin from './security/passwords'; import * as Sentry from '@sentry/node'; import { isSentryAvailable } from '../../../../../common/sentry/tracer'; +import { FastifyRequestWithUser } from '../..'; export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void) { // /v1/meiling/user/:userId/action @@ -26,14 +27,7 @@ export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOpti ); } - if (isSentryAvailable()) { - Sentry.setUser({ - id: userBase.id, - username: userBase.username, - email: userBase.emails.find((n) => n.isPrimary)?.email, - ip_address: req.ip, - }); - } + (req as FastifyRequestWithUser).user = userBase; }); app.get('/', userGetInfo); diff --git a/src/routes/v1/oauth2/token/authorization_code.ts b/src/routes/v1/oauth2/token/authorization_code.ts index 01f4ff60..d53bd971 100644 --- a/src/routes/v1/oauth2/token/authorization_code.ts +++ b/src/routes/v1/oauth2/token/authorization_code.ts @@ -4,6 +4,7 @@ import { Meiling, Utils } from '../../../../common'; import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; import * as Sentry from '@sentry/node'; +import { FastifyRequestWithUser } from '../../meiling'; export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -61,13 +62,7 @@ export async function oAuth2AuthorizationCodeHandler(req: FastifyRequest, rep: F return; } - if (isSentryAvailable()) { - Sentry.setUser({ - id: user.id, - username: user.username, - ip_address: req.ip, - }); - } + (req as FastifyRequestWithUser).user = user; const authorization = await Meiling.Authentication.Token.getAuthorization(token, type); if (!authorization) { diff --git a/src/routes/v1/oauth2/token/device_code.ts b/src/routes/v1/oauth2/token/device_code.ts index e0d96380..8cd30a4c 100644 --- a/src/routes/v1/oauth2/token/device_code.ts +++ b/src/routes/v1/oauth2/token/device_code.ts @@ -3,6 +3,7 @@ import { Meiling, Utils } from '../../../../common'; import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; import * as Sentry from '@sentry/node'; +import { FastifyRequestWithUser } from '../../meiling'; export async function oAuth2DeviceCodeHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -89,13 +90,7 @@ export async function oAuth2DeviceCodeHandler(req: FastifyRequest, rep: FastifyR return; } - if (isSentryAvailable()) { - Sentry.setUser({ - id: user.id, - username: user.username, - ip_address: req.ip, - }); - } + (req as FastifyRequestWithUser).user = user; const scope = permissions.map((p) => p.name).join(' '); const scopes = scope.split(' '); diff --git a/src/routes/v1/oauth2/token/refresh_token.ts b/src/routes/v1/oauth2/token/refresh_token.ts index b999cbb5..85e60d2d 100644 --- a/src/routes/v1/oauth2/token/refresh_token.ts +++ b/src/routes/v1/oauth2/token/refresh_token.ts @@ -3,6 +3,7 @@ import { Meiling, Utils } from '../../../../common'; import { isSentryAvailable } from '../../../../common/sentry/tracer'; import { parseClientInfo } from '../common'; import * as Sentry from '@sentry/node'; +import { FastifyRequestWithUser } from '../../meiling'; export async function oAuth2RefreshTokenHandler(req: FastifyRequest, rep: FastifyReply): Promise { const result = parseClientInfo(req); @@ -50,13 +51,7 @@ export async function oAuth2RefreshTokenHandler(req: FastifyRequest, rep: Fastif return; } - if (isSentryAvailable()) { - Sentry.setUser({ - id: user.id, - username: user.username, - ip_address: req.ip, - }); - } + (req as FastifyRequestWithUser).user = user; const authorization = await Meiling.Authentication.Token.getAuthorization(token, type); if (!authorization) { diff --git a/src/routes/v1/oauth2/userinfo.ts b/src/routes/v1/oauth2/userinfo.ts index 642cab19..86e89ee5 100644 --- a/src/routes/v1/oauth2/userinfo.ts +++ b/src/routes/v1/oauth2/userinfo.ts @@ -3,6 +3,7 @@ import JWT from 'jsonwebtoken'; import { Meiling } from '../../../common'; import * as Sentry from '@sentry/node'; import { isSentryAvailable } from '../../../common/sentry/tracer'; +import { FastifyRequestWithUser } from '../meiling'; export async function oAuth2UserInfoHandler(req: FastifyRequest, rep: FastifyReply): Promise { const type = 'ACCESS_TOKEN'; @@ -41,13 +42,7 @@ export async function oAuth2UserInfoHandler(req: FastifyRequest, rep: FastifyRep return; } - if (isSentryAvailable()) { - Sentry.setUser({ - id: user.id, - username: user.username, - ip_address: req.ip, - }); - } + (req as FastifyRequestWithUser).user = user; const isValid = await Meiling.Authentication.Token.isValid(token.token, type); if (!isValid) { From 8255859efbb9dd4678889987025f7789c22a0687 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 03:46:31 +0000 Subject: [PATCH 83/95] fix: TOTPs are generated wrong --- .../v1/meiling/users/actions/security/otp/actions/post.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts b/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts index 32d478b1..6b67ac2e 100644 --- a/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts +++ b/src/routes/v1/meiling/users/actions/security/otp/actions/post.ts @@ -67,8 +67,11 @@ async function userOTPActionPostKey(req: FastifyRequest, rep: FastifyReply): Pro }, }, data: { - name, - secret, + type: 'OTP', + data: { + name, + secret, + }, }, method: dbType as AuthenticationMethod, allowTwoFactor: true, From 483446b8d03c67f73b86dd09f82d1cf484af9caa Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 05:11:00 +0000 Subject: [PATCH 84/95] chore: improve sentry --- src/common/sentry/tracer.ts | 17 ++++++++++++----- src/routes/v1/meiling/index.ts | 2 ++ .../users/actions/emails/actions/index.ts | 2 ++ src/routes/v1/meiling/users/actions/index.ts | 4 ++++ .../users/actions/phones/actions/index.ts | 3 +++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/common/sentry/tracer.ts b/src/common/sentry/tracer.ts index bb298e9e..83d2169b 100644 --- a/src/common/sentry/tracer.ts +++ b/src/common/sentry/tracer.ts @@ -67,6 +67,8 @@ export function registerSentryTransaction(app: FastifyInstance, opts: FastifyPlu integrations: [new Sentry.Integrations.Http({ tracing: true })], }); + app.decorateRequest('sentryTransaction', undefined); + app.addHook('onRequest', async (req) => { let traceData; if (req.headers && typeof req.headers['sentry-trace'] === 'string') { @@ -75,8 +77,7 @@ export function registerSentryTransaction(app: FastifyInstance, opts: FastifyPlu } const req4Sentry = convertReq4Sentry(req); - - (req as any).sentryTransaction = Sentry.startTransaction( + (app as any).sentryTransaction = Sentry.startTransaction( { op: 'http.server', name: `${req.method} ${req.url}`, @@ -148,10 +149,16 @@ export function sentryErrorHandler(error: Error, req: FastifyRequest, rep: Fasti ip: req.ip, }); } - scope.setTag('path', req.url); - scope.setContext('query', req.query || ({} as any)); + scope.setExtra('session', session as any); + } + + scope.setLevel('error'); + scope.setTag('method', req.method); + scope.setTag('path', req.url); + scope.setExtra('query', req.query || ({} as any)); - scope.setContext('session', session as any); + if (req.headers['content-type'] === 'application/json' && req.body && typeof req.body === 'object') { + scope.setExtra('body', req.body); } if ((error as Meiling.V1.Error.MeilingError)._isMeiling === true) { diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index 83950e0e..2e207003 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -87,6 +87,8 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: } function sessionRequiredPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.decorateRequest('session', undefined); + app.addHook('onRequest', async (req, rep) => { const session = await Meiling.V1.Session.getSessionFromRequest(req); if (!session) { diff --git a/src/routes/v1/meiling/users/actions/emails/actions/index.ts b/src/routes/v1/meiling/users/actions/emails/actions/index.ts index 7f742ee2..0e243a75 100644 --- a/src/routes/v1/meiling/users/actions/emails/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/emails/actions/index.ts @@ -4,6 +4,8 @@ import { FastifyRequestWithSession } from '../../../..'; import { Meiling } from '../../../../../../../common'; function userEmailActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.decorateRequest('email', undefined); + app.addHook('onRequest', async (req, rep) => { const session = (req as FastifyRequestWithSession).session; const userRawSession = session.user; diff --git a/src/routes/v1/meiling/users/actions/index.ts b/src/routes/v1/meiling/users/actions/index.ts index b3424aa4..7ded1fec 100644 --- a/src/routes/v1/meiling/users/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/index.ts @@ -14,6 +14,10 @@ import { isSentryAvailable } from '../../../../../common/sentry/tracer'; import { FastifyRequestWithUser } from '../..'; export function userActionsHandler(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void) { + if (!app.hasRequestDecorator('user')) { + app.decorateRequest('user', undefined); + } + // /v1/meiling/user/:userId/action // TODO: Implement authentication app.addHook('onRequest', async (req, rep) => { diff --git a/src/routes/v1/meiling/users/actions/phones/actions/index.ts b/src/routes/v1/meiling/users/actions/phones/actions/index.ts index 70e93b53..23e477e0 100644 --- a/src/routes/v1/meiling/users/actions/phones/actions/index.ts +++ b/src/routes/v1/meiling/users/actions/phones/actions/index.ts @@ -4,6 +4,8 @@ import { FastifyRequestWithSession } from '../../../..'; import { Meiling } from '../../../../../../../common'; function userPhoneActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: () => void): void { + app.decorateRequest('phone', undefined); + app.addHook('onRequest', async (req, rep) => { const session = (req as FastifyRequestWithSession).session; const userRawSession = session.user; @@ -29,6 +31,7 @@ function userPhoneActionPlugin(app: FastifyInstance, opts: FastifyPluginOptions, } (req as any).phone = matchingPhone; + Object.freeze((req as any).phone); }); From 6619b53aa03644f034de12342e214076930b9e94 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 05:14:14 +0000 Subject: [PATCH 85/95] chore: push with query if available --- src/common/sentry/tracer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/common/sentry/tracer.ts b/src/common/sentry/tracer.ts index 83d2169b..c594a8fa 100644 --- a/src/common/sentry/tracer.ts +++ b/src/common/sentry/tracer.ts @@ -155,7 +155,10 @@ export function sentryErrorHandler(error: Error, req: FastifyRequest, rep: Fasti scope.setLevel('error'); scope.setTag('method', req.method); scope.setTag('path', req.url); - scope.setExtra('query', req.query || ({} as any)); + + if (typeof req.query === 'object') { + scope.setExtra('query', req.query); + } if (req.headers['content-type'] === 'application/json' && req.body && typeof req.body === 'object') { scope.setExtra('body', req.body); From 5a8d12c7f9a8aec30c025218c77c131541e75e9c Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 05:23:46 +0000 Subject: [PATCH 86/95] chore: remove space from response before validate --- src/common/meiling/authentication/validate.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/meiling/authentication/validate.ts b/src/common/meiling/authentication/validate.ts index ff9b01d8..f543890e 100644 --- a/src/common/meiling/authentication/validate.ts +++ b/src/common/meiling/authentication/validate.ts @@ -110,6 +110,10 @@ export async function validateWebAuthn( } export function validateOTP(challengeResponse: string, secret: string) { + if (challengeResponse.includes(' ')) { + challengeResponse = challengeResponse.replace(/ /g, ''); + } + return SpeakEasy.totp.verify({ secret, encoding: 'base32', From bf931fac9a4d0d9b6e6799eeaad0550b45a67594 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 05:24:51 +0000 Subject: [PATCH 87/95] chore: add more data --- src/routes/v1/meiling/users/actions/security/otp/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/v1/meiling/users/actions/security/otp/index.ts b/src/routes/v1/meiling/users/actions/security/otp/index.ts index d5680e4f..5d835a50 100644 --- a/src/routes/v1/meiling/users/actions/security/otp/index.ts +++ b/src/routes/v1/meiling/users/actions/security/otp/index.ts @@ -30,7 +30,7 @@ function userOTPPlugin(app: FastifyInstance, opts: FastifyPluginOptions, done: ( otps.map((n) => ({ id: n.id, createdAt: n.createdAt, - name: (n.data as any)?.name, + name: (n.data as any)?.data?.name, })), ); }); From d820a4b8715b9eeab4aedf209769e322c1855183 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 05:41:52 +0000 Subject: [PATCH 88/95] chore: skip challenge on OTP --- src/routes/v1/meiling/signin.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/v1/meiling/signin.ts b/src/routes/v1/meiling/signin.ts index c44cb7ca..104b2c14 100644 --- a/src/routes/v1/meiling/signin.ts +++ b/src/routes/v1/meiling/signin.ts @@ -385,9 +385,11 @@ please request this endpoint without challengeResponse field to request challeng const challenge = extendedAuthSession.challenge; const authorizedUsers: UserModel[] = []; - if (challenge === undefined) { - throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, `challenge is missing.`); - return; + if (signinMethod !== ExtendedAuthMethods.OTP) { + if (challenge === undefined) { + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST, `challenge is missing.`); + return; + } } const authMethodCheckPromises = []; From 5365cc354820d307244045c0e835a58cbd136d1e Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 06:18:54 +0000 Subject: [PATCH 89/95] chore: update convert clause --- src/routes/v1/admin/apps/index.ts | 2 +- src/routes/v1/admin/sessions/index.ts | 2 +- src/routes/v1/admin/users/index.ts | 4 ++-- src/routes/v1/admin/users/sessions.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/admin/apps/index.ts b/src/routes/v1/admin/apps/index.ts index dd940d23..b7df54e9 100644 --- a/src/routes/v1/admin/apps/index.ts +++ b/src/routes/v1/admin/apps/index.ts @@ -14,7 +14,7 @@ const appsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done app.get('/', async (req, rep) => { let { query } = (req.query as any) || {}; const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; - if (typeof query !== 'string') query = query.toString(); + if (['bigint', 'boolean', 'number'].includes(typeof query)) query = query.toString(); const paginationDetails: { skip?: number; diff --git a/src/routes/v1/admin/sessions/index.ts b/src/routes/v1/admin/sessions/index.ts index 2a1110fe..e69fc9f9 100644 --- a/src/routes/v1/admin/sessions/index.ts +++ b/src/routes/v1/admin/sessions/index.ts @@ -23,7 +23,7 @@ const sessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, let { query } = (req.query as any) || {}; const { pageSize = 20, page = 1 } = (req.query as any) || {}; - if (typeof query !== 'string') query = query.toString(); + if (['bigint', 'boolean', 'number'].includes(typeof query)) query = query.toString(); const paginationDetails: { skip?: number; diff --git a/src/routes/v1/admin/users/index.ts b/src/routes/v1/admin/users/index.ts index 8a776896..c7ca9617 100644 --- a/src/routes/v1/admin/users/index.ts +++ b/src/routes/v1/admin/users/index.ts @@ -58,7 +58,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don app.get('/', async (req, rep) => { let { query } = (req.query as any) || {}; const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; - if (typeof query !== 'string') query = query.toString(); + if (['bigint', 'boolean', 'number'].includes(typeof query)) query = query.toString(); const paginationDetails: { skip?: number; @@ -134,7 +134,7 @@ const usersAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, don app.get('/count', async (req, rep) => { let { query } = (req.query as any) || {}; const { rawQuery = false } = (req.query as any) || {}; - if (typeof query === 'number') query = query.toString(); + if (typeof query !== 'string' && query !== undefined) query = query.toString(); let prismaQuery = undefined; diff --git a/src/routes/v1/admin/users/sessions.ts b/src/routes/v1/admin/users/sessions.ts index 0efb8ebb..4b032fe7 100644 --- a/src/routes/v1/admin/users/sessions.ts +++ b/src/routes/v1/admin/users/sessions.ts @@ -13,7 +13,7 @@ const userSessionsAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptio let { query } = (req.query as any) || {}; const { pageSize = 20, page = 1, rawQuery = false } = (req.query as any) || {}; - if (typeof query !== 'string') query = query.toString(); + if (['bigint', 'boolean', 'number'].includes(typeof query)) query = query.toString(); const paginationDetails: { skip?: number; From 5678f164103b33bc77e4199cd873454df59c3279 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 06:22:58 +0000 Subject: [PATCH 90/95] chore: allow email by default --- src/routes/v1/meiling/signup/signup.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/routes/v1/meiling/signup/signup.ts b/src/routes/v1/meiling/signup/signup.ts index be674a15..f2dfd0b8 100644 --- a/src/routes/v1/meiling/signup/signup.ts +++ b/src/routes/v1/meiling/signup/signup.ts @@ -144,6 +144,15 @@ export async function signupHandler(req: FastifyRequest, rep: FastifyReply): Pro data: { type: 'SMS', }, + allowPasswordReset: false, + allowSingleFactor: false, + allowTwoFactor: false, + }, + { + method: 'EMAIL', + data: { + type: 'EMAIL', + }, allowPasswordReset: true, allowSingleFactor: false, allowTwoFactor: true, From 2aaee9b201dc013e81a758218e8643e9a523a522 Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Mon, 8 Aug 2022 10:46:42 +0000 Subject: [PATCH 91/95] chore: implement MFA on administrative login --- src/routes/v1/admin/auth/index.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/routes/v1/admin/auth/index.ts b/src/routes/v1/admin/auth/index.ts index 9edc0c82..c6301dbf 100644 --- a/src/routes/v1/admin/auth/index.ts +++ b/src/routes/v1/admin/auth/index.ts @@ -62,7 +62,18 @@ const authAdminHandler = (app: FastifyInstance, opts: FastifyPluginOptions, done rep.send({ success: true }); } else { - // TODO: Implement it properly + await Meiling.V1.Session.setExtendedAuthenticationSession( + { + headers: { + authorization: 'Bearer ' + token, + }, + } as any, + { + id: user.id, + type: Meiling.V1.Interfaces.SigninType.TWO_FACTOR_AUTH, + }, + ); + throw new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.TWO_FACTOR_AUTHENTICATION_REQUIRED); } }); From aa8c54f76802370e429b418f141fdd2995bff12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Wed, 17 Aug 2022 17:40:19 +0900 Subject: [PATCH 92/95] chore: remove debug console.log --- src/common/meiling/v1/error/error.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/meiling/v1/error/error.ts b/src/common/meiling/v1/error/error.ts index 438f745a..ee7332f2 100644 --- a/src/common/meiling/v1/error/error.ts +++ b/src/common/meiling/v1/error/error.ts @@ -89,10 +89,12 @@ export class MeilingError extends Error { public description?: string; constructor(type: ErrorType, description?: string) { - super(description); + const internalDesc = description ? description : type; + + super(internalDesc); this.type = type; this.name = 'meiliNG Error'; - this.message = description ? description : type; + this.message = internalDesc; this.description = description; } @@ -102,7 +104,6 @@ export class MeilingError extends Error { public static load(error: MeilingError) { const mlError = new MeilingError(error.type, error.description); - console.log(mlError); return mlError; } From 881679417991ce9a71c4266eb26191ce64778c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Wed, 17 Aug 2022 17:47:23 +0900 Subject: [PATCH 93/95] chore: streamlined error handler --- src/routes/v1/admin/index.ts | 27 +++++++++++---------------- src/routes/v1/meiling/index.ts | 18 ++++++------------ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index 2c39e338..eee61c57 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -23,20 +23,15 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( return mlError.sendFastify(rep); } else { - // This is internal server error. - if (_err.validation) { - // if it is validation issue, the error type is INVALID_REQUEST - const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); - error.loadError(_err); - - return error.sendFastify(rep); - } else { - const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); - error.loadError(_err); - - sentryErrorHandler(err, req, rep); - return error.sendFastify(rep); - } + + const type = (_err.validation) ? + Meiling.V1.Error.ErrorType.INVALID_REQUEST : + Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; + + const error = new Meiling.V1.Error.MeilingError(type); + error.loadError(_err); + + return error.sendFastify(rep); } }); @@ -49,8 +44,8 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( config.node.environment === NodeEnvironment.Development ? '*' : config?.admin?.frontend?.url - ? config.admin.frontend.url - : config.frontend.url, + ? config.admin.frontend.url + : config.frontend.url, }); app.addHook('onRequest', (req, rep, next) => { diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index 2e207003..abb07526 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -47,21 +47,15 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: return mlError.sendFastify(rep); } else { - // This is internal server error. - if (_err.validation) { - // if it is validation issue, the error type is INVALID_REQUEST - const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INVALID_REQUEST); - error.loadError(_err); - return error.sendFastify(rep); - } else { - const error = new Meiling.V1.Error.MeilingError(Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR); - error.loadError(_err); + const type = (_err.validation) ? + Meiling.V1.Error.ErrorType.INVALID_REQUEST : + Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; - sentryErrorHandler(err, req, rep); + const error = new Meiling.V1.Error.MeilingError(type); + error.loadError(_err); - return error.sendFastify(rep); - } + return error.sendFastify(rep); } }); From 1afdc479a5279358a2a63e13ae3a21677ee5ecfd Mon Sep 17 00:00:00 2001 From: Alex4386 Date: Sat, 20 Aug 2022 13:40:40 +0000 Subject: [PATCH 94/95] fix: lints --- src/routes/v1/admin/index.ts | 11 +++++------ src/routes/v1/meiling/index.ts | 7 +++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/routes/v1/admin/index.ts b/src/routes/v1/admin/index.ts index eee61c57..6121387d 100644 --- a/src/routes/v1/admin/index.ts +++ b/src/routes/v1/admin/index.ts @@ -23,10 +23,9 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( return mlError.sendFastify(rep); } else { - - const type = (_err.validation) ? - Meiling.V1.Error.ErrorType.INVALID_REQUEST : - Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; + const type = _err.validation + ? Meiling.V1.Error.ErrorType.INVALID_REQUEST + : Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; const error = new Meiling.V1.Error.MeilingError(type); error.loadError(_err); @@ -44,8 +43,8 @@ const adminV1Plugin = (app: FastifyInstance, opts: FastifyPluginOptions, done: ( config.node.environment === NodeEnvironment.Development ? '*' : config?.admin?.frontend?.url - ? config.admin.frontend.url - : config.frontend.url, + ? config.admin.frontend.url + : config.frontend.url, }); app.addHook('onRequest', (req, rep, next) => { diff --git a/src/routes/v1/meiling/index.ts b/src/routes/v1/meiling/index.ts index abb07526..079ae4fa 100644 --- a/src/routes/v1/meiling/index.ts +++ b/src/routes/v1/meiling/index.ts @@ -47,10 +47,9 @@ function meilingV1Plugin(app: FastifyInstance, opts: FastifyPluginOptions, done: return mlError.sendFastify(rep); } else { - - const type = (_err.validation) ? - Meiling.V1.Error.ErrorType.INVALID_REQUEST : - Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; + const type = _err.validation + ? Meiling.V1.Error.ErrorType.INVALID_REQUEST + : Meiling.V1.Error.ErrorType.INTERNAL_SERVER_ERROR; const error = new Meiling.V1.Error.MeilingError(type); error.loadError(_err); From 0ae656786cc204e78b8385ae689636801da0bc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=9D=AC=20=28Alex=20Park=29?= Date: Mon, 22 Aug 2022 23:17:39 +0900 Subject: [PATCH 95/95] chore: lets go! 0.9.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 162756cc..6322c3c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meiling", - "version": "0.9.0-snapshot", + "version": "0.9.0", "description": "An Opensource Next Generation \"Gatekeeper\" with oAuth2 Authentication Provider and OpenID Connect Server", "main": "dist/", "repository": "https://github.com/meili-NG/meiliNG",