import { Request , Response } from "express" ; import jwt from "jsonwebtoken" ; import { createRefreshToken , deleteRefreshToken , getUserIdFromAuthRefreshToken , } from "../models/AuthRefreshModel" ; import { createForgotPasswordToken , deleteForgotPasswordToken , getUserIdFromForgotPasswordToken , } from "../models/ForgotPasswordModel" ; import { createOrganization , hasOrganization , } from "../models/OrganizationModel" ; import { IS_CLOUD } from "../util/secrets" ; import { isNewInstallation , markInstalled , validatePasswordFormat , } from "../services/auth" ; import { getEmailFromUserId , getOrgFromReq } from "../services/organizations" ; import { createUser , getUserByEmail , getUserById , updatePassword , verifyPassword , } from "../services/users" ; import { AuthRequest } from "../types/AuthRequest" ; import { JWT_SECRET } from "../util/secrets" ; function generateJWT ( userId ) { return jwt . sign ( { scope : "profile openid email" , } , JWT_SECRET , { algorithm : "HS256" , audience : "https://api.growthbook.io" , issuer : "https://api.growthbook.io" , subject : userId , expiresIn : 1800 , } ) ; } async function successResponse ( req , res , userId ) { const token = generateJWT ( userId ) ; await createRefreshToken ( req , res , userId ) ; return res . status ( 200 ) . json ( { status : 200 , token , } ) ; } export async function getHasOrganizations ( req , res ) { const hasOrg = IS_CLOUD ? true : await hasOrganization ( ) ; return res . json ( { status : 200 , hasOrganizations : hasOrg , } ) ; } export async function postRefresh ( req , res ) { const refreshToken = req . cookies [ "AUTH_REFRESH_TOKEN" ] ; if ( ! refreshToken ) { const newInstallation = await isNewInstallation ( ) ; return res . json ( { status : 200 , authenticated : false , newInstallation , } ) ; } const userId = await getUserIdFromAuthRefreshToken ( refreshToken ) ; if ( ! userId ) { return res . json ( { status : 200 , authenticated : false , } ) ; } const user = await getUserById ( userId ) ; const token = generateJWT ( userId ) ; return res . json ( { status : 200 , authenticated : true , token , email : user ?. email || "" , } ) ; } export async function postLogin ( req , res ) { const { email , password } = req . body ; validatePasswordFormat ( password ) ; const user = await getUserByEmail ( email ) ; if ( ! user ) { console . log ( "Unknown email" , email ) ; return res . status ( 400 ) . json ( { status : 400 , message : "Invalid email or password" , } ) ; } const valid = await verifyPassword ( user , password ) ; if ( ! valid ) { console . log ( "Invalid password for" , email ) ; return res . status ( 400 ) . json ( { status : 400 , message : "Invalid email or password" , } ) ; } return successResponse ( req as Request , res , user . id ) ; } export async function postLogout ( req , res ) { await deleteRefreshToken ( req , res ) ; res . status ( 200 ) . json ( { status : 200 , } ) ; } export async function postRegister ( req , res ) { const { email , name , password } = req . body ; validatePasswordFormat ( password ) ; const existingUser = await getUserByEmail ( email ) ; if ( existingUser ) { const valid = await verifyPassword ( existingUser , password ) ; if ( valid ) { return successResponse ( req as Request , res , existingUser . id ) ; } return res . status ( 400 ) . json ( { status : 400 , message : "That email address is already registered." , } ) ; } const user = await createUser ( name , email , password ) ; return successResponse ( req as Request , res , user . id ) ; } export async function postFirstTimeRegister ( req , res ) { const { email , name , password , companyname } = req . body ; validatePasswordFormat ( password ) ; if ( companyname . length < 3 ) { throw Error ( "Company length must be at least 3 characters" ) ; } const existingUser = await getUserByEmail ( email ) ; if ( existingUser ) { return res . status ( 400 ) . json ( { status : 400 , message : "An error ocurred, please refresh the page and try again." , } ) ; } const user = await createUser ( name , email , password ) ; await createOrganization ( email , user . id , companyname , "" ) ; markInstalled ( ) ; return successResponse ( req , res , user . id ) ; } export async function postForgotPassword ( req , res ) { const { email } = req . body ; await createForgotPasswordToken ( email ) ; res . status ( 200 ) . json ( { status : 200 , } ) ; } export async function getResetPassword ( req , res ) { const { token } = req . params ; if ( ! token ) { throw new Error ( "Invalid password reset token." ) ; } const userId = await getUserIdFromForgotPasswordToken ( token ) ; if ( ! userId ) { throw new Error ( "Invalid password reset token." ) ; } const email = await getEmailFromUserId ( userId ) ; if ( ! email ) { throw new Error ( "Could not find user for that password reset token." ) ; } res . status ( 200 ) . json ( { status : 200 , email , } ) ; } export async function postResetPassword ( req , res ) { const { token } = req . params ; const { password } = req . body ; if ( ! token ) { throw new Error ( "Invalid password reset token." ) ; } const userId = await getUserIdFromForgotPasswordToken ( token ) ; if ( ! userId ) { throw new Error ( "Invalid password reset token." ) ; } const email = await getEmailFromUserId ( userId ) ; if ( ! email ) { throw new Error ( "Could not find user for that password reset token." ) ; } await updatePassword ( userId , password ) ; await deleteForgotPasswordToken ( token ) ; res . status ( 200 ) . json ( { status : 200 , email , } ) ; } export async function postChangePassword ( req , res ) { const { currentPassword , newPassword } = req . body ; const { userId } = getOrgFromReq ( req ) ; const user = await getUserById ( userId ) ; if ( ! user ) { throw new Error ( "Invalid user" ) ; } const valid = await verifyPassword ( user , currentPassword ) ; if ( ! valid ) { throw new Error ( "Current password is incorrect" ) ; } await updatePassword ( user . id , newPassword ) ; res . status ( 200 ) . json ( { status : 200 , } ) ; }