From a5671c94133a7cea6ee9d541d51a3044ad9edb5d Mon Sep 17 00:00:00 2001 From: hanahhleee Date: Fri, 3 Nov 2023 15:23:00 -0400 Subject: [PATCH] Created middleware to check claims --- backend/api-spec.json | 64 ++++++++++++++++++++++++- backend/src/index.ts | 1 - backend/src/users/controllers.ts | 9 +--- backend/src/users/firebase-functions.ts | 8 ++-- backend/src/users/views.ts | 5 +- backend/src/utils/admin.ts | 25 ++++++++++ backend/src/utils/evaluator.ts | 25 ++++++++++ backend/src/utils/mobile-entry.ts | 25 ++++++++++ backend/src/utils/web-entry.ts | 25 ++++++++++ 9 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 backend/src/utils/admin.ts create mode 100644 backend/src/utils/evaluator.ts create mode 100644 backend/src/utils/mobile-entry.ts create mode 100644 backend/src/utils/web-entry.ts diff --git a/backend/api-spec.json b/backend/api-spec.json index 583f85a..194bd42 100644 --- a/backend/api-spec.json +++ b/backend/api-spec.json @@ -480,13 +480,22 @@ } } }, - "/users/": { + "/users/users": { "get": { "description": "", - "parameters": [], + "parameters": [ + { + "name": "authorization", + "in": "header", + "type": "string" + } + ], "responses": { "200": { "description": "OK" + }, + "401": { + "description": "Unauthorized" } } } @@ -506,11 +515,19 @@ "in": "path", "required": true, "type": "string" + }, + { + "name": "authorization", + "in": "header", + "type": "string" } ], "responses": { "200": { "description": "OK" + }, + "401": { + "description": "Unauthorized" } } } @@ -524,11 +541,54 @@ "in": "path", "required": true, "type": "string" + }, + { + "name": "authorization", + "in": "header", + "type": "string" } ], "responses": { "200": { "description": "OK" + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/users/modify/": { + "post": { + "description": "", + "parameters": [ + { + "name": "authorization", + "in": "header", + "type": "string" + }, + { + "name": "body", + "in": "body", + "schema": { + "type": "object", + "properties": { + "uid": { + "example": "any" + }, + "new_claim": { + "example": "any" + } + } + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthorized" } } } diff --git a/backend/src/index.ts b/backend/src/index.ts index c131ae3..de6c3a9 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,7 +5,6 @@ import userRouter from "./users/views"; import swaggerUI from "swagger-ui-express"; import spec from "../api-spec.json"; import { dbConnect } from "./database"; -import userRouter from "./users/views"; const app = express(); diff --git a/backend/src/users/controllers.ts b/backend/src/users/controllers.ts index 7089471..bf63175 100644 --- a/backend/src/users/controllers.ts +++ b/backend/src/users/controllers.ts @@ -1,10 +1,5 @@ import * as admin from 'firebase-admin' - -const serviceAccount = require('../../serviceAccountKey.json') - -admin.initializeApp({ - credential: admin.credential.cert(serviceAccount) -}) +import { admin_app } from './firebase-functions' /** * Modify the claim of a user given user ID and new claim @@ -16,7 +11,7 @@ export function changeClaim(uid: string, new_claim: number) { evaluator: new_claim == 2, admin: new_claim == 3 }; - admin.auth().setCustomUserClaims(uid, claims) + admin_app.auth().setCustomUserClaims(uid, claims) .catch( () => { console.log("ERROR: User with uid " + uid + " not found."); diff --git a/backend/src/users/firebase-functions.ts b/backend/src/users/firebase-functions.ts index 80d5659..e0e5b16 100644 --- a/backend/src/users/firebase-functions.ts +++ b/backend/src/users/firebase-functions.ts @@ -2,7 +2,7 @@ var admin = require("firebase-admin"); var serviceAccount = require("./serviceAccountKey.json"); -admin.initializeApp({ +export const admin_app = admin.initializeApp({ credential: admin.credential.cert(serviceAccount), }); @@ -29,13 +29,13 @@ export function createUser(number: string, claim: number) { break; } } - admin + admin_app .auth() .createUser({ phoneNumber: number, }) .then((userRecord: any) => { - admin.auth().setCustomUserClaims(userRecord.uid, customClaims); + admin_app.auth().setCustomUserClaims(userRecord.uid, customClaims); console.log("Successfully created new user:", userRecord.uid); }) .catch((error: any) => { @@ -47,7 +47,7 @@ export function createUser(number: string, claim: number) { * Delete a user given their phone number; number should have +(country code) prepended, e.g. +16071234567 */ export function deleteUser(number: string) { - const auth = admin.auth(); + const auth = admin_app.auth(); auth .getUserByPhoneNumber(number) .then((userRecord: any) => { diff --git a/backend/src/users/views.ts b/backend/src/users/views.ts index 56daadf..abaa999 100644 --- a/backend/src/users/views.ts +++ b/backend/src/users/views.ts @@ -4,10 +4,13 @@ import { Router } from "express"; import { createUser, deleteUser } from "./firebase-functions"; import { successJson } from "../utils/jsonResponses"; import UserController from "./controllers"; +import { verifyToken } from "../utils/admin"; const userRouter = Router(); -userRouter.get("/", (req, res) => { +userRouter.use(verifyToken); + +userRouter.get("/users", (req, res) => { res.send("Hello from a subrouter"); }); diff --git a/backend/src/utils/admin.ts b/backend/src/utils/admin.ts new file mode 100644 index 0000000..928a405 --- /dev/null +++ b/backend/src/utils/admin.ts @@ -0,0 +1,25 @@ +import { Request, Response, NextFunction } from "express"; +import { getAuth } from "firebase-admin/auth"; + +export const verifyToken = async ( + req: Request, + res: Response, + next: NextFunction +) => { + const { authorization } = req.headers + if (!authorization) { + console.log(req.headers) + return res.status(401).send({ message: 'Unauthorized' }); + } + + const token = authorization.split(" ")[1]; + + getAuth() + .verifyIdToken(token) + .then((claims) => { + if (claims.admin === true) { + next(); + } + }) + .catch((err) => res.sendStatus(403).send({ message: 'Forbidden' })) + }; \ No newline at end of file diff --git a/backend/src/utils/evaluator.ts b/backend/src/utils/evaluator.ts new file mode 100644 index 0000000..a674498 --- /dev/null +++ b/backend/src/utils/evaluator.ts @@ -0,0 +1,25 @@ +import { Request, Response, NextFunction } from "express"; +import { getAuth } from "firebase-admin/auth"; + +export const verifyToken = async ( + req: Request, + res: Response, + next: NextFunction +) => { + const { authorization } = req.headers + if (!authorization) { + console.log(req.headers) + return res.status(401).send({ message: 'Unauthorized' }); + } + + const token = authorization.split(" ")[1]; + + getAuth() + .verifyIdToken(token) + .then((claims) => { + if (claims.evaluator === true || claims.admin === true) { + next(); + } + }) + .catch((err) => res.sendStatus(403).send({ message: 'Forbidden' })) + }; \ No newline at end of file diff --git a/backend/src/utils/mobile-entry.ts b/backend/src/utils/mobile-entry.ts new file mode 100644 index 0000000..248d52f --- /dev/null +++ b/backend/src/utils/mobile-entry.ts @@ -0,0 +1,25 @@ +import { Request, Response, NextFunction } from "express"; +import { getAuth } from "firebase-admin/auth"; + +export const verifyToken = async ( + req: Request, + res: Response, + next: NextFunction +) => { + const { authorization } = req.headers + if (!authorization) { + console.log(req.headers) + return res.status(401).send({ message: 'Unauthorized' }); + } + + const token = authorization.split(" ")[1]; + + getAuth() + .verifyIdToken(token) + .then((claims) => { + if (claims.mobile_entry === true || claims.admin === true) { + next(); + } + }) + .catch((err) => res.sendStatus(403).send({ message: 'Forbidden' })) + }; \ No newline at end of file diff --git a/backend/src/utils/web-entry.ts b/backend/src/utils/web-entry.ts new file mode 100644 index 0000000..e220692 --- /dev/null +++ b/backend/src/utils/web-entry.ts @@ -0,0 +1,25 @@ +import { Request, Response, NextFunction } from "express"; +import { getAuth } from "firebase-admin/auth"; + +export const verifyToken = async ( + req: Request, + res: Response, + next: NextFunction +) => { + const { authorization } = req.headers + if (!authorization) { + console.log(req.headers) + return res.status(401).send({ message: 'Unauthorized' }); + } + + const token = authorization.split(" ")[1]; + + getAuth() + .verifyIdToken(token) + .then((claims) => { + if (claims.web_entry === true) { + next(); + } + }) + .catch((err) => res.sendStatus(403).send({ message: 'Forbidden' })) + }; \ No newline at end of file