import { IS_CLOUD , JWT_SECRET } from "../util/secrets" ; import jwt from "express-jwt" ; import jwks from "jwks-rsa" ; import { NextFunction , Response } from "express" ; import { AuthRequest } from "../types/AuthRequest" ; import { UserDocument , UserModel } from "../models/UserModel" ; import { getOrganizationById , getPermissionsByRole , getRole , } from "./organizations" ; import { MemberRole } from "../../types/organization" ; import { AuditInterface } from "../../types/audit" ; import { insertAudit } from "./audit" ; import { getUserByEmail , getUserById } from "./users" ; import { hasOrganization } from "../models/OrganizationModel" ; function getLocalJWTCheck ( ) { if ( ! JWT_SECRET ) { throw new Error ( "Must specify JWT_SECRET environment variable" ) ; } return jwt ( { secret : JWT_SECRET , audience : "https://api.growthbook.io" , issuer : "https://api.growthbook.io" , algorithms : [ "HS256" ] , } ) ; } async function getUserFromLocalJWT ( user ) { return getUserById ( user . sub ) ; } function getAuth0JWTCheck ( ) { return jwt ( { secret : jwks . expressJwtSecret ( { cache : true , rateLimit : true , jwksRequestsPerMinute : 5 , jwksUri : "https://growthbook.auth0.com/.well-known/jwks.json" , } ) , audience : "https://api.growthbook.io" , issuer : "https://growthbook.auth0.com/" , algorithms : [ "RS256" ] , } ) ; } async function getUserFromAuth0JWT ( user ) { return getUserByEmail ( user [ "https://growthbook.io/email" ] ) ; } function getInitialEmailFromJWT ( user ) { if ( IS_CLOUD ) { return user [ "https://growthbook.io/email" ] || "" ; } return "" ; } function getInitialNameFromJWT ( user ) { if ( IS_CLOUD ) { return user [ "https://growthbook.io/fname" ] || "" ; } return "" ; } export function getJWTCheck ( ) { return IS_CLOUD ? getAuth0JWTCheck ( ) : getLocalJWTCheck ( ) ; } export async function processJWT ( req , res , next ) { req . email = getInitialEmailFromJWT ( req . user ) ; req . name = getInitialNameFromJWT ( req . user ) ; req . permissions = { } ; const user = await ( IS_CLOUD ? getUserFromAuth0JWT ( req . user ) : getUserFromLocalJWT ( req . user ) ) ; if ( user ) { req . email = user . email ; req . userId = user . id ; req . name = user . name ; req . admin = ! ! user . admin ; if ( req . headers [ "x-organization" ] ) { req . organization = ( await getOrganizationById ( "" + req . headers [ "x-organization" ] ) ) || undefined ; if ( req . organization ) { if ( ! req . admin && ! req . organization . members . filter ( ( m ) => m . id === req . userId ) . length ) { return res . status ( 403 ) . json ( { status : 403 , message : "You do not have access to that organization" , } ) ; } const role = req . admin ? "admin" : getRole ( req . organization , user . id ) || "collaborator" ; req . permissions = getPermissionsByRole ( role ) ; } else { return res . status ( 404 ) . json ( { status : 404 , message : "Organization not found" , } ) ; } } req . audit = async ( data ) => { await insertAudit ( { ... data , user : { id : user . id , email : user . email , name : user . name , } , organization : req . organization ?. id , dateCreated : new Date ( ) , } ) ; } ; } else { req . audit = async ( ) => { throw new Error ( "No user in request" ) ; } ; } next ( ) ; } export function validatePasswordFormat ( password ? ) { if ( ! password ) { throw new Error ( "Password cannot be empty" ) ; } if ( password . length < 8 ) { throw new Error ( "Password must be at least 8 characters." ) ; } return password ; } async function checkNewInstallation ( ) { const doc = await hasOrganization ( ) ; if ( doc ) { return false ; } const doc2 = await UserModel . findOne ( ) ; if ( doc2 ) { return false ; } return true ; } let newInstallationPromise ; export function isNewInstallation ( ) { if ( ! newInstallationPromise ) { newInstallationPromise = checkNewInstallation ( ) ; } return newInstallationPromise ; } export function markInstalled ( ) { newInstallationPromise = new Promise ( ( resolve ) => resolve ( false ) ) ; }