diff --git a/backend/api/controllers/ape-keys.ts b/backend/api/controllers/ape-keys.ts new file mode 100644 index 000000000..271039d96 --- /dev/null +++ b/backend/api/controllers/ape-keys.ts @@ -0,0 +1,27 @@ +import { MonkeyResponse } from "../../handlers/monkey-response"; + +class ApeKeysController { + static async getApeKey(_req: MonkeyTypes.Request): Promise { + return new MonkeyResponse("ApeKey retrieved"); + } + + static async generateApeKey( + _req: MonkeyTypes.Request + ): Promise { + return new MonkeyResponse("ApeKey generated"); + } + + static async updateApeKey( + _req: MonkeyTypes.Request + ): Promise { + return new MonkeyResponse("ApeKey updated"); + } + + static async deleteApeKey( + _req: MonkeyTypes.Request + ): Promise { + return new MonkeyResponse("ApeKey deleted"); + } +} + +export default ApeKeysController; diff --git a/backend/api/routes/ape-keys.ts b/backend/api/routes/ape-keys.ts new file mode 100644 index 000000000..004023435 --- /dev/null +++ b/backend/api/routes/ape-keys.ts @@ -0,0 +1,80 @@ +import joi from "joi"; +import { Router } from "express"; +import { + asyncHandler, + validateConfiguration, + validateRequest, +} from "../../middlewares/api-utils"; +import { authenticateRequest } from "../../middlewares/auth"; +import ApeKeysController from "../controllers/ape-keys"; +import * as RateLimit from "../../middlewares/rate-limit"; + +const apeKeyNameSchema = joi + .string() + .regex(/^[0-9a-zA-Z_.-]+$/) + .max(20) + .messages({ + "string.pattern.base": "Invalid ApeKey name", + "string.max": "ApeKey name exceeds maximum of 20 characters", + }); + +const router = Router(); + +router.use( + validateConfiguration({ + criteria: (configuration) => { + return configuration.apeKeys.endpointsEnabled; + }, + invalidMessage: "ApeKeys are currently disabled.", + }) +); + +router.get( + "/", + RateLimit.apeKeysGet, + authenticateRequest(), + asyncHandler(ApeKeysController.getApeKey) +); + +router.post( + "/", + RateLimit.apeKeysGenerate, + authenticateRequest(), + validateRequest({ + body: { + name: apeKeyNameSchema.required(), + enabled: joi.boolean().required(), + }, + }), + asyncHandler(ApeKeysController.generateApeKey) +); + +router.patch( + "/:apeKeyId", + RateLimit.apeKeysUpdate, + authenticateRequest(), + validateRequest({ + params: { + apeKeyId: joi.string().required(), + }, + body: { + name: apeKeyNameSchema, + enabled: joi.boolean(), + }, + }), + asyncHandler(ApeKeysController.updateApeKey) +); + +router.delete( + "/:apeKeyId", + RateLimit.apeKeysDelete, + authenticateRequest(), + validateRequest({ + params: { + apeKeyId: joi.string().required(), + }, + }), + asyncHandler(ApeKeysController.deleteApeKey) +); + +export default router; diff --git a/backend/api/routes/index.ts b/backend/api/routes/index.ts index dc7307b0f..b9f3e0174 100644 --- a/backend/api/routes/index.ts +++ b/backend/api/routes/index.ts @@ -5,6 +5,7 @@ import presets from "./presets"; import psas from "./psas"; import leaderboards from "./leaderboards"; import quotes from "./quotes"; +import apeKeys from "./ape-keys"; import { asyncHandler } from "../../middlewares/api-utils"; import { MonkeyResponse } from "../../handlers/monkey-response"; import { Application, NextFunction, Response } from "express"; @@ -22,6 +23,7 @@ const API_ROUTE_MAP = { "/psas": psas, "/leaderboards": leaderboards, "/quotes": quotes, + "/ape-keys": apeKeys, }; function addApiRoutes(app: Application): void { @@ -73,6 +75,16 @@ function addApiRoutes(app: Application): void { const router = API_ROUTE_MAP[route]; app.use(apiRoute, router); }); + + app.use( + asyncHandler(async (req, _res) => { + return new MonkeyResponse( + `Unknown request URL (${req.method}: ${req.path})`, + null, + 404 + ); + }) + ); } export default addApiRoutes; diff --git a/backend/constants/base-configuration.ts b/backend/constants/base-configuration.ts index b19bcb512..ee3a52008 100644 --- a/backend/constants/base-configuration.ts +++ b/backend/constants/base-configuration.ts @@ -16,8 +16,10 @@ const BASE_CONFIGURATION: MonkeyTypes.Configuration = { resultObjectHashCheck: { enabled: false, }, - monkeyTokens: { - enabled: false, + apeKeys: { + endpointsEnabled: false, + acceptKeys: false, + maxKeysPerUser: 0, }, enableSavingResults: { enabled: false, diff --git a/backend/middlewares/auth.ts b/backend/middlewares/auth.ts index 3e2738b00..f278e7d08 100644 --- a/backend/middlewares/auth.ts +++ b/backend/middlewares/auth.ts @@ -4,12 +4,12 @@ import { NextFunction, Response, Handler } from "express"; interface RequestAuthenticationOptions { isPublic?: boolean; - acceptMonkeyTokens?: boolean; + acceptApeKeys?: boolean; } const DEFAULT_OPTIONS: RequestAuthenticationOptions = { isPublic: false, - acceptMonkeyTokens: false, + acceptApeKeys: false, }; function authenticateRequest(authOptions = DEFAULT_OPTIONS): Handler { @@ -28,7 +28,11 @@ function authenticateRequest(authOptions = DEFAULT_OPTIONS): Handler { let token: MonkeyTypes.DecodedToken = {}; if (authHeader) { - token = await authenticateWithAuthHeader(authHeader, options); + token = await authenticateWithAuthHeader( + authHeader, + req.ctx.configuration, + options + ); } else if (options.isPublic) { return next(); } else if (process.env.MODE === "dev") { @@ -72,6 +76,7 @@ function authenticateWithBody( async function authenticateWithAuthHeader( authHeader: string, + configuration: MonkeyTypes.Configuration, options: RequestAuthenticationOptions ): Promise { const token = authHeader.split(" "); @@ -82,8 +87,8 @@ async function authenticateWithAuthHeader( switch (authScheme) { case "Bearer": return await authenticateWithBearerToken(credentials); - case "MonkeyToken": - return await authenticateWithMonkeyToken(credentials, options); + case "ApeKey": + return await authenticateWithApeKey(credentials, configuration, options); } throw new MonkeyError( @@ -126,15 +131,19 @@ async function authenticateWithBearerToken( } } -async function authenticateWithMonkeyToken( - token: string, +async function authenticateWithApeKey( + key: string, + configuration: MonkeyTypes.Configuration, options: RequestAuthenticationOptions ): Promise { - if (!options.acceptMonkeyTokens) { - throw new MonkeyError(401, "This endpoint does not accept MonkeyTokens."); + if (!configuration.apeKeys.acceptKeys) { + throw new MonkeyError(403, "ApeKeys are not being accepted at this time."); + } + if (!options.acceptApeKeys) { + throw new MonkeyError(401, "This endpoint does not accept ApeKeys."); } - throw new MonkeyError(401, "MonkeyTokens are not implemented."); + throw new MonkeyError(401, "ApeKeys are not implemented."); } export { authenticateRequest }; diff --git a/backend/middlewares/rate-limit.ts b/backend/middlewares/rate-limit.ts index 470fa0ea0..ad521cddb 100644 --- a/backend/middlewares/rate-limit.ts +++ b/backend/middlewares/rate-limit.ts @@ -20,16 +20,18 @@ const customHandler = ( throw new MonkeyError(429, "Too many attempts, please try again later."); }; +const ONE_HOUR = 1000 * 60 * 60; + // Config Routing export const configUpdate = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const configGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 120 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -37,7 +39,7 @@ export const configGet = rateLimit({ // Leaderboards Routing export const leaderboardsGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -45,21 +47,21 @@ export const leaderboardsGet = rateLimit({ // New Quotes Routing export const newQuotesGet = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const newQuotesAdd = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const newQuotesAction = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -67,14 +69,14 @@ export const newQuotesAction = rateLimit({ // Quote Ratings Routing export const quoteRatingsGet = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const quoteRatingsSubmit = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -90,28 +92,28 @@ export const quoteReportSubmit = rateLimit({ // Presets Routing export const presetsGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const presetsAdd = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const presetsRemove = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const presetsEdit = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -127,42 +129,42 @@ export const psaGet = rateLimit({ // Results Routing export const resultsGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const resultsAdd = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 500 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const resultsTagsUpdate = rateLimit({ - windowMs: 60 * 60 * 1000, + windowMs: ONE_HOUR, max: 30 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const resultsDeleteAll = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 10 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const resultsLeaderboardGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const resultsLeaderboardQualificationGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -170,21 +172,21 @@ export const resultsLeaderboardQualificationGet = rateLimit({ // Users Routing export const userGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userSignup = rateLimit({ - windowMs: 24 * 60 * 60 * 1000, // 1 day + windowMs: 24 * ONE_HOUR, // 1 day max: 3 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userDelete = rateLimit({ - windowMs: 24 * 60 * 60 * 1000, // 1 day + windowMs: 24 * ONE_HOUR, // 1 day max: 3 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -198,7 +200,7 @@ export const userCheckName = rateLimit({ }); export const userUpdateName = rateLimit({ - windowMs: 24 * 60 * 60 * 1000, // 1 day + windowMs: 24 * ONE_HOUR, // 1 day max: 3 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -212,56 +214,56 @@ export const userUpdateLBMemory = rateLimit({ }); export const userUpdateEmail = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userClearPB = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userTagsGet = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userTagsRemove = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 30 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userTagsClearPB = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 60 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userTagsEdit = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 30 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userTagsAdd = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 30 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); export const userDiscordLink = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 15 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, @@ -270,8 +272,27 @@ export const userDiscordLink = rateLimit({ export const usersTagsEdit = userDiscordLink; export const userDiscordUnlink = rateLimit({ - windowMs: 60 * 60 * 1000, // 60 min + windowMs: ONE_HOUR, max: 15 * REQUEST_MULTIPLIER, keyGenerator: getAddress, handler: customHandler, }); + +// ApeKeys Routing +export const apeKeysGet = rateLimit({ + windowMs: ONE_HOUR, + max: 120 * REQUEST_MULTIPLIER, + keyGenerator: getAddress, + handler: customHandler, +}); + +export const apeKeysGenerate = rateLimit({ + windowMs: ONE_HOUR, + max: 15 * REQUEST_MULTIPLIER, + keyGenerator: getAddress, + handler: customHandler, +}); + +export const apeKeysUpdate = apeKeysGenerate; + +export const apeKeysDelete = apeKeysGenerate; diff --git a/backend/package-lock.json b/backend/package-lock.json index 7c3893dc9..016b6ed71 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -14,7 +14,7 @@ "dotenv": "10.0.0", "express": "4.17.1", "express-rate-limit": "6.2.1", - "firebase-admin": "9.11.0", + "firebase-admin": "10.0.2", "helmet": "4.6.0", "joi": "17.6.0", "lodash": "4.17.21", @@ -43,11 +43,35 @@ "npm": "8.1.2" } }, + "node_modules/@firebase/app": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.7.17.tgz", + "integrity": "sha512-OnZab790eMwRxkUs7o/kgniAzSBxecDTGEk1PVhiG0HQhKrIf+R7lgqOZHDb/2GJsX12jby1p/Z5+WJCBxVbJQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-compat": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.18.tgz", + "integrity": "sha512-YXmMLQro2g2xlNnzB6zVxYoFx9sJS/JDEQy6vsj3FpMUuARaImipL6W8KuGfH+tJ3M+q38qRaFROk5gK6PoCrQ==", + "peer": true, + "dependencies": { + "@firebase/app": "0.7.17", + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "tslib": "^2.1.0" + } + }, "node_modules/@firebase/app-types": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.7.0.tgz", - "integrity": "sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg==", - "peer": true + "integrity": "sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg==" }, "node_modules/@firebase/auth-interop-types": { "version": "0.1.6", @@ -59,58 +83,72 @@ } }, "node_modules/@firebase/component": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.5.tgz", - "integrity": "sha512-L41SdS/4a164jx2iGfakJgaBUPPBI3DI+RrUlmh3oHSUljTeCwfj/Nhcv3S7e2lyXsGFJtAyepfPUx4IQ05crw==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.10.tgz", + "integrity": "sha512-mzUpg6rsBbdQJvAdu1rNWabU3O7qdd+B+/ubE1b+pTbBKfw5ySRpRRE6sKcZ/oQuwLh0HHB6FRJHcylmI7jDzA==", "dependencies": { - "@firebase/util": "1.2.0", + "@firebase/util": "1.4.3", "tslib": "^2.1.0" } }, "node_modules/@firebase/database": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.10.9.tgz", - "integrity": "sha512-Jxi9SiE4cNOftO9YKlG71ccyWFw4kSM9AG/xYu6vWXUGBr39Uw1TvYougANOcU21Q0TP4J08VPGnOnpXk/FGbQ==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.12.5.tgz", + "integrity": "sha512-1Pd2jYqvqZI7SQWAiXbTZxmsOa29PyOaPiUtr8pkLSfLp4AeyMBegYAXCLYLW6BNhKn3zNKFkxYDxYHq4q+Ixg==", "dependencies": { "@firebase/auth-interop-types": "0.1.6", - "@firebase/component": "0.5.5", - "@firebase/database-types": "0.7.3", - "@firebase/logger": "0.2.6", - "@firebase/util": "1.2.0", - "faye-websocket": "0.11.3", + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, - "node_modules/@firebase/database-types": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.7.3.tgz", - "integrity": "sha512-dSOJmhKQ0nL8O4EQMRNGpSExWCXeHtH57gGg0BfNAdWcKhC8/4Y+qfKLfWXzyHvrSecpLmO0SmAi/iK2D5fp5A==", + "node_modules/@firebase/database-compat": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.1.5.tgz", + "integrity": "sha512-UVxkHL24sZfsjsjs+yiKIdYdrWXHrLxSFCYNdwNXDlTkAc0CWP9AAY3feLhBVpUKk+4Cj0I4sGnyIm2C1ltAYg==", "dependencies": { - "@firebase/app-types": "0.6.3" + "@firebase/component": "0.5.10", + "@firebase/database": "0.12.5", + "@firebase/database-types": "0.9.4", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" } }, - "node_modules/@firebase/database-types/node_modules/@firebase/app-types": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.6.3.tgz", - "integrity": "sha512-/M13DPPati7FQHEQ9Minjk1HGLm/4K4gs9bR4rzLCWJg64yGtVC0zNg9gDpkw9yc2cvol/mNFxqTtd4geGrwdw==" + "node_modules/@firebase/database-types": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.4.tgz", + "integrity": "sha512-uAQuc6NUZ5Oh/cWZPeMValtcZ+4L1stgKOeYvz7mLn8+s03tnCDL2N47OLCHdntktVkhImQTwGNARgqhIhtNeA==", + "dependencies": { + "@firebase/app-types": "0.7.0", + "@firebase/util": "1.4.3" + } }, "node_modules/@firebase/logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.6.tgz", - "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.2.tgz", + "integrity": "sha512-lzLrcJp9QBWpo40OcOM9B8QEtBw2Fk1zOZQdvv+rWS6gKmhQBCEMc4SMABQfWdjsylBcDfniD1Q+fUX1dcBTXA==", + "dependencies": { + "tslib": "^2.1.0" + } }, "node_modules/@firebase/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.2.0.tgz", - "integrity": "sha512-8W9TTGImXr9cu+oyjBJ7yjoEd/IVAv0pBZA4c1uIuKrpGZi2ee38m+8xlZOBRmsAaOU/tR9DXz1WF/oeM6Fb7Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.4.3.tgz", + "integrity": "sha512-gQJl6r0a+MElLQEyU8Dx0kkC2coPj67f/zKZrGR7z7WpLgVanhaCUqEsptwpwoxi9RMFIaebleG+C9xxoARq+Q==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@google-cloud/common": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.9.0.tgz", - "integrity": "sha512-R9PfmCKbpOizvcLY+fz/TS4HdOQhvmf4EY4xEXvWnotGbGXujuTLJTJ2URy8BGT8TDxlh6gjjfEwjJ8McnNPIg==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", + "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", "optional": true, "dependencies": { "@google-cloud/projectify": "^2.0.0", @@ -119,7 +157,7 @@ "duplexify": "^4.1.1", "ent": "^2.2.0", "extend": "^3.0.2", - "google-auth-library": "^7.9.2", + "google-auth-library": "^7.14.0", "retry-request": "^4.2.2", "teeny-request": "^7.0.0" }, @@ -143,9 +181,9 @@ } }, "node_modules/@google-cloud/paginator": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.6.tgz", - "integrity": "sha512-XCTm/GfQIlc1ZxpNtTSs/mnZxC2cePNhxU3X8EzHXKIJ2JFncmJj2Fcd2IP+gbmZaSZnY0juFxbUCkIeuu/2eQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", "optional": true, "dependencies": { "arrify": "^2.0.0", @@ -174,13 +212,13 @@ } }, "node_modules/@google-cloud/storage": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.1.tgz", - "integrity": "sha512-EeVIarDb6u9vE5Se3YaXA8tuW8Ae2xmYLHy43doutTwzkXwizGXVS2Qmc2pouq9ln8qMD9A2f3arvhgAPtK9LQ==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.2.tgz", + "integrity": "sha512-hL/6epBF2uPt7YtJoOKI6mVxe6RsKBs7S8o2grE0bFGdQKSOngVHBcstH8jDw7aN2rXGouA2TfVTxH+VapY5cg==", "optional": true, "dependencies": { "@google-cloud/common": "^3.8.1", - "@google-cloud/paginator": "^3.0.0", + "@google-cloud/paginator": "^3.0.7", "@google-cloud/promisify": "^2.0.0", "abort-controller": "^3.0.0", "arrify": "^2.0.0", @@ -219,9 +257,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.5.4.tgz", - "integrity": "sha512-+nJTOsqpFAXnfFrMZ7Too4XXZ/J9O+8jYvSoaunupoC7I7b9H4iex1BRsbTdOmiowfPGJrWit7jUPmbENSUSpw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.5.7.tgz", + "integrity": "sha512-RAlSbZ9LXo0wNoHKeUlwP9dtGgVBDUbnBKFpfAv5iSqMG4qWz9um2yLH215+Wow1I48etIa1QMS+WAGmsE/7HQ==", "optional": true, "dependencies": { "@grpc/proto-loader": "^0.6.4", @@ -479,9 +517,9 @@ } }, "node_modules/@types/express-unless": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.2.tgz", - "integrity": "sha512-Q74UyYRX/zIgl1HSp9tUX2PlG8glkVm+59r7aK4KGKzC5jqKIOX6rrVLRQrzpZUQ84VukHtRoeAuon2nIssHPQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", "dependencies": { "@types/express": "*" } @@ -1221,9 +1259,9 @@ } }, "node_modules/date-and-time": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.1.0.tgz", - "integrity": "sha512-X/b2gM7e8zQ7siiE0DhRLeNMpuCkIqec5Jnx4GMk/HWB71a6e5Lz48mH9/GIS/hpLsBRFZfMF1gjXBkY0vq5oA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.2.1.tgz", + "integrity": "sha512-i5lrLPmRbdtb9/Tcu+NWWvff29ejNZtnL/6TI5VbhuPtqgea7bovY0F2AtFSX9QDQEQLUtqJ3R8ypM2c6alGoA==", "optional": true }, "node_modules/debug": { @@ -1503,9 +1541,9 @@ "optional": true }, "node_modules/faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", - "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -1542,20 +1580,20 @@ } }, "node_modules/firebase-admin": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.11.0.tgz", - "integrity": "sha512-68fXdwcKF99LkWBE33M5hnLwjvGpbCRznIOtZVsiBqZdM9iwxlTfNEpAckh++o3GdJcSLRUWmIN+MKqPUsxoCA==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-10.0.2.tgz", + "integrity": "sha512-MLH0SPmC4L0aCHvPjs1KThraru/T84T3hxiPY3uCH7NZEgE/T5n4GwecwU3RcM3X+br75BIBY7qhaR5uCxhdXA==", "dependencies": { - "@firebase/database": "^0.10.0", - "@firebase/database-types": "^0.7.2", + "@firebase/database-compat": "^0.1.1", + "@firebase/database-types": "^0.9.3", "@types/node": ">=12.12.47", "dicer": "^0.3.0", "jsonwebtoken": "^8.5.1", "jwks-rsa": "^2.0.2", - "node-forge": "^0.10.0" + "node-forge": "^1.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=12.7.0" }, "optionalDependencies": { "@google-cloud/firestore": "^4.5.0", @@ -1720,9 +1758,9 @@ } }, "node_modules/google-auth-library": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", - "integrity": "sha512-3S5jn2quRumvh9F/Ubf7GFrIq71HZ5a6vqosgdIu105kkk0WtSqc2jGCRqtWWOLRS8SX3AHACMOEDxhyWAQIcg==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", + "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", "optional": true, "dependencies": { "arrify": "^2.0.0", @@ -1740,9 +1778,9 @@ } }, "node_modules/google-gax": { - "version": "2.29.5", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.29.5.tgz", - "integrity": "sha512-wJI+rgqujcl4/0eO4sRIwXAJAD+G8dFRqvGxc2lUuZtdzOToc5NHYbrTvplWQVO6Lw1YNsk9u1pKN3HcXembJg==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.30.0.tgz", + "integrity": "sha512-JcZGDuSOzhPwOJfbK80cyyGLZkrlLBTiwfqrW46sC0I9h3FtFmbN7FwIQ3PHreYiE6iVK4InfEZiTp4laOmPfA==", "optional": true, "dependencies": { "@grpc/grpc-js": "~1.5.0", @@ -1751,10 +1789,10 @@ "abort-controller": "^3.0.0", "duplexify": "^4.0.0", "fast-text-encoding": "^1.0.3", - "google-auth-library": "^7.6.1", + "google-auth-library": "^7.14.0", "is-stream-ended": "^0.1.4", "node-fetch": "^2.6.1", - "object-hash": "^2.1.1", + "object-hash": "^3.0.0", "proto3-json-serializer": "^0.1.8", "protobufjs": "6.11.2", "retry-request": "^4.0.0" @@ -1781,15 +1819,6 @@ "node": ">=10" } }, - "node_modules/google-p12-pem/node_modules/node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", - "optional": true, - "engines": { - "node": ">= 6.13.0" - } - }, "node_modules/got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -2752,11 +2781,11 @@ } }, "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", + "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", "engines": { - "node": ">= 6.0.0" + "node": ">= 6.13.0" } }, "node_modules/node-object-hash": { @@ -2854,9 +2883,9 @@ } }, "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "optional": true, "engines": { "node": ">= 6" @@ -4107,11 +4136,35 @@ } }, "dependencies": { + "@firebase/app": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.7.17.tgz", + "integrity": "sha512-OnZab790eMwRxkUs7o/kgniAzSBxecDTGEk1PVhiG0HQhKrIf+R7lgqOZHDb/2GJsX12jby1p/Z5+WJCBxVbJQ==", + "peer": true, + "requires": { + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "tslib": "^2.1.0" + } + }, + "@firebase/app-compat": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.18.tgz", + "integrity": "sha512-YXmMLQro2g2xlNnzB6zVxYoFx9sJS/JDEQy6vsj3FpMUuARaImipL6W8KuGfH+tJ3M+q38qRaFROk5gK6PoCrQ==", + "peer": true, + "requires": { + "@firebase/app": "0.7.17", + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "tslib": "^2.1.0" + } + }, "@firebase/app-types": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.7.0.tgz", - "integrity": "sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg==", - "peer": true + "integrity": "sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg==" }, "@firebase/auth-interop-types": { "version": "0.1.6", @@ -4120,60 +4173,69 @@ "requires": {} }, "@firebase/component": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.5.tgz", - "integrity": "sha512-L41SdS/4a164jx2iGfakJgaBUPPBI3DI+RrUlmh3oHSUljTeCwfj/Nhcv3S7e2lyXsGFJtAyepfPUx4IQ05crw==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.10.tgz", + "integrity": "sha512-mzUpg6rsBbdQJvAdu1rNWabU3O7qdd+B+/ubE1b+pTbBKfw5ySRpRRE6sKcZ/oQuwLh0HHB6FRJHcylmI7jDzA==", "requires": { - "@firebase/util": "1.2.0", + "@firebase/util": "1.4.3", "tslib": "^2.1.0" } }, "@firebase/database": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.10.9.tgz", - "integrity": "sha512-Jxi9SiE4cNOftO9YKlG71ccyWFw4kSM9AG/xYu6vWXUGBr39Uw1TvYougANOcU21Q0TP4J08VPGnOnpXk/FGbQ==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.12.5.tgz", + "integrity": "sha512-1Pd2jYqvqZI7SQWAiXbTZxmsOa29PyOaPiUtr8pkLSfLp4AeyMBegYAXCLYLW6BNhKn3zNKFkxYDxYHq4q+Ixg==", "requires": { "@firebase/auth-interop-types": "0.1.6", - "@firebase/component": "0.5.5", - "@firebase/database-types": "0.7.3", - "@firebase/logger": "0.2.6", - "@firebase/util": "1.2.0", - "faye-websocket": "0.11.3", + "@firebase/component": "0.5.10", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "@firebase/database-compat": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.1.5.tgz", + "integrity": "sha512-UVxkHL24sZfsjsjs+yiKIdYdrWXHrLxSFCYNdwNXDlTkAc0CWP9AAY3feLhBVpUKk+4Cj0I4sGnyIm2C1ltAYg==", + "requires": { + "@firebase/component": "0.5.10", + "@firebase/database": "0.12.5", + "@firebase/database-types": "0.9.4", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.4.3", "tslib": "^2.1.0" } }, "@firebase/database-types": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.7.3.tgz", - "integrity": "sha512-dSOJmhKQ0nL8O4EQMRNGpSExWCXeHtH57gGg0BfNAdWcKhC8/4Y+qfKLfWXzyHvrSecpLmO0SmAi/iK2D5fp5A==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.4.tgz", + "integrity": "sha512-uAQuc6NUZ5Oh/cWZPeMValtcZ+4L1stgKOeYvz7mLn8+s03tnCDL2N47OLCHdntktVkhImQTwGNARgqhIhtNeA==", "requires": { - "@firebase/app-types": "0.6.3" - }, - "dependencies": { - "@firebase/app-types": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.6.3.tgz", - "integrity": "sha512-/M13DPPati7FQHEQ9Minjk1HGLm/4K4gs9bR4rzLCWJg64yGtVC0zNg9gDpkw9yc2cvol/mNFxqTtd4geGrwdw==" - } + "@firebase/app-types": "0.7.0", + "@firebase/util": "1.4.3" } }, "@firebase/logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.6.tgz", - "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.2.tgz", + "integrity": "sha512-lzLrcJp9QBWpo40OcOM9B8QEtBw2Fk1zOZQdvv+rWS6gKmhQBCEMc4SMABQfWdjsylBcDfniD1Q+fUX1dcBTXA==", + "requires": { + "tslib": "^2.1.0" + } }, "@firebase/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.2.0.tgz", - "integrity": "sha512-8W9TTGImXr9cu+oyjBJ7yjoEd/IVAv0pBZA4c1uIuKrpGZi2ee38m+8xlZOBRmsAaOU/tR9DXz1WF/oeM6Fb7Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.4.3.tgz", + "integrity": "sha512-gQJl6r0a+MElLQEyU8Dx0kkC2coPj67f/zKZrGR7z7WpLgVanhaCUqEsptwpwoxi9RMFIaebleG+C9xxoARq+Q==", "requires": { "tslib": "^2.1.0" } }, "@google-cloud/common": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.9.0.tgz", - "integrity": "sha512-R9PfmCKbpOizvcLY+fz/TS4HdOQhvmf4EY4xEXvWnotGbGXujuTLJTJ2URy8BGT8TDxlh6gjjfEwjJ8McnNPIg==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.10.0.tgz", + "integrity": "sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw==", "optional": true, "requires": { "@google-cloud/projectify": "^2.0.0", @@ -4182,7 +4244,7 @@ "duplexify": "^4.1.1", "ent": "^2.2.0", "extend": "^3.0.2", - "google-auth-library": "^7.9.2", + "google-auth-library": "^7.14.0", "retry-request": "^4.2.2", "teeny-request": "^7.0.0" } @@ -4200,9 +4262,9 @@ } }, "@google-cloud/paginator": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.6.tgz", - "integrity": "sha512-XCTm/GfQIlc1ZxpNtTSs/mnZxC2cePNhxU3X8EzHXKIJ2JFncmJj2Fcd2IP+gbmZaSZnY0juFxbUCkIeuu/2eQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -4222,13 +4284,13 @@ "optional": true }, "@google-cloud/storage": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.1.tgz", - "integrity": "sha512-EeVIarDb6u9vE5Se3YaXA8tuW8Ae2xmYLHy43doutTwzkXwizGXVS2Qmc2pouq9ln8qMD9A2f3arvhgAPtK9LQ==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.18.2.tgz", + "integrity": "sha512-hL/6epBF2uPt7YtJoOKI6mVxe6RsKBs7S8o2grE0bFGdQKSOngVHBcstH8jDw7aN2rXGouA2TfVTxH+VapY5cg==", "optional": true, "requires": { "@google-cloud/common": "^3.8.1", - "@google-cloud/paginator": "^3.0.0", + "@google-cloud/paginator": "^3.0.7", "@google-cloud/promisify": "^2.0.0", "abort-controller": "^3.0.0", "arrify": "^2.0.0", @@ -4260,9 +4322,9 @@ } }, "@grpc/grpc-js": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.5.4.tgz", - "integrity": "sha512-+nJTOsqpFAXnfFrMZ7Too4XXZ/J9O+8jYvSoaunupoC7I7b9H4iex1BRsbTdOmiowfPGJrWit7jUPmbENSUSpw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.5.7.tgz", + "integrity": "sha512-RAlSbZ9LXo0wNoHKeUlwP9dtGgVBDUbnBKFpfAv5iSqMG4qWz9um2yLH215+Wow1I48etIa1QMS+WAGmsE/7HQ==", "optional": true, "requires": { "@grpc/proto-loader": "^0.6.4", @@ -4493,9 +4555,9 @@ } }, "@types/express-unless": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.2.tgz", - "integrity": "sha512-Q74UyYRX/zIgl1HSp9tUX2PlG8glkVm+59r7aK4KGKzC5jqKIOX6rrVLRQrzpZUQ84VukHtRoeAuon2nIssHPQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", "requires": { "@types/express": "*" } @@ -5065,9 +5127,9 @@ } }, "date-and-time": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.1.0.tgz", - "integrity": "sha512-X/b2gM7e8zQ7siiE0DhRLeNMpuCkIqec5Jnx4GMk/HWB71a6e5Lz48mH9/GIS/hpLsBRFZfMF1gjXBkY0vq5oA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.2.1.tgz", + "integrity": "sha512-i5lrLPmRbdtb9/Tcu+NWWvff29ejNZtnL/6TI5VbhuPtqgea7bovY0F2AtFSX9QDQEQLUtqJ3R8ypM2c6alGoA==", "optional": true }, "debug": { @@ -5297,9 +5359,9 @@ "optional": true }, "faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", - "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "requires": { "websocket-driver": ">=0.5.1" } @@ -5327,19 +5389,19 @@ } }, "firebase-admin": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.11.0.tgz", - "integrity": "sha512-68fXdwcKF99LkWBE33M5hnLwjvGpbCRznIOtZVsiBqZdM9iwxlTfNEpAckh++o3GdJcSLRUWmIN+MKqPUsxoCA==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-10.0.2.tgz", + "integrity": "sha512-MLH0SPmC4L0aCHvPjs1KThraru/T84T3hxiPY3uCH7NZEgE/T5n4GwecwU3RcM3X+br75BIBY7qhaR5uCxhdXA==", "requires": { - "@firebase/database": "^0.10.0", - "@firebase/database-types": "^0.7.2", + "@firebase/database-compat": "^0.1.1", + "@firebase/database-types": "^0.9.3", "@google-cloud/firestore": "^4.5.0", "@google-cloud/storage": "^5.3.0", "@types/node": ">=12.12.47", "dicer": "^0.3.0", "jsonwebtoken": "^8.5.1", "jwks-rsa": "^2.0.2", - "node-forge": "^0.10.0" + "node-forge": "^1.0.0" } }, "forever-agent": { @@ -5454,9 +5516,9 @@ } }, "google-auth-library": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", - "integrity": "sha512-3S5jn2quRumvh9F/Ubf7GFrIq71HZ5a6vqosgdIu105kkk0WtSqc2jGCRqtWWOLRS8SX3AHACMOEDxhyWAQIcg==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", + "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -5471,9 +5533,9 @@ } }, "google-gax": { - "version": "2.29.5", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.29.5.tgz", - "integrity": "sha512-wJI+rgqujcl4/0eO4sRIwXAJAD+G8dFRqvGxc2lUuZtdzOToc5NHYbrTvplWQVO6Lw1YNsk9u1pKN3HcXembJg==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.30.0.tgz", + "integrity": "sha512-JcZGDuSOzhPwOJfbK80cyyGLZkrlLBTiwfqrW46sC0I9h3FtFmbN7FwIQ3PHreYiE6iVK4InfEZiTp4laOmPfA==", "optional": true, "requires": { "@grpc/grpc-js": "~1.5.0", @@ -5482,10 +5544,10 @@ "abort-controller": "^3.0.0", "duplexify": "^4.0.0", "fast-text-encoding": "^1.0.3", - "google-auth-library": "^7.6.1", + "google-auth-library": "^7.14.0", "is-stream-ended": "^0.1.4", "node-fetch": "^2.6.1", - "object-hash": "^2.1.1", + "object-hash": "^3.0.0", "proto3-json-serializer": "^0.1.8", "protobufjs": "6.11.2", "retry-request": "^4.0.0" @@ -5498,14 +5560,6 @@ "optional": true, "requires": { "node-forge": "^1.0.0" - }, - "dependencies": { - "node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", - "optional": true - } } }, "got": { @@ -6255,9 +6309,9 @@ } }, "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", + "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==" }, "node-object-hash": { "version": "2.3.10", @@ -6323,9 +6377,9 @@ "version": "4.1.1" }, "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "optional": true }, "object-inspect": { diff --git a/backend/package.json b/backend/package.json index c5ab96240..f5bc98021 100644 --- a/backend/package.json +++ b/backend/package.json @@ -21,7 +21,7 @@ "dotenv": "10.0.0", "express": "4.17.1", "express-rate-limit": "6.2.1", - "firebase-admin": "9.11.0", + "firebase-admin": "10.0.2", "helmet": "4.6.0", "joi": "17.6.0", "lodash": "4.17.21", diff --git a/backend/types/types.d.ts b/backend/types/types.d.ts index a198d6f48..64bef8056 100644 --- a/backend/types/types.d.ts +++ b/backend/types/types.d.ts @@ -14,13 +14,16 @@ declare namespace MonkeyTypes { resultObjectHashCheck: { enabled: boolean; }; - monkeyTokens: { - enabled: boolean; + apeKeys: { + endpointsEnabled: boolean; + acceptKeys: boolean; + maxKeysPerUser: number; }; enableSavingResults: { enabled: boolean; }; } + interface DecodedToken { uid?: string; email?: string; @@ -58,4 +61,14 @@ declare namespace MonkeyTypes { quoteMod: boolean; cannotReport: boolean; } + + interface ApeKey { + _id: string; + name: string; + hash: string; + uid: string; + createdOn: number; + modifiedOn: number; + enabled: boolean; + } }