moved firebase admin into its own module

not initialising if ther eis no service account
this allows the backend server to be ran without firebase (all though it will throw errors)
closes #4190
This commit is contained in:
Miodec 2023-04-18 15:50:48 +02:00
parent 942df911bd
commit c6d0070dd3
4 changed files with 78 additions and 28 deletions

View file

@ -20,6 +20,7 @@ import { v4 as uuidv4 } from "uuid";
import { ObjectId } from "mongodb";
import * as ReportDAL from "../../dal/report";
import emailQueue from "../../queues/email-queue";
import FirebaseAdmin from "../../init/firebase-admin";
async function verifyCaptcha(captcha: string): Promise<void> {
if (!(await verify(captcha))) {
@ -37,7 +38,7 @@ export async function createNewUser(
await verifyCaptcha(captcha);
} catch (e) {
try {
await admin.auth().deleteUser(uid);
await FirebaseAdmin().auth().deleteUser(uid);
} catch (e) {
// user might be deleted on the frontend
}
@ -84,12 +85,14 @@ export async function sendVerificationEmail(
let link = "";
try {
link = await admin.auth().generateEmailVerificationLink(email, {
url:
process.env.MODE === "dev"
? "http://localhost:3000"
: "https://monkeytype.com",
});
link = await FirebaseAdmin()
.auth()
.generateEmailVerificationLink(email, {
url:
process.env.MODE === "dev"
? "http://localhost:3000"
: "https://monkeytype.com",
});
} catch (e) {
if (
e.code === "auth/internal-error" &&
@ -121,7 +124,7 @@ export async function sendForgotPasswordEmail(
let auth;
try {
auth = await admin.auth().getUserByEmail(email);
auth = await FirebaseAdmin().auth().getUserByEmail(email);
} catch (e) {
if (e.code === "auth/user-not-found") {
throw new MonkeyError(404, "User not found");
@ -134,12 +137,14 @@ export async function sendForgotPasswordEmail(
"request forgot password email"
);
const link = await admin.auth().generatePasswordResetLink(email, {
url:
process.env.MODE === "dev"
? "http://localhost:3000"
: "https://monkeytype.com",
});
const link = await FirebaseAdmin()
.auth()
.generatePasswordResetLink(email, {
url:
process.env.MODE === "dev"
? "http://localhost:3000"
: "https://monkeytype.com",
});
await emailQueue.sendForgotPasswordEmail(email, userInfo.name, link);
return new MonkeyResponse("Email sent if user was found");
@ -292,7 +297,7 @@ export async function getUser(
if (e.status === 404) {
let user;
try {
user = await admin.auth().getUser(uid);
user = await FirebaseAdmin().auth().getUser(uid);
//exists, recreate in db
await UserDAL.addUser(user.displayName, user.email, uid);
userInfo = await UserDAL.getUser(uid, "get user (recreated)");

View file

@ -0,0 +1,52 @@
import admin, { ServiceAccount } from "firebase-admin";
import Logger from "../utils/logger";
import { readFileSync, existsSync } from "fs";
import MonkeyError from "../utils/error";
import path from "path";
const SERVICE_ACCOUNT_PATH = path.join(
__dirname,
"../credentials/serviceAccountKey.json"
);
export function init(): void {
if (!existsSync(SERVICE_ACCOUNT_PATH)) {
if (process.env.MODE === "dev") {
Logger.warning(
"Firebase service account key not found! Continuing in dev mode, but authentication will throw errors."
);
} else {
throw new MonkeyError(
500,
"Firebase service account key not found! Make sure generate a service account key and place it in credentials/serviceAccountKey.json.",
"init() firebase-admin.ts"
);
}
} else {
const serviceAccount = JSON.parse(
readFileSync(SERVICE_ACCOUNT_PATH, {
encoding: "utf8",
flag: "r",
})
);
admin.initializeApp({
credential: admin.credential.cert(
serviceAccount as unknown as ServiceAccount
),
});
Logger.success("Firebase app initialized");
}
}
function get(): typeof admin {
if (admin.apps.length === 0) {
throw new MonkeyError(
500,
"Firebase app not initialized! Make sure generate a service account key and place it in credentials/serviceAccountKey.json.",
"get() firebase-admin.ts"
);
}
return admin;
}
export default get;

View file

@ -1,7 +1,4 @@
import "dotenv/config";
import admin, { ServiceAccount } from "firebase-admin";
// @ts-ignore
import serviceAccount from "./credentials/serviceAccountKey.json"; // eslint-disable-line require-path-exists/exists
import * as db from "./init/db";
import jobs from "./jobs";
import { getLiveConfiguration } from "./init/configuration";
@ -15,6 +12,7 @@ import queues from "./queues";
import workers from "./workers";
import Logger from "./utils/logger";
import * as EmailClient from "./init/email-client";
import { init as initFirebaseAdmin } from "./init/firebase-admin";
async function bootServer(port: number): Promise<Server> {
try {
@ -25,12 +23,7 @@ async function bootServer(port: number): Promise<Server> {
Logger.success("Connected to database");
Logger.info("Initializing Firebase app instance...");
admin.initializeApp({
credential: admin.credential.cert(
serviceAccount as unknown as ServiceAccount
),
});
Logger.success("Firebase app initialized");
initFirebaseAdmin();
Logger.info("Fetching live configuration...");
const liveConfiguration = await getLiveConfiguration();

View file

@ -1,4 +1,4 @@
import admin from "firebase-admin";
import FirebaseAdmin from "./../init/firebase-admin";
import { UserRecord } from "firebase-admin/lib/auth/user-record";
import { DecodedIdToken } from "firebase-admin/lib/auth/token-verifier";
import LRUCache from "lru-cache";
@ -22,7 +22,7 @@ export async function verifyIdToken(
noCache = false
): Promise<DecodedIdToken> {
if (noCache) {
return await admin.auth().verifyIdToken(idToken, true);
return await FirebaseAdmin().auth().verifyIdToken(idToken, true);
}
setTokenCacheLength(tokenCache.size);
@ -44,7 +44,7 @@ export async function verifyIdToken(
recordTokenCacheAccess("miss");
}
const decoded = await admin.auth().verifyIdToken(idToken, true);
const decoded = await FirebaseAdmin().auth().verifyIdToken(idToken, true);
tokenCache.set(idToken, decoded);
return decoded;
}
@ -53,7 +53,7 @@ export async function updateUserEmail(
uid: string,
email: string
): Promise<UserRecord> {
return await admin.auth().updateUser(uid, {
return await FirebaseAdmin().auth().updateUser(uid, {
email,
emailVerified: false,
});