From 51fb680f9c1fc6552dd2225e9f594180cb6b888a Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Fri, 1 Mar 2024 22:16:08 +0530 Subject: [PATCH 1/2] feat(server): changed license service to use redis cache keystore --- .../ee/services/license/license-service.ts | 43 +++++++++++-------- backend/src/server/routes/index.ts | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index b0bc11e314..fe6b7a3411 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -5,8 +5,8 @@ // TODO(akhilmhdh): With tony find out the api structure and fill it here import { ForbiddenError } from "@casl/ability"; -import NodeCache from "node-cache"; +import { TKeyStoreFactory } from "@app/keystore/keystore"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; @@ -39,6 +39,7 @@ type TLicenseServiceFactoryDep = { orgDAL: Pick; permissionService: Pick; licenseDAL: TLicenseDALFactory; + keyStore: Pick; }; export type TLicenseServiceFactory = ReturnType; @@ -46,12 +47,18 @@ export type TLicenseServiceFactory = ReturnType; const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login"; const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/license-login"; -const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`; -export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => { +const LICENSE_SERVER_CLOUD_PLAN_TTL = 60; // 60s +const FEATURE_CACHE_KEY = (orgId: string) => `infisical-cloud-plan-${orgId}`; + +export const licenseServiceFactory = ({ + orgDAL, + permissionService, + licenseDAL, + keyStore +}: TLicenseServiceFactoryDep) => { let isValidLicense = false; let instanceType = InstanceType.OnPrem; let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures(); - const featureStore = new NodeCache({ stdTTL: 60 }); const appCfg = getConfig(); const licenseServerCloudApi = setupLicenceRequestWithStore( @@ -75,6 +82,7 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: isValidLicense = true; return; } + if (appCfg.LICENSE_KEY) { const token = await licenseServerOnPremApi.refreshLicence(); if (token) { @@ -100,22 +108,21 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: logger.info(`getPlan: attempting to fetch plan for [orgId=${orgId}] [projectId=${projectId}]`); try { if (instanceType === InstanceType.Cloud) { - const cachedPlan = featureStore.get(FEATURE_CACHE_KEY(orgId, projectId)); - if (cachedPlan) return cachedPlan; + const cachedPlan = await keyStore.getItem(FEATURE_CACHE_KEY(orgId)); + if (cachedPlan) return JSON.parse(cachedPlan) as TFeatureSet; const org = await orgDAL.findOrgById(orgId); if (!org) throw new BadRequestError({ message: "Org not found" }); const { data: { currentPlan } } = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>( - `/api/license-server/v1/customers/${org.customerId}/cloud-plan`, - { - params: { - workspaceId: projectId - } - } + `/api/license-server/v1/customers/${org.customerId}/cloud-plan` + ); + await keyStore.setItemWithExpiry( + FEATURE_CACHE_KEY(org.id), + LICENSE_SERVER_CLOUD_PLAN_TTL, + JSON.stringify(currentPlan) ); - featureStore.set(FEATURE_CACHE_KEY(org.id, projectId), currentPlan); return currentPlan; } } catch (error) { @@ -128,10 +135,10 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: return onPremFeatures; }; - const refreshPlan = async (orgId: string, projectId?: string) => { + const refreshPlan = async (orgId: string) => { if (instanceType === InstanceType.Cloud) { - featureStore.del(FEATURE_CACHE_KEY(orgId, projectId)); - await getPlan(orgId, projectId); + await keyStore.deleteItem(FEATURE_CACHE_KEY(orgId)); + await getPlan(orgId); } }; @@ -166,7 +173,7 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: quantity: count }); } - featureStore.del(orgId); + await keyStore.deleteItem(FEATURE_CACHE_KEY(orgId)); } else if (instanceType === InstanceType.EnterpriseOnPrem) { const usedSeats = await licenseDAL.countOfOrgMembers(null); await licenseServerOnPremApi.request.patch(`/api/license/v1/license`, { usedSeats }); @@ -215,7 +222,7 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: `/api/license-server/v1/customers/${organization.customerId}/session/trial`, { success_url } ); - featureStore.del(FEATURE_CACHE_KEY(orgId)); + await keyStore.deleteItem(FEATURE_CACHE_KEY(orgId)); return { url }; }; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index a218256339..d3d01ccb5d 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -194,7 +194,7 @@ export const registerRoutes = async ( projectRoleDAL, serviceTokenDAL }); - const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL }); + const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL, keyStore }); const trustedIpService = trustedIpServiceFactory({ licenseService, projectDAL, From 6a7241d7d13e89946bb052f9f4b42a1e49a74c19 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Fri, 1 Mar 2024 22:20:25 +0530 Subject: [PATCH 2/2] feat(server): uninstalled node-cache --- backend/package-lock.json | 20 -------------------- backend/package.json | 1 - 2 files changed, 21 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index c18378aa9a..a829cf346d 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -47,7 +47,6 @@ "lodash.isequal": "^4.5.0", "mysql2": "^3.9.1", "nanoid": "^5.0.4", - "node-cache": "^5.1.2", "nodemailer": "^6.9.9", "ora": "^7.0.1", "passport-github": "^1.1.0", @@ -5706,14 +5705,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -9258,17 +9249,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, - "node_modules/node-cache": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", - "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "dependencies": { - "clone": "2.x" - }, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", diff --git a/backend/package.json b/backend/package.json index 19fb3fafa6..ad44dc2da9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -108,7 +108,6 @@ "lodash.isequal": "^4.5.0", "mysql2": "^3.9.1", "nanoid": "^5.0.4", - "node-cache": "^5.1.2", "nodemailer": "^6.9.9", "ora": "^7.0.1", "passport-github": "^1.1.0",