diff --git a/packages/nocodb/src/lib/controllers/user/user.ctl.ts b/packages/nocodb/src/lib/controllers/user/user.ctl.ts index 70d17b40ef..07bbbbcf81 100644 --- a/packages/nocodb/src/lib/controllers/user/user.ctl.ts +++ b/packages/nocodb/src/lib/controllers/user/user.ctl.ts @@ -1,139 +1,23 @@ import { Request, Response } from 'express'; -import { TableType, validatePassword } from 'nocodb-sdk'; -import { T } from 'nc-help'; - -const { isEmail } = require('validator'); import * as ejs from 'ejs'; - -import bcrypt from 'bcryptjs'; import { promisify } from 'util'; -const { v4: uuidv4 } = require('uuid'); - import passport from 'passport'; -import { getAjvValidatorMw } from '../../meta/api/helpers'; import catchError, { NcError } from '../../meta/helpers/catchError'; import extractProjectIdAndAuthenticate from '../../meta/helpers/extractProjectIdAndAuthenticate'; import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; -import NcPluginMgrv2 from '../../meta/helpers/NcPluginMgrv2'; import { Audit, User } from '../../models'; import Noco from '../../Noco'; import { userService } from '../../services'; -export async function signup(req: Request, res: Response) { - const { - email: _email, - firstname, - lastname, - token, - ignore_subscribe, - } = req.body; - let { password } = req.body; - - // validate password and throw error if password is satisfying the conditions - const { valid, error } = validatePassword(password); - if (!valid) { - NcError.badRequest(`Password : ${error}`); - } - - if (!isEmail(_email)) { - NcError.badRequest(`Invalid email`); - } - - const email = _email.toLowerCase(); - - let user = await User.getByEmail(email); - - if (user) { - if (token) { - if (token !== user.invite_token) { - NcError.badRequest(`Invalid invite url`); - } else if (user.invite_token_expires < new Date()) { - NcError.badRequest( - 'Expired invite url, Please contact super admin to get a new invite url' - ); - } - } else { - // todo : opening up signup for timebeing - // return next(new Error(`Email '${email}' already registered`)); - } - } - - const salt = await promisify(bcrypt.genSalt)(10); - password = await promisify(bcrypt.hash)(password, salt); - const email_verification_token = uuidv4(); - - if (!ignore_subscribe) { - T.emit('evt_subscribe', email); - } - - if (user) { - if (token) { - await User.update(user.id, { - firstname, - lastname, - salt, - password, - email_verification_token, - invite_token: null, - invite_token_expires: null, - email: user.email, - }); - } else { - NcError.badRequest('User already exist'); - } - } else { - await userService.registerNewUserIfAllowed({ - firstname, - lastname, - email, - salt, - password, - email_verification_token, - }); - } - user = await User.getByEmail(email); - - try { - const template = (await import('./ui/emailTemplates/verify')).default; - await ( - await NcPluginMgrv2.emailAdapter() - ).mailSend({ - to: email, - subject: 'Verify email', - html: ejs.render(template, { - verifyLink: - (req as any).ncSiteUrl + - `/email/verify/${user.email_verification_token}`, - }), - }); - } catch (e) { - console.log( - 'Warning : `mailSend` failed, Please configure emailClient configuration.' - ); - } - await promisify((req as any).login.bind(req))(user); - const refreshToken = userService.randomTokenString(); - await User.update(user.id, { - refresh_token: refreshToken, - email: user.email, - }); - - setTokenCookie(res, refreshToken); - - user = (req as any).user; - - await Audit.insert({ - op_type: 'AUTHENTICATION', - op_sub_type: 'SIGNUP', - user: user.email, - description: `signed up `, - ip: (req as any).clientIp, - }); - - res.json({ - token: userService.genJwt(user, Noco.getConfig()), - } as any); +export async function signup(req: Request, res): Promise { + res.json( + await userService.signup({ + body: req.body, + req, + res, + }) + ); } async function successfulSignIn({ @@ -221,15 +105,6 @@ async function googleSignin(req, res, next) { )(req, res, next); } -function setTokenCookie(res: Response, token): void { - // create http only cookie with refresh token that expires in 7 days - const cookieOptions = { - httpOnly: true, - expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), - }; - res.cookie('refresh_token', token, cookieOptions); -} - async function me(req, res): Promise { res.json(req?.session?.passport?.user ?? {}); } @@ -284,35 +159,6 @@ async function emailVerification(req, res): Promise { res.json({ msg: 'Email verified successfully' }); } -async function refreshToken(req, res): Promise { - try { - if (!req?.cookies?.refresh_token) { - return res.status(400).json({ msg: 'Missing refresh token' }); - } - - const user = await User.getByRefreshToken(req.cookies.refresh_token); - - if (!user) { - return res.status(400).json({ msg: 'Invalid refresh token' }); - } - - const refreshToken = userService.randomTokenString(); - - await User.update(user.id, { - email: user.email, - refresh_token: refreshToken, - }); - - setTokenCookie(res, refreshToken); - - res.json({ - token: userService.genJwt(user, Noco.getConfig()), - } as any); - } catch (e) { - return res.status(400).json({ msg: e.message }); - } -} - async function renderPasswordReset(req, res): Promise { try { res.send( @@ -329,32 +175,15 @@ async function renderPasswordReset(req, res): Promise { const mapRoutes = (router) => { // todo: old api - /auth/signup?tool=1 - router.post( - '/auth/user/signup', - getAjvValidatorMw('swagger.json#/components/schemas/SignUpReq'), - catchError(signup) - ); - router.post( - '/auth/user/signin', - getAjvValidatorMw('swagger.json#/components/schemas/SignInReq'), - catchError(signin) - ); + router.post('/auth/user/signup', catchError(signup)); + router.post('/auth/user/signin', catchError(signin)); router.get('/auth/user/me', extractProjectIdAndAuthenticate, catchError(me)); - router.post( - '/auth/password/forgot', - getAjvValidatorMw('swagger.json#/components/schemas/ForgotPasswordReq'), - catchError(passwordForgot) - ); + router.post('/auth/password/forgot', catchError(passwordForgot)); router.post('/auth/token/validate/:tokenId', catchError(tokenValidate)); - router.post( - '/auth/password/reset/:tokenId', - getAjvValidatorMw('swagger.json#/components/schemas/PasswordResetReq'), - catchError(passwordReset) - ); + router.post('/auth/password/reset/:tokenId', catchError(passwordReset)); router.post('/auth/email/validate/:tokenId', catchError(emailVerification)); router.post( '/user/password/change', - getAjvValidatorMw('swagger.json#/components/schemas/PasswordChangeReq'), ncMetaAclMw(passwordChange, 'passwordChange') ); router.post('/auth/token/refresh', catchError(refreshToken)); @@ -372,33 +201,20 @@ const mapRoutes = (router) => { ); // deprecated APIs - router.post( - '/api/v1/db/auth/user/signup', - getAjvValidatorMw('swagger.json#/components/schemas/SignUpReq'), - catchError(signup) - ); - router.post( - '/api/v1/db/auth/user/signin', - getAjvValidatorMw('swagger.json#/components/schemas/SignInReq'), - catchError(signin) - ); + router.post('/api/v1/db/auth/user/signup', catchError(signup)); + router.post('/api/v1/db/auth/user/signin', catchError(signin)); router.get( '/api/v1/db/auth/user/me', extractProjectIdAndAuthenticate, catchError(me) ); - router.post( - '/api/v1/db/auth/password/forgot', - getAjvValidatorMw('swagger.json#/components/schemas/ForgotPasswordReq'), - catchError(passwordForgot) - ); + router.post('/api/v1/db/auth/password/forgot', catchError(passwordForgot)); router.post( '/api/v1/db/auth/token/validate/:tokenId', catchError(tokenValidate) ); router.post( '/api/v1/db/auth/password/reset/:tokenId', - getAjvValidatorMw('swagger.json#/components/schemas/PasswordResetReq'), catchError(passwordReset) ); router.post( @@ -407,7 +223,6 @@ const mapRoutes = (router) => { ); router.post( '/api/v1/db/auth/password/change', - getAjvValidatorMw('swagger.json#/components/schemas/PasswordChangeReq'), ncMetaAclMw(passwordChange, 'passwordChange') ); router.post('/api/v1/db/auth/token/refresh', catchError(refreshToken)); @@ -417,26 +232,14 @@ const mapRoutes = (router) => { ); // new API - router.post( - '/api/v1/auth/user/signup', - getAjvValidatorMw('swagger.json#/components/schemas/SignUpReq'), - catchError(signup) - ); - router.post( - '/api/v1/auth/user/signin', - getAjvValidatorMw('swagger.json#/components/schemas/SignInReq'), - catchError(signin) - ); + router.post('/api/v1/auth/user/signup', catchError(signup)); + router.post('/api/v1/auth/user/signin', catchError(signin)); router.get( '/api/v1/auth/user/me', extractProjectIdAndAuthenticate, catchError(me) ); - router.post( - '/api/v1/auth/password/forgot', - getAjvValidatorMw('swagger.json#/components/schemas/ForgotPasswordReq'), - catchError(passwordForgot) - ); + router.post('/api/v1/auth/password/forgot', catchError(passwordForgot)); router.post( '/api/v1/auth/token/validate/:tokenId', catchError(tokenValidate) @@ -451,11 +254,10 @@ const mapRoutes = (router) => { ); router.post( '/api/v1/auth/password/change', - getAjvValidatorMw('swagger.json#/components/schemas/PasswordChangeReq'), ncMetaAclMw(passwordChange, 'passwordChange') ); router.post('/api/v1/auth/token/refresh', catchError(refreshToken)); // respond with password reset page router.get('/auth/password/reset/:tokenId', catchError(renderPasswordReset)); }; -export { mapRoutes as userController }; +export default mapRoutes;