diff --git a/packages/api/src/routers/auth/auth_router.ts b/packages/api/src/routers/auth/auth_router.ts index 8721fb9ca..0b4b5266c 100644 --- a/packages/api/src/routers/auth/auth_router.ts +++ b/packages/api/src/routers/auth/auth_router.ts @@ -54,6 +54,15 @@ import { import { createWebAuthToken } from './jwt_helpers' import { createSsoToken, ssoRedirectURL } from '../../utils/sso' +export interface SignupRequest { + email: string + password: string + name: string + username: string + bio?: string + pictureUrl?: string +} + const logger = buildLogger('app.dispatch') const signToken = promisify(jwt.sign) @@ -62,6 +71,19 @@ const cookieParams = { maxAge: 365 * 24 * 60 * 60 * 1000, } +export const isValidSignupRequest = (obj: any): obj is SignupRequest => { + return ( + 'email' in obj && + obj.email.trim().length > 0 && // email must not be empty + 'password' in obj && + obj.password.length >= 8 && // password must be at least 8 characters + 'name' in obj && + obj.name.trim().length > 0 && // name must not be empty + 'username' in obj && + obj.username.trim().length > 0 // username must not be empty + ) +} + export function authRouter() { const router = express.Router() @@ -443,26 +465,6 @@ export function authRouter() { '/email-signup', cors(corsConfig), async (req: express.Request, res: express.Response) => { - interface SignupRequest { - email: string - password: string - name: string - username: string - bio?: string - pictureUrl?: string - } - function isValidSignupRequest(obj: any): obj is SignupRequest { - return ( - 'email' in obj && - obj.email.trim().length > 0 && // email must not be empty - 'password' in obj && - obj.password.length >= 8 && // password must be at least 8 characters - 'name' in obj && - obj.name.trim().length > 0 && // name must not be empty - 'username' in obj && - obj.username.trim().length > 0 // username must not be empty - ) - } if (!isValidSignupRequest(req.body)) { return res.redirect( `${env.client.url}/auth/email-signup?errorCodes=INVALID_CREDENTIALS` diff --git a/packages/api/src/routers/auth/mobile/mobile_auth_router.ts b/packages/api/src/routers/auth/mobile/mobile_auth_router.ts index c43df9bc8..f27a032fa 100644 --- a/packages/api/src/routers/auth/mobile/mobile_auth_router.ts +++ b/packages/api/src/routers/auth/mobile/mobile_auth_router.ts @@ -32,13 +32,8 @@ export function mobileAuthRouter() { }) router.post('/email-sign-up', async (req, res) => { - const { email, password, username, name } = req.body - const payload = await createMobileEmailSignUpResponse( - email, - password, - username, - name - ) + const payload = await createMobileEmailSignUpResponse(req.body) + res.status(payload.statusCode).json(payload.json) }) diff --git a/packages/api/src/routers/auth/mobile/sign_in.ts b/packages/api/src/routers/auth/mobile/sign_in.ts index a19b505c3..323556569 100644 --- a/packages/api/src/routers/auth/mobile/sign_in.ts +++ b/packages/api/src/routers/auth/mobile/sign_in.ts @@ -1,18 +1,17 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ +import UserModel from '../../../datalayer/user' +import { StatusType } from '../../../datalayer/user/model' +import { getUserByEmail } from '../../../services/create_user' +import { sendConfirmationEmail } from '../../../services/send_emails' +import { comparePassword } from '../../../utils/auth' import { decodeAppleToken } from '../apple_auth' -import { decodeGoogleToken } from '../google_auth' import { + AuthProvider, DecodeTokenResult, JsonResponsePayload, - AuthProvider, } from '../auth_types' +import { decodeGoogleToken } from '../google_auth' import { createMobileAuthPayload } from '../jwt_helpers' -import UserModel from '../../../datalayer/user' -import { initModels } from '../../../server' -import { sendConfirmationEmail } from '../../../services/send_emails' -import { kx } from '../../../datalayer/knex_config' -import { StatusType } from '../../../datalayer/user/model' -import { comparePassword } from '../../../utils/auth' export async function createMobileSignInResponse( isAndroid: boolean, @@ -46,11 +45,7 @@ export async function createMobileEmailSignInResponse( throw new Error('Missing username or password') } - const models = initModels(kx, false) - const user = await models.user.getWhere({ - email, - }) - + const user = await getUserByEmail(email.trim()) if (!user?.id || !user?.password) { throw new Error('user not found') } diff --git a/packages/api/src/routers/auth/mobile/sign_up.ts b/packages/api/src/routers/auth/mobile/sign_up.ts index 55d9e6dea..f21e64d5d 100644 --- a/packages/api/src/routers/auth/mobile/sign_up.ts +++ b/packages/api/src/routers/auth/mobile/sign_up.ts @@ -11,6 +11,7 @@ import { createPendingUserToken, suggestedUsername } from '../jwt_helpers' import UserModel from '../../../datalayer/user' import { hashPassword } from '../../../utils/auth' import { createUser } from '../../../services/create_user' +import { isValidSignupRequest } from '../auth_router' export async function createMobileSignUpResponse( isAndroid: boolean, @@ -45,24 +46,24 @@ export async function createMobileSignUpResponse( } export async function createMobileEmailSignUpResponse( - email?: string, - password?: string, - username?: string, - name?: string + requestBody: any ): Promise { try { - if (!email || !password || !username || !name) { + if (!isValidSignupRequest(requestBody)) { throw new Error('Missing username, password, name, or username') } + const { email, password, name, username } = requestBody + // trim whitespace in email address + const trimmedEmail = email.trim() const hashedPassword = await hashPassword(password) await createUser({ - email, + email: trimmedEmail, provider: 'EMAIL', - sourceUserId: email, - name, - username: username.toLowerCase(), + sourceUserId: trimmedEmail, + name: name.trim(), + username: username.trim().toLowerCase(), password: hashedPassword, pendingConfirmation: true, }) diff --git a/packages/api/src/services/create_user.ts b/packages/api/src/services/create_user.ts index f8e2fbea2..ec180f5be 100644 --- a/packages/api/src/services/create_user.ts +++ b/packages/api/src/services/create_user.ts @@ -24,7 +24,8 @@ export const createUser = async (input: { password?: string pendingConfirmation?: boolean }): Promise<[User, Profile]> => { - const existingUser = await getUserByEmail(input.email) + const trimmedEmail = input.email.trim() + const existingUser = await getUserByEmail(trimmedEmail) if (existingUser) { if (existingUser.profile) { return Promise.reject({ errorCode: SignupErrorCode.UserExists }) @@ -63,7 +64,7 @@ export const createUser = async (input: { const user = await t.getRepository(User).save({ source: input.provider, name: input.name, - email: input.email, + email: trimmedEmail, sourceUserId: input.sourceUserId, password: input.password, status: input.pendingConfirmation