mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-04-12 02:27:36 -04:00
Fix dev firebase admin key
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# You already have access to basic local functionality (UI, authentication, database read access).
|
||||
|
||||
# openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 -in backend/shared/src/googleApplicationCredentials-dev.json -out secrets/googleApplicationCredentials-dev.json.enc
|
||||
GOOGLE_CREDENTIALS_ENC_PWD=nP7s3274uzOG4c2t
|
||||
|
||||
|
||||
# Optional variables for full local functionality
|
||||
|
||||
# For the location / distance filtering features.
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -80,3 +80,4 @@ email-preview
|
||||
*.tar.gz
|
||||
*.rar
|
||||
/favicon_color.ico
|
||||
/backend/shared/src/googleApplicationCredentials-dev.json
|
||||
|
||||
@@ -1,35 +1,29 @@
|
||||
import * as admin from 'firebase-admin'
|
||||
import { z } from 'zod'
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import {z} from 'zod'
|
||||
import {NextFunction, Request, Response} from 'express'
|
||||
|
||||
import { PrivateUser } from 'common/user'
|
||||
import { APIError } from 'common/api/utils'
|
||||
export { APIError } from 'common/api/utils'
|
||||
import {
|
||||
API,
|
||||
APIPath,
|
||||
APIResponseOptionalContinue,
|
||||
APISchema,
|
||||
ValidatedAPIParams,
|
||||
} from 'common/api/schema'
|
||||
import { log } from 'shared/utils'
|
||||
import { getPrivateUserByKey } from 'shared/utils'
|
||||
import {PrivateUser} from 'common/user'
|
||||
import {APIError} from 'common/api/utils'
|
||||
import {API, APIPath, APIResponseOptionalContinue, APISchema, ValidatedAPIParams,} from 'common/api/schema'
|
||||
import {getPrivateUserByKey, log} from 'shared/utils'
|
||||
|
||||
export type Json = Record<string, unknown> | Json[]
|
||||
export type JsonHandler<T extends Json> = (
|
||||
req: Request,
|
||||
res: Response
|
||||
) => Promise<T>
|
||||
export type AuthedHandler<T extends Json> = (
|
||||
req: Request,
|
||||
user: AuthedUser,
|
||||
res: Response
|
||||
) => Promise<T>
|
||||
export type MaybeAuthedHandler<T extends Json> = (
|
||||
req: Request,
|
||||
user: AuthedUser | undefined,
|
||||
res: Response
|
||||
) => Promise<T>
|
||||
export {APIError} from 'common/api/utils'
|
||||
|
||||
// export type Json = Record<string, unknown> | Json[]
|
||||
// export type JsonHandler<T extends Json> = (
|
||||
// req: Request,
|
||||
// res: Response
|
||||
// ) => Promise<T>
|
||||
// export type AuthedHandler<T extends Json> = (
|
||||
// req: Request,
|
||||
// user: AuthedUser,
|
||||
// res: Response
|
||||
// ) => Promise<T>
|
||||
// export type MaybeAuthedHandler<T extends Json> = (
|
||||
// req: Request,
|
||||
// user: AuthedUser | undefined,
|
||||
// res: Response
|
||||
// ) => Promise<T>
|
||||
|
||||
export type AuthedUser = {
|
||||
uid: string
|
||||
@@ -39,6 +33,29 @@ type JwtCredentials = { kind: 'jwt'; data: admin.auth.DecodedIdToken }
|
||||
type KeyCredentials = { kind: 'key'; data: string }
|
||||
type Credentials = JwtCredentials | KeyCredentials
|
||||
|
||||
// export async function verifyIdToken(payload: string): Promise<DecodedIdToken> {
|
||||
// TODO: make local dev work without firebase admin SDK setup.
|
||||
// if (IS_LOCAL) {
|
||||
// // Skip real verification locally (to avoid needing to set up admin service account).
|
||||
// return {
|
||||
// aud: "",
|
||||
// auth_time: 0,
|
||||
// email_verified: false,
|
||||
// exp: 0,
|
||||
// firebase: {identities: {}, sign_in_provider: ""},
|
||||
// iat: 0,
|
||||
// iss: "",
|
||||
// phone_number: "",
|
||||
// picture: "",
|
||||
// sub: "",
|
||||
// uid: 'dev-user',
|
||||
// user_id: 'dev-user',
|
||||
// email: 'dev-user@example.com'
|
||||
// };
|
||||
// }
|
||||
// return await admin.auth().verifyIdToken(payload);
|
||||
// }
|
||||
|
||||
export const parseCredentials = async (req: Request): Promise<Credentials> => {
|
||||
const auth = admin.auth()
|
||||
const authHeader = req.get('Authorization')
|
||||
@@ -57,14 +74,14 @@ export const parseCredentials = async (req: Request): Promise<Credentials> => {
|
||||
throw new APIError(401, 'Firebase JWT payload undefined.')
|
||||
}
|
||||
try {
|
||||
return { kind: 'jwt', data: await auth.verifyIdToken(payload) }
|
||||
return {kind: 'jwt', data: await auth.verifyIdToken(payload)}
|
||||
} catch (err) {
|
||||
// This is somewhat suspicious, so get it into the firebase console
|
||||
console.error('Error verifying Firebase JWT: ', err, scheme, payload)
|
||||
throw new APIError(500, 'Error validating token.')
|
||||
}
|
||||
case 'Key':
|
||||
return { kind: 'key', data: payload }
|
||||
return {kind: 'key', data: payload}
|
||||
default:
|
||||
throw new APIError(401, 'Invalid auth scheme; must be "Key" or "Bearer".')
|
||||
}
|
||||
@@ -76,7 +93,7 @@ export const lookupUser = async (creds: Credentials): Promise<AuthedUser> => {
|
||||
if (typeof creds.data.user_id !== 'string') {
|
||||
throw new APIError(401, 'JWT must contain user ID.')
|
||||
}
|
||||
return { uid: creds.data.user_id, creds }
|
||||
return {uid: creds.data.user_id, creds}
|
||||
}
|
||||
case 'key': {
|
||||
const key = creds.data
|
||||
@@ -84,7 +101,7 @@ export const lookupUser = async (creds: Credentials): Promise<AuthedUser> => {
|
||||
if (!privateUser) {
|
||||
throw new APIError(401, `No private user exists with API key ${key}.`)
|
||||
}
|
||||
return { uid: privateUser.id, creds: { privateUser, ...creds } }
|
||||
return {uid: privateUser.id, creds: {privateUser, ...creds}}
|
||||
}
|
||||
default:
|
||||
throw new APIError(401, 'Invalid credential type.')
|
||||
@@ -109,45 +126,45 @@ export const validate = <T extends z.ZodTypeAny>(schema: T, val: unknown) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const jsonEndpoint = <T extends Json>(fn: JsonHandler<T>) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
res.status(200).json(await fn(req, res))
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const authEndpoint = <T extends Json>(fn: AuthedHandler<T>) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const authedUser = await lookupUser(await parseCredentials(req))
|
||||
res.status(200).json(await fn(req, authedUser, res))
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const MaybeAuthedEndpoint = <T extends Json>(
|
||||
fn: MaybeAuthedHandler<T>
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
let authUser: AuthedUser | undefined = undefined
|
||||
try {
|
||||
authUser = await lookupUser(await parseCredentials(req))
|
||||
} catch {
|
||||
// it's treated as an anon request
|
||||
}
|
||||
|
||||
try {
|
||||
res.status(200).json(await fn(req, authUser, res))
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
// export const jsonEndpoint = <T extends Json>(fn: JsonHandler<T>) => {
|
||||
// return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// try {
|
||||
// res.status(200).json(await fn(req, res))
|
||||
// } catch (e) {
|
||||
// next(e)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export const authEndpoint = <T extends Json>(fn: AuthedHandler<T>) => {
|
||||
// return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// try {
|
||||
// const authedUser = await lookupUser(await parseCredentials(req))
|
||||
// res.status(200).json(await fn(req, authedUser, res))
|
||||
// } catch (e) {
|
||||
// next(e)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export const MaybeAuthedEndpoint = <T extends Json>(
|
||||
// fn: MaybeAuthedHandler<T>
|
||||
// ) => {
|
||||
// return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// let authUser: AuthedUser | undefined = undefined
|
||||
// try {
|
||||
// authUser = await lookupUser(await parseCredentials(req))
|
||||
// } catch {
|
||||
// // it's treated as an anon request
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// res.status(200).json(await fn(req, authUser, res))
|
||||
// } catch (e) {
|
||||
// next(e)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
export type APIHandler<N extends APIPath> = (
|
||||
props: ValidatedAPIParams<N>,
|
||||
@@ -161,7 +178,7 @@ export const typedEndpoint = <N extends APIPath>(
|
||||
name: N,
|
||||
handler: APIHandler<N>
|
||||
) => {
|
||||
const { props: propSchema, authed: authRequired, method } = API[name]
|
||||
const {props: propSchema, authed: authRequired, method} = API[name]
|
||||
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
let authUser: AuthedUser | undefined = undefined
|
||||
@@ -195,7 +212,7 @@ export const typedEndpoint = <N extends APIPath>(
|
||||
// Convert bigint to number, b/c JSON doesn't support bigint.
|
||||
const convertedResult = deepConvertBigIntToNumber(result)
|
||||
|
||||
res.status(200).json(convertedResult ?? { success: true })
|
||||
res.status(200).json(convertedResult ?? {success: true})
|
||||
}
|
||||
|
||||
if (hasContinue) {
|
||||
|
||||
@@ -3,11 +3,12 @@ import {ENV_CONFIG} from "common/envs/constants";
|
||||
|
||||
export const getServiceAccountCredentials = () => {
|
||||
let keyPath = ENV_CONFIG.googleApplicationCredentials
|
||||
// console.log('Using GOOGLE_APPLICATION_CREDENTIALS:', keyPath)
|
||||
console.log('Using GOOGLE_APPLICATION_CREDENTIALS:', keyPath)
|
||||
if (!keyPath) {
|
||||
throw new Error(
|
||||
`Please set the GOOGLE_APPLICATION_CREDENTIALS environment variable to contain the path to your key file.`
|
||||
)
|
||||
// throw new Error(
|
||||
// `Please set the GOOGLE_APPLICATION_CREDENTIALS environment variable to contain the path to your key file.`
|
||||
// )
|
||||
return {}
|
||||
}
|
||||
|
||||
if (!keyPath.startsWith('/')) {
|
||||
|
||||
@@ -9,9 +9,12 @@ export const initAdmin = () => {
|
||||
if (IS_LOCAL) {
|
||||
try {
|
||||
const serviceAccount = getServiceAccountCredentials()
|
||||
console.log(
|
||||
`Initializing connection to ${serviceAccount.project_id} Firebase...`
|
||||
)
|
||||
// console.log(serviceAccount)
|
||||
if (!serviceAccount.project_id) {
|
||||
console.log(`GOOGLE_APPLICATION_CREDENTIALS not set, skipping admin firebase init.`)
|
||||
return
|
||||
}
|
||||
console.log(`Initializing connection to ${serviceAccount.project_id} Firebase...`)
|
||||
return admin.initializeApp({
|
||||
projectId: serviceAccount.project_id,
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
|
||||
@@ -7,4 +7,8 @@ cd "$(dirname "$0")"/..
|
||||
if [ ! -f .env ]; then
|
||||
cp .env.example .env
|
||||
echo ".env file created from .env.example"
|
||||
fi
|
||||
fi
|
||||
|
||||
source .env
|
||||
|
||||
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -in secrets/googleApplicationCredentials-dev.json.enc -out backend/shared/src/googleApplicationCredentials-dev.json -pass pass:$GOOGLE_CREDENTIALS_ENC_PWD
|
||||
BIN
secrets/googleApplicationCredentials-dev.json.enc
Normal file
BIN
secrets/googleApplicationCredentials-dev.json.enc
Normal file
Binary file not shown.
Reference in New Issue
Block a user