From d3c2bb3a074b2b601f2a2ba9e9148d6f9e756627 Mon Sep 17 00:00:00 2001 From: Klaus <88317742+l4u532@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:33:24 +0100 Subject: [PATCH] feat: circumvent permission checks when developing locally via serve-dev (credits go to bradleyDean) --- .vscode/launch.json | 12 +++++++++ package.json | 1 + src/auth/middleware.ts | 58 ++++++++++++++++++++++++----------------- src/auth/permissions.ts | 19 +++++++++++++- 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 34f0ff72..7631bae6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -44,6 +44,18 @@ ], "console": "integratedTerminal", }, + { + "type": "node", + "request": "launch", + "name": "Launch API Server (serve-dev)", + "skipFiles": ["/**"], + "program": "${workspaceFolder}/src/main.ts", + "preLaunchTask": "tsc: build - tsconfig.json", + "outFiles": ["${workspaceFolder}/build/**/*.js"], + "runtimeExecutable": "yarn", + "runtimeArgs": ["run", "serve-dev"], + "console": "integratedTerminal" + }, { "name": "Debug Jest Tests", "type": "node", diff --git a/package.json b/package.json index a83b795f..ef295901 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "build-release": "tsc -p tsconfig.release.json", "clean": "tsc -b --clean && rm -rf build/*", "serve": "yarn build && node --experimental-json-modules build/main.js", + "serve-dev": "GOD_MODE=true yarn serve", "refresh-db": "./refresh-db.sh", "seed-usa": "yarn build && node build/db/import/usa/USADay0Seed.js", "seed-db": "./seed-db.sh", diff --git a/src/auth/middleware.ts b/src/auth/middleware.ts index af81045c..ffa419ac 100644 --- a/src/auth/middleware.ts +++ b/src/auth/middleware.ts @@ -1,37 +1,47 @@ -import muid from 'uuid-mongodb' +import muid, { MUUID } from 'uuid-mongodb' +import { logger } from '../logger.js' import { AuthUserType } from '../types.js' import { verifyJWT } from './util.js' -import { logger } from '../logger.js' /** * Create a middleware context for Apollo server */ -export const createContext = async ({ req }): Promise => { - const { headers } = req +export const createContext = (() => { + let testUUID: MUUID - const user: AuthUserType = { - roles: [], - uuid: undefined, - isBuilder: false + if (process.env.GOD_MODE === 'true') { + testUUID = muid.v4() + logger.info('🚨🚨 GOD_MODE enabled, allowing all queries and mutations. This is ONLY for local development and should NOT happen production. 🚨🚨') + logger.info(`The user.uuid for this session is: ${testUUID.toString()}`) } - const authHeader = String(headers?.authorization ?? '') - if (authHeader.startsWith('Bearer ')) { - const token = authHeader.substring(7, authHeader.length).trim() + // return async ({ req }: { req?: Request } = {}): Promise => { + // const headers = req?.headers + return async ({ req }): Promise => { + const { headers } = req - let payload - try { - payload = await verifyJWT(token) - } catch (e) { - logger.error(`Can't verify JWT token ${e.toString() as string}`) - throw new Error('An unexpected error has occurred. Please notify us at support@openbeta.io.') + const user: AuthUserType = { + roles: [], + uuid: undefined, + isBuilder: false } - user.isBuilder = payload?.scope?.includes('builder:default') ?? false - user.roles = payload?.['https://tacos.openbeta.io/roles'] ?? [] - const uidStr: string | undefined = payload?.['https://tacos.openbeta.io/uuid'] - user.uuid = uidStr != null ? muid.from(uidStr) : undefined - } + if (process.env.GOD_MODE === 'true' && (user.uuid == null)) { + user.roles = ['user_admin', 'org_admin', 'editor'] + user.uuid = testUUID + logger.info(`The user.roles for this session is: ${user.roles.toString()}`) + } else { + const authHeader = String(headers.authorization ?? '') + if (authHeader.startsWith('Bearer ')) { + const token = authHeader.substring(7, authHeader.length).trim() + const z = await verifyJWT(token) - return { user } -} + user.isBuilder = z?.scope?.includes('builder:default') ?? false + user.roles = z?.['https://tacos.openbeta.io/roles'] ?? [] + const uidStr: string | undefined = z?.['https://tacos.openbeta.io/uuid'] + user.uuid = uidStr != null ? muid.from(uidStr) : undefined + } + } + return { user } + } +})() diff --git a/src/auth/permissions.ts b/src/auth/permissions.ts index 59e2925e..f53b904d 100644 --- a/src/auth/permissions.ts +++ b/src/auth/permissions.ts @@ -1,7 +1,7 @@ import { shield, allow, and, or } from 'graphql-shield' import { isEditor, isUserAdmin, isOwner, isValidEmail, isMediaOwner } from './rules.js' -const permissions = shield({ +const defaultPermissions = shield({ Query: { '*': allow }, @@ -25,4 +25,21 @@ const permissions = shield({ fallbackRule: allow }) +// permissions object for when env var GOD_MODE is true +// only relevant for local development via `yarn serve-dev` +const godModePermissions = shield({ + Query: { + '*': allow + }, + Mutation: { + '*': allow + } +}, { + allowExternalErrors: true, + fallbackRule: allow +}) + +// Choose the appropriate shield based on whether env var GOD_MODE is set +const permissions = process.env.GOD_MODE === 'true' ? godModePermissions : defaultPermissions + export default permissions