diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 7a3a8d8024..e99c48c097 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -1,27 +1,39 @@ +/* eslint-env node */ module.exports = { - root: true, env: { - browser: true, - es2021: true + es6: true, + node: true }, - extends: ["airbnb-base", "airbnb-typescript/base", "prettier"], - plugins: ["prettier", "simple-import-sort", "import"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-type-checked", + "airbnb-base", + "airbnb-typescript/base", + "plugin:prettier/recommended", + "prettier" + ], + plugins: ["@typescript-eslint", "simple-import-sort", "import"], + parser: "@typescript-eslint/parser", parserOptions: { - ecmaVersion: "latest", + project: true, sourceType: "module", - project: "./tsconfig.json", tsconfigRootDir: __dirname }, + root: true, rules: { "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "no-void": "off", "consistent-return": "off", // my style "import/order": "off", // for simple-import-order "import/prefer-default-export": "off", // why "no-restricted-syntax": "off", + // importing rules + "simple-import-sort/exports": "error", "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error", - "simple-import-sort/exports": "error", "simple-import-sort/imports": [ "warn", { @@ -45,12 +57,5 @@ module.exports = { ] } ] - }, - settings: { - "import/resolver": { - typescript: { - project: ["./tsconfig.json"] - } - } } }; diff --git a/backend/.prettierrc.json b/backend/.prettierrc.json index f9058accfd..987f567d4e 100644 --- a/backend/.prettierrc.json +++ b/backend/.prettierrc.json @@ -1,7 +1,7 @@ { "singleQuote": false, - "printWidth": 100, + "printWidth": 120, "trailingComma": "none", "tabWidth": 2, "semi": true -} \ No newline at end of file +} diff --git a/backend/package-lock.json b/backend/package-lock.json index 6f8a6d33ea..d1d12ad2eb 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -25,6 +25,8 @@ "@octokit/webhooks-types": "^7.3.1", "@serdnam/pino-cloudwatch-transport": "^1.0.4", "@sindresorhus/slugify": "^2.2.1", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -34,6 +36,8 @@ "bcrypt": "^5.1.1", "bullmq": "^5.1.1", "dotenv": "^16.3.1", + "eslint": "^8.56.0", + "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", @@ -80,10 +84,6 @@ "@types/picomatch": "^2.3.3", "@types/prompt-sync": "^4.2.3", "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", - "eslint": "^8.56.0", - "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -4530,15 +4530,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", - "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", + "integrity": "sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==", "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/type-utils": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/type-utils": "6.20.0", + "@typescript-eslint/utils": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -4585,14 +4585,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", - "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", + "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", + "dependencies": { + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4" }, "engines": { @@ -4633,12 +4633,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", - "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz", + "integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -4649,12 +4649,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", - "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz", + "integrity": "sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==", "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/utils": "6.20.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -4696,9 +4696,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", - "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz", + "integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4708,15 +4708,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", - "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz", + "integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -4733,6 +4734,14 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4749,22 +4758,36 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", - "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.20.0.tgz", + "integrity": "sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", "semver": "^7.5.4" }, "engines": { @@ -4779,11 +4802,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", - "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz", + "integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==", "dependencies": { - "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/types": "6.20.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/backend/package.json b/backend/package.json index d379d54a86..39aed4e342 100644 --- a/backend/package.json +++ b/backend/package.json @@ -45,10 +45,6 @@ "@types/picomatch": "^2.3.3", "@types/prompt-sync": "^4.2.3", "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", - "eslint": "^8.56.0", - "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -83,6 +79,8 @@ "@octokit/webhooks-types": "^7.3.1", "@serdnam/pino-cloudwatch-transport": "^1.0.4", "@sindresorhus/slugify": "^2.2.1", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -92,6 +90,8 @@ "bcrypt": "^5.1.1", "bullmq": "^5.1.1", "dotenv": "^16.3.1", + "eslint": "^8.56.0", + "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", diff --git a/backend/src/@types/fastify-zod.d.ts b/backend/src/@types/fastify-zod.d.ts index cff119c2f1..3935793916 100644 --- a/backend/src/@types/fastify-zod.d.ts +++ b/backend/src/@types/fastify-zod.d.ts @@ -1,9 +1,4 @@ -import { - FastifyInstance, - RawReplyDefaultExpression, - RawRequestDefaultExpression, - RawServerDefault -} from "fastify"; +import { FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify"; import { Logger } from "pino"; import { ZodTypeProvider } from "@app/server/plugins/fastify-zod"; diff --git a/backend/src/@types/knex.d.ts b/backend/src/@types/knex.d.ts index 05ce1e59d0..5bf5638104 100644 --- a/backend/src/@types/knex.d.ts +++ b/backend/src/@types/knex.d.ts @@ -177,11 +177,7 @@ declare module "knex/types/tables" { TUserEncryptionKeysInsert, TUserEncryptionKeysUpdate >; - [TableName.AuthTokens]: Knex.CompositeTableType< - TAuthTokens, - TAuthTokensInsert, - TAuthTokensUpdate - >; + [TableName.AuthTokens]: Knex.CompositeTableType; [TableName.AuthTokenSession]: Knex.CompositeTableType< TAuthTokenSessions, TAuthTokenSessionsInsert, @@ -192,32 +188,16 @@ declare module "knex/types/tables" { TBackupPrivateKeyInsert, TBackupPrivateKeyUpdate >; - [TableName.Organization]: Knex.CompositeTableType< - TOrganizations, - TOrganizationsInsert, - TOrganizationsUpdate - >; - [TableName.OrgMembership]: Knex.CompositeTableType< - TOrgMemberships, - TOrgMembershipsInsert, - TOrgMembershipsUpdate - >; + [TableName.Organization]: Knex.CompositeTableType; + [TableName.OrgMembership]: Knex.CompositeTableType; [TableName.OrgRoles]: Knex.CompositeTableType; [TableName.IncidentContact]: Knex.CompositeTableType< TIncidentContacts, TIncidentContactsInsert, TIncidentContactsUpdate >; - [TableName.UserAction]: Knex.CompositeTableType< - TUserActions, - TUserActionsInsert, - TUserActionsUpdate - >; - [TableName.SuperAdmin]: Knex.CompositeTableType< - TSuperAdmin, - TSuperAdminInsert, - TSuperAdminUpdate - >; + [TableName.UserAction]: Knex.CompositeTableType; + [TableName.SuperAdmin]: Knex.CompositeTableType; [TableName.ApiKey]: Knex.CompositeTableType; [TableName.Project]: Knex.CompositeTableType; [TableName.ProjectMembership]: Knex.CompositeTableType< @@ -230,73 +210,33 @@ declare module "knex/types/tables" { TProjectEnvironmentsInsert, TProjectEnvironmentsUpdate >; - [TableName.ProjectBot]: Knex.CompositeTableType< - TProjectBots, - TProjectBotsInsert, - TProjectBotsUpdate - >; - [TableName.ProjectRoles]: Knex.CompositeTableType< - TProjectRoles, - TProjectRolesInsert, - TProjectRolesUpdate - >; - [TableName.ProjectKeys]: Knex.CompositeTableType< - TProjectKeys, - TProjectKeysInsert, - TProjectKeysUpdate - >; + [TableName.ProjectBot]: Knex.CompositeTableType; + [TableName.ProjectRoles]: Knex.CompositeTableType; + [TableName.ProjectKeys]: Knex.CompositeTableType; [TableName.Secret]: Knex.CompositeTableType; [TableName.SecretBlindIndex]: Knex.CompositeTableType< TSecretBlindIndexes, TSecretBlindIndexesInsert, TSecretBlindIndexesUpdate >; - [TableName.SecretVersion]: Knex.CompositeTableType< - TSecretVersions, - TSecretVersionsInsert, - TSecretVersionsUpdate - >; - [TableName.SecretFolder]: Knex.CompositeTableType< - TSecretFolders, - TSecretFoldersInsert, - TSecretFoldersUpdate - >; + [TableName.SecretVersion]: Knex.CompositeTableType; + [TableName.SecretFolder]: Knex.CompositeTableType; [TableName.SecretFolderVersion]: Knex.CompositeTableType< TSecretFolderVersions, TSecretFolderVersionsInsert, TSecretFolderVersionsUpdate >; - [TableName.SecretTag]: Knex.CompositeTableType< - TSecretTags, - TSecretTagsInsert, - TSecretTagsUpdate - >; - [TableName.SecretImport]: Knex.CompositeTableType< - TSecretImports, - TSecretImportsInsert, - TSecretImportsUpdate - >; - [TableName.Integration]: Knex.CompositeTableType< - TIntegrations, - TIntegrationsInsert, - TIntegrationsUpdate - >; + [TableName.SecretTag]: Knex.CompositeTableType; + [TableName.SecretImport]: Knex.CompositeTableType; + [TableName.Integration]: Knex.CompositeTableType; [TableName.Webhook]: Knex.CompositeTableType; - [TableName.ServiceToken]: Knex.CompositeTableType< - TServiceTokens, - TServiceTokensInsert, - TServiceTokensUpdate - >; + [TableName.ServiceToken]: Knex.CompositeTableType; [TableName.IntegrationAuth]: Knex.CompositeTableType< TIntegrationAuths, TIntegrationAuthsInsert, TIntegrationAuthsUpdate >; - [TableName.Identity]: Knex.CompositeTableType< - TIdentities, - TIdentitiesInsert, - TIdentitiesUpdate - >; + [TableName.Identity]: Knex.CompositeTableType; [TableName.IdentityUniversalAuth]: Knex.CompositeTableType< TIdentityUniversalAuths, TIdentityUniversalAuthsInsert, @@ -362,11 +302,7 @@ declare module "knex/types/tables" { TSecretRotationOutputsInsert, TSecretRotationOutputsUpdate >; - [TableName.Snapshot]: Knex.CompositeTableType< - TSecretSnapshots, - TSecretSnapshotsInsert, - TSecretSnapshotsUpdate - >; + [TableName.Snapshot]: Knex.CompositeTableType; [TableName.SnapshotSecret]: Knex.CompositeTableType< TSecretSnapshotSecrets, TSecretSnapshotSecretsInsert, @@ -377,11 +313,7 @@ declare module "knex/types/tables" { TSecretSnapshotFoldersInsert, TSecretSnapshotFoldersUpdate >; - [TableName.SamlConfig]: Knex.CompositeTableType< - TSamlConfigs, - TSamlConfigsInsert, - TSamlConfigsUpdate - >; + [TableName.SamlConfig]: Knex.CompositeTableType; [TableName.OrgBot]: Knex.CompositeTableType; [TableName.AuditLog]: Knex.CompositeTableType; [TableName.GitAppInstallSession]: Knex.CompositeTableType< @@ -395,11 +327,7 @@ declare module "knex/types/tables" { TSecretScanningGitRisksInsert, TSecretScanningGitRisksUpdate >; - [TableName.TrustedIps]: Knex.CompositeTableType< - TTrustedIps, - TTrustedIpsInsert, - TTrustedIpsUpdate - >; + [TableName.TrustedIps]: Knex.CompositeTableType; // Junction tables [TableName.JnSecretTag]: Knex.CompositeTableType< TSecretTagJunction, diff --git a/backend/src/db/migrations/20231220052508_secret-version.ts b/backend/src/db/migrations/20231220052508_secret-version.ts index 0bcee295bf..46e3264bf3 100644 --- a/backend/src/db/migrations/20231220052508_secret-version.ts +++ b/backend/src/db/migrations/20231220052508_secret-version.ts @@ -38,12 +38,7 @@ export async function up(knex: Knex): Promise { } await createOnUpdateTrigger(knex, TableName.SecretVersion); // many to many relation between tags - await createJunctionTable( - knex, - TableName.SecretVersionTag, - TableName.SecretVersion, - TableName.SecretTag - ); + await createJunctionTable(knex, TableName.SecretVersionTag, TableName.SecretVersion, TableName.SecretTag); } export async function down(knex: Knex): Promise { diff --git a/backend/src/db/migrations/20231222172455_integration.ts b/backend/src/db/migrations/20231222172455_integration.ts index 4ef34cab13..43fd9986ac 100644 --- a/backend/src/db/migrations/20231222172455_integration.ts +++ b/backend/src/db/migrations/20231222172455_integration.ts @@ -50,10 +50,7 @@ export async function up(knex: Knex): Promise { t.string("integration").notNullable(); t.jsonb("metadata"); t.uuid("integrationAuthId").notNullable(); - t.foreign("integrationAuthId") - .references("id") - .inTable(TableName.IntegrationAuth) - .onDelete("CASCADE"); + t.foreign("integrationAuthId").references("id").inTable(TableName.IntegrationAuth).onDelete("CASCADE"); t.uuid("envId").notNullable(); t.string("secretPath").defaultTo("/").notNullable(); t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE"); diff --git a/backend/src/db/migrations/20231228074908_identity-universal-auth.ts b/backend/src/db/migrations/20231228074908_identity-universal-auth.ts index 76d05db91b..48d58ccd40 100644 --- a/backend/src/db/migrations/20231228074908_identity-universal-auth.ts +++ b/backend/src/db/migrations/20231228074908_identity-universal-auth.ts @@ -31,10 +31,7 @@ export async function up(knex: Knex): Promise { t.boolean("isClientSecretRevoked").defaultTo(false).notNullable(); t.timestamps(true, true, true); t.uuid("identityUAId").notNullable(); - t.foreign("identityUAId") - .references("id") - .inTable(TableName.IdentityUniversalAuth) - .onDelete("CASCADE"); + t.foreign("identityUAId").references("id").inTable(TableName.IdentityUniversalAuth).onDelete("CASCADE"); }); } await createOnUpdateTrigger(knex, TableName.IdentityUniversalAuth); diff --git a/backend/src/db/migrations/20231228075011_identity-access-token.ts b/backend/src/db/migrations/20231228075011_identity-access-token.ts index 33c5f96efa..e8e26fc708 100644 --- a/backend/src/db/migrations/20231228075011_identity-access-token.ts +++ b/backend/src/db/migrations/20231228075011_identity-access-token.ts @@ -19,7 +19,7 @@ export async function up(knex: Knex): Promise { .references("id") .inTable(TableName.IdentityUaClientSecret) .onDelete("CASCADE"); - t.uuid("identityId").notNullable(); + t.uuid("identityId").notNullable(); t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE"); t.timestamps(true, true, true); }); diff --git a/backend/src/db/migrations/20240101054849_secret-approval-policy.ts b/backend/src/db/migrations/20240101054849_secret-approval-policy.ts index 7fde0d3140..3de1ce2801 100644 --- a/backend/src/db/migrations/20240101054849_secret-approval-policy.ts +++ b/backend/src/db/migrations/20240101054849_secret-approval-policy.ts @@ -21,15 +21,9 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.SecretApprovalPolicyApprover, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.uuid("approverId").notNullable(); - t.foreign("approverId") - .references("id") - .inTable(TableName.ProjectMembership) - .onDelete("CASCADE"); + t.foreign("approverId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); t.uuid("policyId").notNullable(); - t.foreign("policyId") - .references("id") - .inTable(TableName.SecretApprovalPolicy) - .onDelete("CASCADE"); + t.foreign("policyId").references("id").inTable(TableName.SecretApprovalPolicy).onDelete("CASCADE"); t.timestamps(true, true, true); }); } diff --git a/backend/src/db/migrations/20240101104907_secret-approval-request.ts b/backend/src/db/migrations/20240101104907_secret-approval-request.ts index 21a9e944ed..f35f878194 100644 --- a/backend/src/db/migrations/20240101104907_secret-approval-request.ts +++ b/backend/src/db/migrations/20240101104907_secret-approval-request.ts @@ -11,23 +11,14 @@ export async function up(knex: Knex): Promise { t.boolean("hasMerged").defaultTo(false).notNullable(); t.string("status").defaultTo("open").notNullable(); t.jsonb("conflicts"); - t.foreign("policyId") - .references("id") - .inTable(TableName.SecretApprovalPolicy) - .onDelete("CASCADE"); + t.foreign("policyId").references("id").inTable(TableName.SecretApprovalPolicy).onDelete("CASCADE"); t.string("slug").notNullable(); t.uuid("folderId").notNullable(); t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE"); t.uuid("statusChangeBy"); - t.foreign("statusChangeBy") - .references("id") - .inTable(TableName.ProjectMembership) - .onDelete("SET NULL"); + t.foreign("statusChangeBy").references("id").inTable(TableName.ProjectMembership).onDelete("SET NULL"); t.uuid("committerId").notNullable(); - t.foreign("committerId") - .references("id") - .inTable(TableName.ProjectMembership) - .onDelete("CASCADE"); + t.foreign("committerId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); t.timestamps(true, true, true); }); } @@ -40,10 +31,7 @@ export async function up(knex: Knex): Promise { t.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); t.string("status").notNullable(); t.uuid("requestId").notNullable(); - t.foreign("requestId") - .references("id") - .inTable(TableName.SecretApprovalRequest) - .onDelete("CASCADE"); + t.foreign("requestId").references("id").inTable(TableName.SecretApprovalRequest).onDelete("CASCADE"); t.timestamps(true, true, true); }); } @@ -73,18 +61,12 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); // commit details t.uuid("requestId").notNullable(); - t.foreign("requestId") - .references("id") - .inTable(TableName.SecretApprovalRequest) - .onDelete("CASCADE"); + t.foreign("requestId").references("id").inTable(TableName.SecretApprovalRequest).onDelete("CASCADE"); t.string("op").notNullable(); t.uuid("secretId"); t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL"); t.uuid("secretVersion"); - t.foreign("secretVersion") - .references("id") - .inTable(TableName.SecretVersion) - .onDelete("SET NULL"); + t.foreign("secretVersion").references("id").inTable(TableName.SecretVersion).onDelete("SET NULL"); }); } await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecret); @@ -93,10 +75,7 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.SecretApprovalRequestSecretTag, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.uuid("secretId").notNullable(); - t.foreign("secretId") - .references("id") - .inTable(TableName.SecretApprovalRequestSecret) - .onDelete("CASCADE"); + t.foreign("secretId").references("id").inTable(TableName.SecretApprovalRequestSecret).onDelete("CASCADE"); t.uuid("tagId").notNullable(); t.foreign("tagId").references("id").inTable(TableName.SecretTag).onDelete("CASCADE"); t.timestamps(true, true, true); diff --git a/backend/src/db/migrations/20240102152111_secret-rotation.ts b/backend/src/db/migrations/20240102152111_secret-rotation.ts index f7009488a5..ea962cc6ec 100644 --- a/backend/src/db/migrations/20240102152111_secret-rotation.ts +++ b/backend/src/db/migrations/20240102152111_secret-rotation.ts @@ -32,10 +32,7 @@ export async function up(knex: Knex): Promise { t.uuid("secretId").notNullable(); t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("CASCADE"); t.uuid("rotationId").notNullable(); - t.foreign("rotationId") - .references("id") - .inTable(TableName.SecretRotation) - .onDelete("CASCADE"); + t.foreign("rotationId").references("id").inTable(TableName.SecretRotation).onDelete("CASCADE"); }); } } diff --git a/backend/src/db/migrations/20240104140641_secret-snapshot.ts b/backend/src/db/migrations/20240104140641_secret-snapshot.ts index 01b1e24fb0..3dfb067725 100644 --- a/backend/src/db/migrations/20240104140641_secret-snapshot.ts +++ b/backend/src/db/migrations/20240104140641_secret-snapshot.ts @@ -25,10 +25,7 @@ export async function up(knex: Knex): Promise { t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE"); // not a relation kept like that to keep it when rolled back t.uuid("secretVersionId").notNullable(); - t.foreign("secretVersionId") - .references("id") - .inTable(TableName.SecretVersion) - .onDelete("CASCADE"); + t.foreign("secretVersionId").references("id").inTable(TableName.SecretVersion).onDelete("CASCADE"); t.uuid("snapshotId").notNullable(); t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE"); t.timestamps(true, true, true); @@ -42,10 +39,7 @@ export async function up(knex: Knex): Promise { t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE"); // not a relation kept like that to keep it when rolled back t.uuid("folderVersionId").notNullable(); - t.foreign("folderVersionId") - .references("id") - .inTable(TableName.SecretFolderVersion) - .onDelete("CASCADE"); + t.foreign("folderVersionId").references("id").inTable(TableName.SecretFolderVersion).onDelete("CASCADE"); t.uuid("snapshotId").notNullable(); t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE"); t.timestamps(true, true, true); diff --git a/backend/src/db/migrations/20240111051011_secret-scanning.ts b/backend/src/db/migrations/20240111051011_secret-scanning.ts index af011d5585..28a57bf08c 100644 --- a/backend/src/db/migrations/20240111051011_secret-scanning.ts +++ b/backend/src/db/migrations/20240111051011_secret-scanning.ts @@ -15,7 +15,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.GitAppInstallSession); + await createOnUpdateTrigger(knex, TableName.GitAppInstallSession); if (!(await knex.schema.hasTable(TableName.GitAppOrg))) { await knex.schema.createTable(TableName.GitAppOrg, (t) => { @@ -28,7 +28,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.GitAppOrg); + await createOnUpdateTrigger(knex, TableName.GitAppOrg); if (!(await knex.schema.hasTable(TableName.SecretScanningGitRisk))) { await knex.schema.createTable(TableName.SecretScanningGitRisk, (t) => { @@ -66,7 +66,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk); + await createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk); } export async function down(knex: Knex): Promise { diff --git a/backend/src/db/schemas/api-keys.ts b/backend/src/db/schemas/api-keys.ts index c3f384a5af..ff29a54e10 100644 --- a/backend/src/db/schemas/api-keys.ts +++ b/backend/src/db/schemas/api-keys.ts @@ -15,7 +15,7 @@ export const ApiKeysSchema = z.object({ secretHash: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TApiKeys = z.infer; diff --git a/backend/src/db/schemas/audit-logs.ts b/backend/src/db/schemas/audit-logs.ts index 90c389b942..f7143bb575 100644 --- a/backend/src/db/schemas/audit-logs.ts +++ b/backend/src/db/schemas/audit-logs.ts @@ -20,7 +20,7 @@ export const AuditLogsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), orgId: z.string().uuid().nullable().optional(), - projectId: z.string().nullable().optional(), + projectId: z.string().nullable().optional() }); export type TAuditLogs = z.infer; diff --git a/backend/src/db/schemas/auth-token-sessions.ts b/backend/src/db/schemas/auth-token-sessions.ts index 9dbf8e09f7..46ed7c2019 100644 --- a/backend/src/db/schemas/auth-token-sessions.ts +++ b/backend/src/db/schemas/auth-token-sessions.ts @@ -16,7 +16,7 @@ export const AuthTokenSessionsSchema = z.object({ lastUsed: z.date(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TAuthTokenSessions = z.infer; diff --git a/backend/src/db/schemas/auth-tokens.ts b/backend/src/db/schemas/auth-tokens.ts index 4a612b11d1..9ae8eed448 100644 --- a/backend/src/db/schemas/auth-tokens.ts +++ b/backend/src/db/schemas/auth-tokens.ts @@ -17,7 +17,7 @@ export const AuthTokensSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), userId: z.string().uuid().nullable().optional(), - orgId: z.string().uuid().nullable().optional(), + orgId: z.string().uuid().nullable().optional() }); export type TAuthTokens = z.infer; diff --git a/backend/src/db/schemas/backup-private-key.ts b/backend/src/db/schemas/backup-private-key.ts index 9b6e787b1a..5930bbd4a8 100644 --- a/backend/src/db/schemas/backup-private-key.ts +++ b/backend/src/db/schemas/backup-private-key.ts @@ -18,7 +18,7 @@ export const BackupPrivateKeySchema = z.object({ verifier: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TBackupPrivateKey = z.infer; diff --git a/backend/src/db/schemas/git-app-install-sessions.ts b/backend/src/db/schemas/git-app-install-sessions.ts index 16f62eab78..6c6db40ea4 100644 --- a/backend/src/db/schemas/git-app-install-sessions.ts +++ b/backend/src/db/schemas/git-app-install-sessions.ts @@ -13,7 +13,7 @@ export const GitAppInstallSessionsSchema = z.object({ userId: z.string().uuid().nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TGitAppInstallSessions = z.infer; diff --git a/backend/src/db/schemas/git-app-org.ts b/backend/src/db/schemas/git-app-org.ts index f5226811de..57e0d474a8 100644 --- a/backend/src/db/schemas/git-app-org.ts +++ b/backend/src/db/schemas/git-app-org.ts @@ -13,7 +13,7 @@ export const GitAppOrgSchema = z.object({ userId: z.string().uuid(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TGitAppOrg = z.infer; diff --git a/backend/src/db/schemas/identities.ts b/backend/src/db/schemas/identities.ts index b8ff6c36fe..005adf0253 100644 --- a/backend/src/db/schemas/identities.ts +++ b/backend/src/db/schemas/identities.ts @@ -12,7 +12,7 @@ export const IdentitiesSchema = z.object({ name: z.string(), authMethod: z.string().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentities = z.infer; diff --git a/backend/src/db/schemas/identity-access-tokens.ts b/backend/src/db/schemas/identity-access-tokens.ts index d36291ab9c..cbd71e5c5c 100644 --- a/backend/src/db/schemas/identity-access-tokens.ts +++ b/backend/src/db/schemas/identity-access-tokens.ts @@ -19,7 +19,7 @@ export const IdentityAccessTokensSchema = z.object({ identityUAClientSecretId: z.string().nullable().optional(), identityId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentityAccessTokens = z.infer; diff --git a/backend/src/db/schemas/identity-org-memberships.ts b/backend/src/db/schemas/identity-org-memberships.ts index c5c9a0f614..647ec7124c 100644 --- a/backend/src/db/schemas/identity-org-memberships.ts +++ b/backend/src/db/schemas/identity-org-memberships.ts @@ -14,7 +14,7 @@ export const IdentityOrgMembershipsSchema = z.object({ orgId: z.string().uuid(), createdAt: z.date(), updatedAt: z.date(), - identityId: z.string().uuid(), + identityId: z.string().uuid() }); export type TIdentityOrgMemberships = z.infer; diff --git a/backend/src/db/schemas/identity-project-memberships.ts b/backend/src/db/schemas/identity-project-memberships.ts index 9a57952a4a..866324c8b7 100644 --- a/backend/src/db/schemas/identity-project-memberships.ts +++ b/backend/src/db/schemas/identity-project-memberships.ts @@ -14,7 +14,7 @@ export const IdentityProjectMembershipsSchema = z.object({ projectId: z.string(), identityId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentityProjectMemberships = z.infer; diff --git a/backend/src/db/schemas/identity-ua-client-secrets.ts b/backend/src/db/schemas/identity-ua-client-secrets.ts index f17b1ed7fa..60f8d862f2 100644 --- a/backend/src/db/schemas/identity-ua-client-secrets.ts +++ b/backend/src/db/schemas/identity-ua-client-secrets.ts @@ -19,7 +19,7 @@ export const IdentityUaClientSecretsSchema = z.object({ isClientSecretRevoked: z.boolean().default(false), createdAt: z.date(), updatedAt: z.date(), - identityUAId: z.string().uuid(), + identityUAId: z.string().uuid() }); export type TIdentityUaClientSecrets = z.infer; diff --git a/backend/src/db/schemas/identity-universal-auths.ts b/backend/src/db/schemas/identity-universal-auths.ts index 1dbc61ea80..5a8f0c7ec5 100644 --- a/backend/src/db/schemas/identity-universal-auths.ts +++ b/backend/src/db/schemas/identity-universal-auths.ts @@ -17,7 +17,7 @@ export const IdentityUniversalAuthsSchema = z.object({ accessTokenTrustedIps: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - identityId: z.string().uuid(), + identityId: z.string().uuid() }); export type TIdentityUniversalAuths = z.infer; diff --git a/backend/src/db/schemas/incident-contacts.ts b/backend/src/db/schemas/incident-contacts.ts index c1492e0fa8..431bf05ab1 100644 --- a/backend/src/db/schemas/incident-contacts.ts +++ b/backend/src/db/schemas/incident-contacts.ts @@ -12,7 +12,7 @@ export const IncidentContactsSchema = z.object({ email: z.string(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TIncidentContacts = z.infer; diff --git a/backend/src/db/schemas/integration-auths.ts b/backend/src/db/schemas/integration-auths.ts index d2983658c9..db602c0af8 100644 --- a/backend/src/db/schemas/integration-auths.ts +++ b/backend/src/db/schemas/integration-auths.ts @@ -29,7 +29,7 @@ export const IntegrationAuthsSchema = z.object({ keyEncoding: z.string(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIntegrationAuths = z.infer; diff --git a/backend/src/db/schemas/integrations.ts b/backend/src/db/schemas/integrations.ts index b2163dc4d9..62f73d1901 100644 --- a/backend/src/db/schemas/integrations.ts +++ b/backend/src/db/schemas/integrations.ts @@ -25,9 +25,9 @@ export const IntegrationsSchema = z.object({ metadata: z.unknown().nullable().optional(), integrationAuthId: z.string().uuid(), envId: z.string().uuid(), - secretPath: z.string().default('/'), + secretPath: z.string().default("/"), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIntegrations = z.infer; diff --git a/backend/src/db/schemas/org-bots.ts b/backend/src/db/schemas/org-bots.ts index 400ab19c89..b328f1aafb 100644 --- a/backend/src/db/schemas/org-bots.ts +++ b/backend/src/db/schemas/org-bots.ts @@ -23,7 +23,7 @@ export const OrgBotsSchema = z.object({ privateKeyKeyEncoding: z.string(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TOrgBots = z.infer; diff --git a/backend/src/db/schemas/org-memberships.ts b/backend/src/db/schemas/org-memberships.ts index 932c84d004..b2fffa1173 100644 --- a/backend/src/db/schemas/org-memberships.ts +++ b/backend/src/db/schemas/org-memberships.ts @@ -10,13 +10,13 @@ import { TImmutableDBKeys } from "./models"; export const OrgMembershipsSchema = z.object({ id: z.string().uuid(), role: z.string(), - status: z.string().default('invited'), + status: z.string().default("invited"), inviteEmail: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), userId: z.string().uuid().nullable().optional(), orgId: z.string().uuid(), - roleId: z.string().uuid().nullable().optional(), + roleId: z.string().uuid().nullable().optional() }); export type TOrgMemberships = z.infer; diff --git a/backend/src/db/schemas/org-roles.ts b/backend/src/db/schemas/org-roles.ts index 9718cdb264..72b582f969 100644 --- a/backend/src/db/schemas/org-roles.ts +++ b/backend/src/db/schemas/org-roles.ts @@ -15,7 +15,7 @@ export const OrgRolesSchema = z.object({ permissions: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TOrgRoles = z.infer; diff --git a/backend/src/db/schemas/organizations.ts b/backend/src/db/schemas/organizations.ts index 539217c005..e0f70d1c03 100644 --- a/backend/src/db/schemas/organizations.ts +++ b/backend/src/db/schemas/organizations.ts @@ -13,7 +13,7 @@ export const OrganizationsSchema = z.object({ customerId: z.string().nullable().optional(), slug: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TOrganizations = z.infer; diff --git a/backend/src/db/schemas/project-bots.ts b/backend/src/db/schemas/project-bots.ts index 90ced9b3e9..c685769438 100644 --- a/backend/src/db/schemas/project-bots.ts +++ b/backend/src/db/schemas/project-bots.ts @@ -22,7 +22,7 @@ export const ProjectBotsSchema = z.object({ projectId: z.string(), senderId: z.string().uuid().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectBots = z.infer; diff --git a/backend/src/db/schemas/project-environments.ts b/backend/src/db/schemas/project-environments.ts index aa3e392c75..8b95dbba06 100644 --- a/backend/src/db/schemas/project-environments.ts +++ b/backend/src/db/schemas/project-environments.ts @@ -14,7 +14,7 @@ export const ProjectEnvironmentsSchema = z.object({ position: z.number(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectEnvironments = z.infer; diff --git a/backend/src/db/schemas/project-keys.ts b/backend/src/db/schemas/project-keys.ts index 64e33d5745..720cd79bf0 100644 --- a/backend/src/db/schemas/project-keys.ts +++ b/backend/src/db/schemas/project-keys.ts @@ -15,7 +15,7 @@ export const ProjectKeysSchema = z.object({ senderId: z.string().uuid().nullable().optional(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectKeys = z.infer; diff --git a/backend/src/db/schemas/project-memberships.ts b/backend/src/db/schemas/project-memberships.ts index c98befb38a..b9f191a84b 100644 --- a/backend/src/db/schemas/project-memberships.ts +++ b/backend/src/db/schemas/project-memberships.ts @@ -14,7 +14,7 @@ export const ProjectMembershipsSchema = z.object({ updatedAt: z.date(), userId: z.string().uuid(), projectId: z.string(), - roleId: z.string().uuid().nullable().optional(), + roleId: z.string().uuid().nullable().optional() }); export type TProjectMemberships = z.infer; diff --git a/backend/src/db/schemas/project-roles.ts b/backend/src/db/schemas/project-roles.ts index 190dd1cece..1946ab5e1b 100644 --- a/backend/src/db/schemas/project-roles.ts +++ b/backend/src/db/schemas/project-roles.ts @@ -15,7 +15,7 @@ export const ProjectRolesSchema = z.object({ permissions: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - projectId: z.string(), + projectId: z.string() }); export type TProjectRoles = z.infer; diff --git a/backend/src/db/schemas/projects.ts b/backend/src/db/schemas/projects.ts index 005e4bbde4..296fa421ed 100644 --- a/backend/src/db/schemas/projects.ts +++ b/backend/src/db/schemas/projects.ts @@ -14,7 +14,7 @@ export const ProjectsSchema = z.object({ autoCapitalization: z.boolean().default(true).nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjects = z.infer; diff --git a/backend/src/db/schemas/saml-configs.ts b/backend/src/db/schemas/saml-configs.ts index 392fb2bef7..4633384b9e 100644 --- a/backend/src/db/schemas/saml-configs.ts +++ b/backend/src/db/schemas/saml-configs.ts @@ -22,7 +22,7 @@ export const SamlConfigsSchema = z.object({ certTag: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TSamlConfigs = z.infer; diff --git a/backend/src/db/schemas/secret-approval-policies-approvers.ts b/backend/src/db/schemas/secret-approval-policies-approvers.ts index c6fb75f06c..503299d30a 100644 --- a/backend/src/db/schemas/secret-approval-policies-approvers.ts +++ b/backend/src/db/schemas/secret-approval-policies-approvers.ts @@ -12,7 +12,7 @@ export const SecretApprovalPoliciesApproversSchema = z.object({ approverId: z.string().uuid(), policyId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalPoliciesApprovers = z.infer; diff --git a/backend/src/db/schemas/secret-approval-policies.ts b/backend/src/db/schemas/secret-approval-policies.ts index ec859bb4e1..6c331f1b1f 100644 --- a/backend/src/db/schemas/secret-approval-policies.ts +++ b/backend/src/db/schemas/secret-approval-policies.ts @@ -14,7 +14,7 @@ export const SecretApprovalPoliciesSchema = z.object({ approvals: z.number().default(1), envId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalPolicies = z.infer; diff --git a/backend/src/db/schemas/secret-approval-request-secret-tags.ts b/backend/src/db/schemas/secret-approval-request-secret-tags.ts index 47e11e6a99..f5e7ba632f 100644 --- a/backend/src/db/schemas/secret-approval-request-secret-tags.ts +++ b/backend/src/db/schemas/secret-approval-request-secret-tags.ts @@ -12,7 +12,7 @@ export const SecretApprovalRequestSecretTagsSchema = z.object({ secretId: z.string().uuid(), tagId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalRequestSecretTags = z.infer; diff --git a/backend/src/db/schemas/secret-approval-requests-reviewers.ts b/backend/src/db/schemas/secret-approval-requests-reviewers.ts index 4ed9b50a18..a3657f1f97 100644 --- a/backend/src/db/schemas/secret-approval-requests-reviewers.ts +++ b/backend/src/db/schemas/secret-approval-requests-reviewers.ts @@ -13,7 +13,7 @@ export const SecretApprovalRequestsReviewersSchema = z.object({ status: z.string(), requestId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalRequestsReviewers = z.infer; diff --git a/backend/src/db/schemas/secret-approval-requests-secrets.ts b/backend/src/db/schemas/secret-approval-requests-secrets.ts index db98bda17f..810a4f2cfe 100644 --- a/backend/src/db/schemas/secret-approval-requests-secrets.ts +++ b/backend/src/db/schemas/secret-approval-requests-secrets.ts @@ -23,15 +23,15 @@ export const SecretApprovalRequestsSecretsSchema = z.object({ secretReminderNote: z.string().nullable().optional(), secretReminderRepeatDays: z.number().nullable().optional(), skipMultilineEncoding: z.boolean().default(false).nullable().optional(), - algorithm: z.string().default('aes-256-gcm'), - keyEncoding: z.string().default('utf8'), + algorithm: z.string().default("aes-256-gcm"), + keyEncoding: z.string().default("utf8"), metadata: z.unknown().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), requestId: z.string().uuid(), op: z.string(), secretId: z.string().uuid().nullable().optional(), - secretVersion: z.string().uuid().nullable().optional(), + secretVersion: z.string().uuid().nullable().optional() }); export type TSecretApprovalRequestsSecrets = z.infer; diff --git a/backend/src/db/schemas/secret-approval-requests.ts b/backend/src/db/schemas/secret-approval-requests.ts index 7d5f2f443b..590c283f59 100644 --- a/backend/src/db/schemas/secret-approval-requests.ts +++ b/backend/src/db/schemas/secret-approval-requests.ts @@ -11,14 +11,14 @@ export const SecretApprovalRequestsSchema = z.object({ id: z.string().uuid(), policyId: z.string().uuid(), hasMerged: z.boolean().default(false), - status: z.string().default('open'), + status: z.string().default("open"), conflicts: z.unknown().nullable().optional(), slug: z.string(), folderId: z.string().uuid(), statusChangeBy: z.string().uuid().nullable().optional(), committerId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalRequests = z.infer; diff --git a/backend/src/db/schemas/secret-blind-indexes.ts b/backend/src/db/schemas/secret-blind-indexes.ts index 17eacb473b..fa919babd2 100644 --- a/backend/src/db/schemas/secret-blind-indexes.ts +++ b/backend/src/db/schemas/secret-blind-indexes.ts @@ -12,11 +12,11 @@ export const SecretBlindIndexesSchema = z.object({ encryptedSaltCipherText: z.string(), saltIV: z.string(), saltTag: z.string(), - algorithm: z.string().default('aes-256-gcm'), - keyEncoding: z.string().default('utf8'), + algorithm: z.string().default("aes-256-gcm"), + keyEncoding: z.string().default("utf8"), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretBlindIndexes = z.infer; diff --git a/backend/src/db/schemas/secret-folder-versions.ts b/backend/src/db/schemas/secret-folder-versions.ts index 895f81ebce..8c550d0651 100644 --- a/backend/src/db/schemas/secret-folder-versions.ts +++ b/backend/src/db/schemas/secret-folder-versions.ts @@ -14,7 +14,7 @@ export const SecretFolderVersionsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), envId: z.string().uuid(), - folderId: z.string().uuid(), + folderId: z.string().uuid() }); export type TSecretFolderVersions = z.infer; diff --git a/backend/src/db/schemas/secret-folders.ts b/backend/src/db/schemas/secret-folders.ts index aa437c7535..648238b0a7 100644 --- a/backend/src/db/schemas/secret-folders.ts +++ b/backend/src/db/schemas/secret-folders.ts @@ -14,7 +14,7 @@ export const SecretFoldersSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), envId: z.string().uuid(), - parentId: z.string().uuid().nullable().optional(), + parentId: z.string().uuid().nullable().optional() }); export type TSecretFolders = z.infer; diff --git a/backend/src/db/schemas/secret-imports.ts b/backend/src/db/schemas/secret-imports.ts index 109d41ec2a..9c1ee905f7 100644 --- a/backend/src/db/schemas/secret-imports.ts +++ b/backend/src/db/schemas/secret-imports.ts @@ -15,7 +15,7 @@ export const SecretImportsSchema = z.object({ position: z.number(), createdAt: z.date(), updatedAt: z.date(), - folderId: z.string().uuid(), + folderId: z.string().uuid() }); export type TSecretImports = z.infer; diff --git a/backend/src/db/schemas/secret-rotation-outputs.ts b/backend/src/db/schemas/secret-rotation-outputs.ts index b98338c75e..3b594365a5 100644 --- a/backend/src/db/schemas/secret-rotation-outputs.ts +++ b/backend/src/db/schemas/secret-rotation-outputs.ts @@ -11,7 +11,7 @@ export const SecretRotationOutputsSchema = z.object({ id: z.string().uuid(), key: z.string(), secretId: z.string().uuid(), - rotationId: z.string().uuid(), + rotationId: z.string().uuid() }); export type TSecretRotationOutputs = z.infer; diff --git a/backend/src/db/schemas/secret-rotations.ts b/backend/src/db/schemas/secret-rotations.ts index 6e2bf6547b..4c65712faa 100644 --- a/backend/src/db/schemas/secret-rotations.ts +++ b/backend/src/db/schemas/secret-rotations.ts @@ -22,7 +22,7 @@ export const SecretRotationsSchema = z.object({ keyEncoding: z.string().nullable().optional(), envId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretRotations = z.infer; diff --git a/backend/src/db/schemas/secret-scanning-git-risks.ts b/backend/src/db/schemas/secret-scanning-git-risks.ts index 0951d3ba5a..85cfcd3768 100644 --- a/backend/src/db/schemas/secret-scanning-git-risks.ts +++ b/backend/src/db/schemas/secret-scanning-git-risks.ts @@ -38,7 +38,7 @@ export const SecretScanningGitRisksSchema = z.object({ status: z.string().nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretScanningGitRisks = z.infer; diff --git a/backend/src/db/schemas/secret-snapshot-folders.ts b/backend/src/db/schemas/secret-snapshot-folders.ts index 5f3b1a88c2..acf11ab0af 100644 --- a/backend/src/db/schemas/secret-snapshot-folders.ts +++ b/backend/src/db/schemas/secret-snapshot-folders.ts @@ -13,7 +13,7 @@ export const SecretSnapshotFoldersSchema = z.object({ folderVersionId: z.string().uuid(), snapshotId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshotFolders = z.infer; diff --git a/backend/src/db/schemas/secret-snapshot-secrets.ts b/backend/src/db/schemas/secret-snapshot-secrets.ts index f8a69a6955..6a83d11558 100644 --- a/backend/src/db/schemas/secret-snapshot-secrets.ts +++ b/backend/src/db/schemas/secret-snapshot-secrets.ts @@ -13,7 +13,7 @@ export const SecretSnapshotSecretsSchema = z.object({ secretVersionId: z.string().uuid(), snapshotId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshotSecrets = z.infer; diff --git a/backend/src/db/schemas/secret-snapshots.ts b/backend/src/db/schemas/secret-snapshots.ts index ef9e0b7d0d..ed255cb776 100644 --- a/backend/src/db/schemas/secret-snapshots.ts +++ b/backend/src/db/schemas/secret-snapshots.ts @@ -13,7 +13,7 @@ export const SecretSnapshotsSchema = z.object({ folderId: z.string().uuid(), parentFolderId: z.string().uuid().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshots = z.infer; diff --git a/backend/src/db/schemas/secret-tag-junction.ts b/backend/src/db/schemas/secret-tag-junction.ts index 467ef7b157..1d25574c5f 100644 --- a/backend/src/db/schemas/secret-tag-junction.ts +++ b/backend/src/db/schemas/secret-tag-junction.ts @@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const SecretTagJunctionSchema = z.object({ id: z.string().uuid(), secretsId: z.string().uuid(), - secret_tagsId: z.string().uuid(), + secret_tagsId: z.string().uuid() }); export type TSecretTagJunction = z.infer; diff --git a/backend/src/db/schemas/secret-tags.ts b/backend/src/db/schemas/secret-tags.ts index 78f03dedd1..622c29bd39 100644 --- a/backend/src/db/schemas/secret-tags.ts +++ b/backend/src/db/schemas/secret-tags.ts @@ -15,7 +15,7 @@ export const SecretTagsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), createdBy: z.string().uuid().nullable().optional(), - projectId: z.string(), + projectId: z.string() }); export type TSecretTags = z.infer; diff --git a/backend/src/db/schemas/secret-version-tag-junction.ts b/backend/src/db/schemas/secret-version-tag-junction.ts index 11b3f0032e..2c9a24fee7 100644 --- a/backend/src/db/schemas/secret-version-tag-junction.ts +++ b/backend/src/db/schemas/secret-version-tag-junction.ts @@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const SecretVersionTagJunctionSchema = z.object({ id: z.string().uuid(), secret_versionsId: z.string().uuid(), - secret_tagsId: z.string().uuid(), + secret_tagsId: z.string().uuid() }); export type TSecretVersionTagJunction = z.infer; diff --git a/backend/src/db/schemas/service-tokens.ts b/backend/src/db/schemas/service-tokens.ts index c12e284320..24720f3e4f 100644 --- a/backend/src/db/schemas/service-tokens.ts +++ b/backend/src/db/schemas/service-tokens.ts @@ -21,7 +21,7 @@ export const ServiceTokensSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), createdBy: z.string(), - projectId: z.string(), + projectId: z.string() }); export type TServiceTokens = z.infer; diff --git a/backend/src/db/schemas/super-admin.ts b/backend/src/db/schemas/super-admin.ts index f998cf3257..13bf45e7bd 100644 --- a/backend/src/db/schemas/super-admin.ts +++ b/backend/src/db/schemas/super-admin.ts @@ -12,7 +12,7 @@ export const SuperAdminSchema = z.object({ initialized: z.boolean().default(false).nullable().optional(), allowSignUp: z.boolean().default(true).nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSuperAdmin = z.infer; diff --git a/backend/src/db/schemas/trusted-ips.ts b/backend/src/db/schemas/trusted-ips.ts index c3311340da..6d9018db3d 100644 --- a/backend/src/db/schemas/trusted-ips.ts +++ b/backend/src/db/schemas/trusted-ips.ts @@ -16,7 +16,7 @@ export const TrustedIpsSchema = z.object({ comment: z.string().nullable().optional(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TTrustedIps = z.infer; diff --git a/backend/src/db/schemas/user-actions.ts b/backend/src/db/schemas/user-actions.ts index a3a07d699a..eaa03ba98d 100644 --- a/backend/src/db/schemas/user-actions.ts +++ b/backend/src/db/schemas/user-actions.ts @@ -12,7 +12,7 @@ export const UserActionsSchema = z.object({ action: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TUserActions = z.infer; diff --git a/backend/src/db/schemas/user-encryption-keys.ts b/backend/src/db/schemas/user-encryption-keys.ts index 938b93aafd..8f35b09fe9 100644 --- a/backend/src/db/schemas/user-encryption-keys.ts +++ b/backend/src/db/schemas/user-encryption-keys.ts @@ -21,7 +21,7 @@ export const UserEncryptionKeysSchema = z.object({ tag: z.string(), salt: z.string(), verifier: z.string(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TUserEncryptionKeys = z.infer; diff --git a/backend/src/db/schemas/users.ts b/backend/src/db/schemas/users.ts index b9689883d0..4a29de5100 100644 --- a/backend/src/db/schemas/users.ts +++ b/backend/src/db/schemas/users.ts @@ -19,7 +19,7 @@ export const UsersSchema = z.object({ mfaMethods: z.string().array().nullable().optional(), devices: z.unknown().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TUsers = z.infer; diff --git a/backend/src/db/schemas/webhooks.ts b/backend/src/db/schemas/webhooks.ts index 2b7e36cabe..7abfb3772f 100644 --- a/backend/src/db/schemas/webhooks.ts +++ b/backend/src/db/schemas/webhooks.ts @@ -9,7 +9,7 @@ import { TImmutableDBKeys } from "./models"; export const WebhooksSchema = z.object({ id: z.string().uuid(), - secretPath: z.string().default('/'), + secretPath: z.string().default("/"), url: z.string(), lastStatus: z.string().nullable().optional(), lastRunErrorMessage: z.string().nullable().optional(), @@ -21,7 +21,7 @@ export const WebhooksSchema = z.object({ keyEncoding: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), - envId: z.string().uuid(), + envId: z.string().uuid() }); export type TWebhooks = z.infer; diff --git a/backend/src/db/seed-data.ts b/backend/src/db/seed-data.ts index a9dedbb115..bb57d5bb4b 100644 --- a/backend/src/db/seed-data.ts +++ b/backend/src/db/seed-data.ts @@ -48,14 +48,12 @@ export const generateUserSrpKeys = async (password: string) => { await new Promise((resolve) => { client.init({ username: seedData1.email, password: seedData1.password }, () => resolve(null)); }); - const { salt, verifier } = await new Promise<{ salt: string; verifier: string }>( - (resolve, reject) => { - client.createVerifier((err, res) => { - if (err) return reject(err); - return resolve(res); - }); - } - ); + const { salt, verifier } = await new Promise<{ salt: string; verifier: string }>((resolve, reject) => { + client.createVerifier((err, res) => { + if (err) return reject(err); + return resolve(res); + }); + }); const derivedKey = await argon2.hash(password, { salt: Buffer.from(salt), memoryCost: 65536, diff --git a/backend/src/db/seeds/1-user.ts b/backend/src/db/seeds/1-user.ts index 7855ebc789..ca0042a98f 100644 --- a/backend/src/db/seeds/1-user.ts +++ b/backend/src/db/seeds/1-user.ts @@ -14,7 +14,7 @@ export async function seed(knex: Knex): Promise { const [user] = await knex(TableName.Users) .insert([ { - // @ts-ignore to calculate predefined + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.id, email: seedData1.email, superAdmin: true, @@ -48,7 +48,7 @@ export async function seed(knex: Knex): Promise { ]); await knex(TableName.AuthTokenSession).insert({ - // @ts-ignore + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.token.id, userId: seedData1.id, ip: "151.196.220.213", diff --git a/backend/src/db/seeds/2-org.ts b/backend/src/db/seeds/2-org.ts index ec7e9dd43a..a9c3ec3c77 100644 --- a/backend/src/db/seeds/2-org.ts +++ b/backend/src/db/seeds/2-org.ts @@ -14,7 +14,7 @@ export async function seed(knex: Knex): Promise { const [org] = await knex(TableName.Organization) .insert([ { - // @ts-ignore because we need that id for api calls + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.organization.id, name: "infisical", slug: "infisical", diff --git a/backend/src/db/seeds/3-project.ts b/backend/src/db/seeds/3-project.ts index 48d4df5c17..7818d58311 100644 --- a/backend/src/db/seeds/3-project.ts +++ b/backend/src/db/seeds/3-project.ts @@ -20,7 +20,7 @@ export async function seed(knex: Knex): Promise { name: seedData1.project.name, orgId: seedData1.organization.id, slug: "first-project", - // @ts-ignore pre calc id + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.project.id }) .returning("*"); @@ -45,7 +45,5 @@ export async function seed(knex: Knex): Promise { })) ) .returning("*"); - await knex(TableName.SecretFolder).insert( - envs.map(({ id }) => ({ name: "root", envId: id, parentId: null })) - ); + await knex(TableName.SecretFolder).insert(envs.map(({ id }) => ({ name: "root", envId: id, parentId: null }))); } diff --git a/backend/src/db/utils.ts b/backend/src/db/utils.ts index 51a097a4b1..68c4005963 100644 --- a/backend/src/db/utils.ts +++ b/backend/src/db/utils.ts @@ -2,12 +2,7 @@ import { Knex } from "knex"; import { TableName } from "./schemas"; -export const createJunctionTable = ( - knex: Knex, - tableName: TableName, - table1Name: TableName, - table2Name: TableName -) => +export const createJunctionTable = (knex: Knex, tableName: TableName, table1Name: TableName, table2Name: TableName) => knex.schema.createTable(tableName, (table) => { table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1 diff --git a/backend/src/ee/routes/v1/license-router.ts b/backend/src/ee/routes/v1/license-router.ts index 36c3a571df..e560fc8422 100644 --- a/backend/src/ee/routes/v1/license-router.ts +++ b/backend/src/ee/routes/v1/license-router.ts @@ -1,3 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// TODO(akhilmhdh): Fix this when licence service gets it type import { z } from "zod"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; diff --git a/backend/src/ee/routes/v1/org-role-router.ts b/backend/src/ee/routes/v1/org-role-router.ts index 79e3928802..4890c97a58 100644 --- a/backend/src/ee/routes/v1/org-role-router.ts +++ b/backend/src/ee/routes/v1/org-role-router.ts @@ -26,12 +26,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - - const role = await server.services.orgRole.createRole( - req.permission.id, - req.params.organizationId, - req.body - ); + const role = await server.services.orgRole.createRole(req.permission.id, req.params.organizationId, req.body); return { role }; } }); @@ -58,7 +53,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const role = await server.services.orgRole.updateRole( req.permission.id, req.params.organizationId, @@ -85,7 +79,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const role = await server.services.orgRole.deleteRole( req.permission.id, req.params.organizationId, @@ -114,11 +107,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - - const roles = await server.services.orgRole.listRoles( - req.permission.id, - req.params.organizationId - ); + const roles = await server.services.orgRole.listRoles(req.permission.id, req.params.organizationId); return { data: { roles } }; } }); @@ -139,7 +128,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const { permissions, membership } = await server.services.orgRole.getUserPermission( req.permission.id, req.params.organizationId diff --git a/backend/src/ee/routes/v1/project-role-router.ts b/backend/src/ee/routes/v1/project-role-router.ts index 622762bca0..86f2242e20 100644 --- a/backend/src/ee/routes/v1/project-role-router.ts +++ b/backend/src/ee/routes/v1/project-role-router.ts @@ -141,7 +141,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const { permissions, membership } = await server.services.projectRole.getUserPermission( req.permission.id, req.params.projectId diff --git a/backend/src/ee/routes/v1/saml-router.ts b/backend/src/ee/routes/v1/saml-router.ts index 96ee2408db..6ddebb388c 100644 --- a/backend/src/ee/routes/v1/saml-router.ts +++ b/backend/src/ee/routes/v1/saml-router.ts @@ -1,3 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +// All the any rules are disabled because passport typesense with fastify is really poor + import { Authenticator } from "@fastify/passport"; import fastifySession from "@fastify/session"; import { MultiSamlStrategy } from "@node-saml/passport-saml"; @@ -33,6 +41,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { new MultiSamlStrategy( { passReqToCallback: true, + // eslint-disable-next-line getSamlOptions: async (req, done) => { try { const { ssoIdentifier } = req.params; @@ -67,14 +76,15 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { } } }, + // eslint-disable-next-line async (req, profile, cb) => { try { const serverCfg = getServerCfg(); if (!profile) throw new BadRequestError({ message: "Missing profile" }); const { firstName } = profile; - const email = profile?.email ?? profile?.emailAddress as string // emailRippling is added because in Rippling the field `email` reserved - - if (!email || !firstName){ + const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved + + if (!email || !firstName) { throw new BadRequestError({ message: "Invalid request. Missing email or first name" }); } @@ -140,15 +150,11 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { handler: (req, res) => { if (req.passportUser.isUserCompleted) { return res.redirect( - `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } return res.redirect( - `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } }); diff --git a/backend/src/ee/routes/v1/secret-approval-policy-router.ts b/backend/src/ee/routes/v1/secret-approval-policy-router.ts index 49d2b95ad8..dda8dbe381 100644 --- a/backend/src/ee/routes/v1/secret-approval-policy-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-policy-router.ts @@ -111,7 +111,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - approvals: sapPubSchema.merge(z.object({approvers:z.string().array()})).array() + approvals: sapPubSchema.merge(z.object({ approvers: z.string().array() })).array() }) } }, @@ -137,7 +137,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - policy: sapPubSchema.merge(z.object({approvers:z.string().array()})).optional() + policy: sapPubSchema.merge(z.object({ approvers: z.string().array() })).optional() }) } }, diff --git a/backend/src/ee/routes/v1/secret-approval-request-router.ts b/backend/src/ee/routes/v1/secret-approval-request-router.ts index a745a9b047..f33e8b0d05 100644 --- a/backend/src/ee/routes/v1/secret-approval-request-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-request-router.ts @@ -9,10 +9,7 @@ import { SecretVersionsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { - ApprovalStatus, - RequestState -} from "@app/ee/services/secret-approval-request/secret-approval-request-types"; +import { ApprovalStatus, RequestState } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -41,9 +38,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv approvers: z.string().array(), secretPath: z.string().optional().nullable() }), - commits: z - .object({ op: z.string(), secretId: z.string().nullable().optional() }) - .array(), + commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(), environment: z.string(), reviewers: z.object({ member: z.string(), status: z.string() }).array(), approvers: z.string().array() @@ -174,11 +169,12 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv ...req.auditLogInfo, event: { type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED, + // eslint-disable-next-line metadata: { - [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: - approval.statusChangeBy as string, + [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangeBy as string, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug + // eslint-disable-next-line } as any // akhilmhdh: had to apply any to avoid ts issue with this } diff --git a/backend/src/ee/routes/v1/secret-scanning-router.ts b/backend/src/ee/routes/v1/secret-scanning-router.ts index 48898eddba..2970a43088 100644 --- a/backend/src/ee/routes/v1/secret-scanning-router.ts +++ b/backend/src/ee/routes/v1/secret-scanning-router.ts @@ -62,12 +62,11 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) = }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const appInstallationCompleted = - await server.services.secretScanning.getOrgInstallationStatus({ - actor: req.permission.type, - actorId: req.permission.id, - orgId: req.params.organizationId - }); + const appInstallationCompleted = await server.services.secretScanning.getOrgInstallationStatus({ + actor: req.permission.type, + actorId: req.permission.id, + orgId: req.params.organizationId + }); return { appInstallationCompleted }; } }); diff --git a/backend/src/ee/services/audit-log/audit-log-dal.ts b/backend/src/ee/services/audit-log/audit-log-dal.ts index ec5f6ab3d0..c1368880d7 100644 --- a/backend/src/ee/services/audit-log/audit-log-dal.ts +++ b/backend/src/ee/services/audit-log/audit-log-dal.ts @@ -22,17 +22,7 @@ export const auditLogDALFactory = (db: TDbClient) => { const auditLogOrm = ormify(db, TableName.AuditLog); const find = async ( - { - orgId, - projectId, - userAgentType, - startDate, - endDate, - limit = 20, - offset = 0, - actor, - eventType - }: TFindQuery, + { orgId, projectId, userAgentType, startDate, endDate, limit = 20, offset = 0, actor, eventType }: TFindQuery, tx?: Knex ) => { const sqlQuery = (tx || db)(TableName.AuditLog) @@ -48,10 +38,10 @@ export const auditLogDALFactory = (db: TDbClient) => { .limit(limit) .offset(offset); if (startDate) { - sqlQuery.where("createdAt", ">=", startDate); + void sqlQuery.where("createdAt", ">=", startDate); } if (endDate) { - sqlQuery.where("createdAt", "<=", endDate); + void sqlQuery.where("createdAt", "<=", endDate); } const docs = await sqlQuery; return docs; diff --git a/backend/src/ee/services/audit-log/audit-log-service.ts b/backend/src/ee/services/audit-log/audit-log-service.ts index 7f5d0007f0..c1d5c6925f 100644 --- a/backend/src/ee/services/audit-log/audit-log-service.ts +++ b/backend/src/ee/services/audit-log/audit-log-service.ts @@ -34,10 +34,7 @@ export const auditLogServiceFactory = ({ auditLogActor }: TListProjectAuditLogDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.AuditLogs - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs); const auditLogs = await auditLogDAL.find({ startDate, endDate, @@ -48,20 +45,17 @@ export const auditLogServiceFactory = ({ actor: auditLogActor, projectId }); - return auditLogs.map( - ({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({ - ...el, - event: { type: logEventType, metadata: eventMetadata }, - actor: { type: eActor, metadata: actorMetadata } - }) - ); + return auditLogs.map(({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({ + ...el, + event: { type: logEventType, metadata: eventMetadata }, + actor: { type: eActor, metadata: actorMetadata } + })); }; const createAuditLog = async (data: TCreateAuditLogDTO) => { // add all cases in which project id or org id cannot be added if (data.event.type !== EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH) { - if (!data.projectId && !data.orgId) - throw new BadRequestError({ message: "Must either project id or org id" }); + if (!data.projectId && !data.orgId) throw new BadRequestError({ message: "Must either project id or org id" }); } return auditLogQueue.pushToLog(data); }; diff --git a/backend/src/ee/services/license/licence-fns.ts b/backend/src/ee/services/license/licence-fns.ts index ca69b7d0ee..7014eac5f3 100644 --- a/backend/src/ee/services/license/licence-fns.ts +++ b/backend/src/ee/services/license/licence-fns.ts @@ -31,15 +31,11 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ secretRotation: true }); -export const setupLicenceRequestWithStore = ( - baseURL: string, - refreshUrl: string, - licenseKey: string -) => { +export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => { let token: string; const licenceReq = axios.create({ baseURL, - timeout: 35 * 1000, + timeout: 35 * 1000 // signal: AbortSignal.timeout(60 * 1000) }); @@ -47,7 +43,7 @@ export const setupLicenceRequestWithStore = ( const appCfg = getConfig(); const { data: { token: authToken } - } = await request.post( + } = await request.post<{ token: string }>( refreshUrl, {}, { @@ -75,18 +71,18 @@ export const setupLicenceRequestWithStore = ( licenceReq.interceptors.response.use( (response) => response, async (err) => { - const originalRequest = err.config; + const originalRequest = (err as AxiosError).config; // eslint-disable-next-line - if ((err as AxiosError)?.response?.status === 401 && !originalRequest._retry) { + if ((err as AxiosError)?.response?.status === 401 && !(originalRequest as any)._retry) { // eslint-disable-next-line - originalRequest._retry = true; + (originalRequest as any)._retry = true; // injected // refresh await refreshLicence(); licenceReq.defaults.headers.common.Authorization = `Bearer ${token}`; - return licenceReq(originalRequest); + return licenceReq(originalRequest!); } return Promise.reject(err); diff --git a/backend/src/ee/services/license/license-dal.ts b/backend/src/ee/services/license/license-dal.ts index 208cb6f9b5..4e70dfb5a5 100644 --- a/backend/src/ee/services/license/license-dal.ts +++ b/backend/src/ee/services/license/license-dal.ts @@ -13,7 +13,7 @@ export const licenseDALFactory = (db: TDbClient) => { .where({ status: OrgMembershipStatus.Accepted }) .andWhere((bd) => { if (orgId) { - bd.where({ orgId }); + void bd.where({ orgId }); } }) .count(); diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index 6ed9230be4..6a7073b4e5 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -1,3 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// eslint-disable @typescript-eslint/no-unsafe-assignment + +// TODO(akhilmhdh): With tony find out the api structure and fill it here + import { ForbiddenError } from "@casl/ability"; import NodeCache from "node-cache"; @@ -14,6 +20,7 @@ import { InstanceType, TAddOrgPmtMethodDTO, TAddOrgTaxIdDTO, + TCreateOrgPortalSession, TDelOrgPmtMethodDTO, TDelOrgTaxIdDTO, TFeatureSet, @@ -25,7 +32,6 @@ import { TOrgPlansTableDTO, TOrgPmtMethodsDTO, TStartOrgTrialDTO, - TCreateOrgPortalSession, TUpdateOrgBillingDetailsDTO } from "./license-types"; @@ -41,11 +47,7 @@ const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login"; const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/licence-login"; const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`; -export const licenseServiceFactory = ({ - orgDAL, - permissionService, - licenseDAL -}: TLicenseServiceFactoryDep) => { +export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => { let isValidLicense = false; let instanceType = InstanceType.OnPrem; let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures(); @@ -78,9 +80,7 @@ export const licenseServiceFactory = ({ if (token) { const { data: { currentPlan } - } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>( - "/api/license/v1/plan" - ); + } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); onPremFeatures = currentPlan; instanceType = InstanceType.EnterpriseOnPrem; logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`); @@ -92,7 +92,7 @@ export const licenseServiceFactory = ({ // else it would reach catch statement isValidLicense = true; } catch (error) { - logger.error(`init-license: encountered an error when init license [error=${error}]`); + logger.error(`init-license: encountered an error when init license [error]`, error); } }; @@ -119,7 +119,10 @@ export const licenseServiceFactory = ({ return currentPlan; } } catch (error) { - logger.error(`getPlan: encountered an error when fetching pan [orgId=${orgId}] [projectId=${projectId}] [error=${error}]`); + logger.error( + `getPlan: encountered an error when fetching pan [orgId=${orgId}] [projectId=${projectId}] [error]`, + error + ); return onPremFeatures; } return onPremFeatures; @@ -136,7 +139,7 @@ export const licenseServiceFactory = ({ if (instanceType === InstanceType.Cloud) { const { data: { customerId } - } = await licenseServerCloudApi.request.post( + } = await licenseServerCloudApi.request.post<{ customerId: string }>( "/api/license-server/v1/customers", { email, @@ -159,12 +162,9 @@ export const licenseServiceFactory = ({ const count = await licenseDAL.countOfOrgMembers(orgId); if (org?.customerId) { - await licenseServerCloudApi.request.patch( - `/api/license-server/v1/customers/${org.customerId}/cloud-plan`, - { - quantity: count - } - ); + await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, { + quantity: count + }); } featureStore.del(orgId); } else if (instanceType === InstanceType.EnterpriseOnPrem) { @@ -175,17 +175,9 @@ export const licenseServiceFactory = ({ }; // below all are api calls - const getOrgPlansTableByBillCycle = async ({ - orgId, - actor, - actorId, - billingCycle - }: TOrgPlansTableDTO) => { + const getOrgPlansTableByBillCycle = async ({ orgId, actor, actorId, billingCycle }: TOrgPlansTableDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const { data } = await licenseServerCloudApi.request.get( `/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}` ); @@ -194,24 +186,15 @@ export const licenseServiceFactory = ({ const getOrgPlan = async ({ orgId, actor, actorId, projectId }: TOrgPlanDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const plan = await getPlan(orgId, projectId); return plan; }; const startOrgTrial = async ({ orgId, actorId, actor, success_url }: TStartOrgTrialDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Billing - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -232,14 +215,8 @@ export const licenseServiceFactory = ({ const createOrganizationPortalSession = async ({ orgId, actorId, actor }: TCreateOrgPortalSession) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Billing - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -250,7 +227,7 @@ export const licenseServiceFactory = ({ const { data: { pmtMethods } - } = await licenseServerCloudApi.request.get( + } = await licenseServerCloudApi.request.get<{ pmtMethods: string[] }>( `/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods` ); @@ -262,34 +239,30 @@ export const licenseServiceFactory = ({ } = await licenseServerCloudApi.request.post( `/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`, { - success_url: appCfg.SITE_URL + "/dashboard", - cancel_url: appCfg.SITE_URL + "/dashboard" - } - ); - - return { url }; - } else { - // case: organization has payment method on file - // -> redirect to billing portal - const { - data: { url } - } = await licenseServerCloudApi.request.post( - `/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`, - { - return_url: appCfg.SITE_URL + "/dashboard" + success_url: `${appCfg.SITE_URL}/dashboard`, + cancel_url: `${appCfg.SITE_URL}/dashboard` } ); return { url }; } - } + // case: organization has payment method on file + // -> redirect to billing portal + const { + data: { url } + } = await licenseServerCloudApi.request.post( + `/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`, + { + return_url: `${appCfg.SITE_URL}/dashboard` + } + ); + + return { url }; + }; const getOrgBillingInfo = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -306,10 +279,7 @@ export const licenseServiceFactory = ({ // returns org current plan feature table const getOrgPlanTable = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -325,10 +295,7 @@ export const licenseServiceFactory = ({ const getOrgBillingDetails = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -343,18 +310,9 @@ export const licenseServiceFactory = ({ return data; }; - const updateOrgBillingDetails = async ({ - actorId, - actor, - orgId, - name, - email - }: TUpdateOrgBillingDetailsDTO) => { + const updateOrgBillingDetails = async ({ actorId, actor, orgId, name, email }: TUpdateOrgBillingDetailsDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -374,10 +332,7 @@ export const licenseServiceFactory = ({ const getOrgPmtMethods = async ({ orgId, actor, actorId }: TOrgPmtMethodsDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -394,18 +349,9 @@ export const licenseServiceFactory = ({ return pmtMethods; }; - const addOrgPmtMethods = async ({ - orgId, - actor, - actorId, - success_url, - cancel_url - }: TAddOrgPmtMethodDTO) => { + const addOrgPmtMethods = async ({ orgId, actor, actorId, success_url, cancel_url }: TAddOrgPmtMethodDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -427,10 +373,7 @@ export const licenseServiceFactory = ({ const delOrgPmtMethods = async ({ actorId, actor, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -447,10 +390,7 @@ export const licenseServiceFactory = ({ const getOrgTaxIds = async ({ orgId, actor, actorId }: TGetOrgTaxIdDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -468,10 +408,7 @@ export const licenseServiceFactory = ({ const addOrgTaxId = async ({ actorId, actor, orgId, type, value }: TAddOrgTaxIdDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -492,10 +429,7 @@ export const licenseServiceFactory = ({ const delOrgTaxId = async ({ orgId, actor, actorId, taxId }: TDelOrgTaxIdDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -512,10 +446,7 @@ export const licenseServiceFactory = ({ const getOrgTaxInvoices = async ({ actorId, actor, orgId }: TOrgInvoiceDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -526,18 +457,13 @@ export const licenseServiceFactory = ({ const { data: { invoices } - } = await licenseServerCloudApi.request.get( - `/api/license-server/v1/customers/${organization.customerId}/invoices` - ); + } = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/invoices`); return invoices; }; const getOrgLicenses = async ({ orgId, actor, actorId }: TOrgLicensesDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Billing - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); const organization = await orgDAL.findOrgById(orgId); if (!organization) { @@ -548,9 +474,7 @@ export const licenseServiceFactory = ({ const { data: { licenses } - } = await licenseServerCloudApi.request.get( - `/api/license-server/v1/customers/${organization.customerId}/licenses` - ); + } = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/licenses`); return licenses; }; diff --git a/backend/src/ee/services/permission/permission-dal.ts b/backend/src/ee/services/permission/permission-dal.ts index d2529f18bc..cc35fb04e5 100644 --- a/backend/src/ee/services/permission/permission-dal.ts +++ b/backend/src/ee/services/permission/permission-dal.ts @@ -9,11 +9,7 @@ export const permissionDALFactory = (db: TDbClient) => { const getOrgPermission = async (userId: string, orgId: string) => { try { const membership = await db(TableName.OrgMembership) - .leftJoin( - TableName.OrgRoles, - `${TableName.OrgMembership}.roleId`, - `${TableName.OrgRoles}.id` - ) + .leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .where("userId", userId) .where(`${TableName.OrgMembership}.orgId`, orgId) .select("permissions") @@ -29,11 +25,7 @@ export const permissionDALFactory = (db: TDbClient) => { const getOrgIdentityPermission = async (identityId: string, orgId: string) => { try { const membership = await db(TableName.IdentityOrgMembership) - .leftJoin( - TableName.OrgRoles, - `${TableName.IdentityOrgMembership}.roleId`, - `${TableName.OrgRoles}.id` - ) + .leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .where("identityId", identityId) .where(`${TableName.IdentityOrgMembership}.orgId`, orgId) .select(selectAllTableCols(TableName.IdentityOrgMembership)) @@ -48,11 +40,7 @@ export const permissionDALFactory = (db: TDbClient) => { const getProjectPermission = async (userId: string, projectId: string) => { try { const membership = await db(TableName.ProjectMembership) - .leftJoin( - TableName.ProjectRoles, - `${TableName.ProjectMembership}.roleId`, - `${TableName.ProjectRoles}.id` - ) + .leftJoin(TableName.ProjectRoles, `${TableName.ProjectMembership}.roleId`, `${TableName.ProjectRoles}.id`) .where("userId", userId) .where(`${TableName.ProjectMembership}.projectId`, projectId) .select(selectAllTableCols(TableName.ProjectMembership)) diff --git a/backend/src/ee/services/permission/permission-service.ts b/backend/src/ee/services/permission/permission-service.ts index 8549d00ee4..3daf1c20a9 100644 --- a/backend/src/ee/services/permission/permission-service.ts +++ b/backend/src/ee/services/permission/permission-service.ts @@ -16,12 +16,7 @@ import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal"; import { TProjectRoleDALFactory } from "@app/services/project-role/project-role-dal"; import { TServiceTokenDALFactory } from "@app/services/service-token/service-token-dal"; -import { - orgAdminPermissions, - orgMemberPermissions, - orgNoAccessPermissions, - OrgPermissionSet -} from "./org-permission"; +import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission"; import { TPermissionDALFactory } from "./permission-dal"; import { buildServiceTokenProjectPermission, @@ -188,9 +183,9 @@ export const permissionServiceFactory = ({ ? { permission: MongoAbility; membership: undefined } : { permission: MongoAbility; - membership: (T extends ActorType.USER - ? TProjectMemberships - : TIdentityProjectMemberships) & { permissions?: unknown }; + membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & { + permissions?: unknown; + }; }; const getProjectPermission = async ( @@ -214,9 +209,7 @@ export const permissionServiceFactory = ({ }; const getProjectPermissionByRole = async (role: string, projectId: string) => { - const isCustomRole = !Object.values(ProjectMembershipRole).includes( - role as ProjectMembershipRole - ); + const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole); if (isCustomRole) { const projectRole = await projectRoleDAL.findOne({ slug: role, projectId }); if (!projectRole) throw new BadRequestError({ message: "Role not found" }); diff --git a/backend/src/ee/services/permission/project-permission.ts b/backend/src/ee/services/permission/project-permission.ts index f3fb67705d..5245c26e47 100644 --- a/backend/src/ee/services/permission/project-permission.ts +++ b/backend/src/ee/services/permission/project-permission.ts @@ -239,17 +239,29 @@ export const buildServiceTokenProjectPermission = ( const { can, build } = new AbilityBuilder>(createMongoAbility); scopes.forEach(({ secretPath, environment }) => { if (canWrite) { - // TODO: @Akhi - // @ts-expect-error type - can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); - // @ts-expect-error type - can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); - // @ts-expect-error type - can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets, {secretPath: { $glob: secretPath }, environment }); + // TODO: @Akhi + // @ts-expect-error type + can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); + // @ts-expect-error type + can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); + // @ts-expect-error type + can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); } if (canRead) { - // @ts-expect-error type - can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); + // @ts-expect-error type + can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); } }); @@ -258,6 +270,8 @@ export const buildServiceTokenProjectPermission = ( export const projectNoAccessPermissions = buildNoAccessProjectPermission(); +/* eslint-disable */ + /** * Extracts and formats permissions from a CASL Ability object or a raw permission set. * @param ability @@ -287,3 +301,5 @@ export const isAtLeastAsPrivilegedWorkspace = ( return set1.size >= set2.size; }; + +/* eslint-enable */ diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index ad6a34a379..9da2dd1222 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -38,10 +38,7 @@ import { type TSamlConfigServiceFactoryDep = { samlConfigDAL: TSamlConfigDALFactory; userDAL: Pick; - orgDAL: Pick< - TOrgDALFactory, - "createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" - >; + orgDAL: Pick; orgBotDAL: Pick; permissionService: Pick; licenseService: Pick; @@ -68,10 +65,7 @@ export const samlConfigServiceFactory = ({ authProvider }: TCreateSamlCfgDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Sso - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso); const plan = await licenseService.getPlan(orgId); if (!plan.samlSSO) @@ -128,16 +122,8 @@ export const samlConfigServiceFactory = ({ keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding }); - const { - ciphertext: encryptedEntryPoint, - iv: entryPointIV, - tag: entryPointTag - } = encryptSymmetric(entryPoint, key); - const { - ciphertext: encryptedIssuer, - iv: issuerIV, - tag: issuerTag - } = encryptSymmetric(issuer, key); + const { ciphertext: encryptedEntryPoint, iv: entryPointIV, tag: entryPointTag } = encryptSymmetric(entryPoint, key); + const { ciphertext: encryptedIssuer, iv: issuerIV, tag: issuerTag } = encryptSymmetric(issuer, key); const { ciphertext: encryptedCert, iv: certIV, tag: certTag } = encryptSymmetric(cert, key); const samlConfig = await samlConfigDAL.create({ @@ -168,10 +154,7 @@ export const samlConfigServiceFactory = ({ authProvider }: TUpdateSamlCfgDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Sso - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso); const plan = await licenseService.getPlan(orgId); if (!plan.samlSSO) throw new BadRequestError({ @@ -181,8 +164,7 @@ export const samlConfigServiceFactory = ({ const updateQuery: TSamlConfigsUpdate = { authProvider, isActive }; const orgBot = await orgBotDAL.findOne({ orgId }); - if (!orgBot) - throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" }); + if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" }); const key = infisicalSymmetricDecrypt({ ciphertext: orgBot.encryptedSymmetricKey, iv: orgBot.symmetricKeyIV, @@ -201,11 +183,7 @@ export const samlConfigServiceFactory = ({ updateQuery.entryPointTag = entryPointTag; } if (issuer) { - const { - ciphertext: encryptedIssuer, - iv: issuerIV, - tag: issuerTag - } = encryptSymmetric(issuer, key); + const { ciphertext: encryptedIssuer, iv: issuerIV, tag: issuerTag } = encryptSymmetric(issuer, key); updateQuery.encryptedIssuer = encryptedIssuer; updateQuery.issuerIV = issuerIV; updateQuery.issuerTag = issuerTag; @@ -239,9 +217,9 @@ export const samlConfigServiceFactory = ({ "64f23239a5d4ed17f1e544c4": "9256337f-e3da-43d7-8266-39c9276e8426", "65348e49db355e6e4782571f": "b8a227c7-843e-410e-8982-b4976a599b69", "657a219fc8a80c2eff97eb38": "fcab1573-ae7f-4fcf-9645-646207acf035" - }; + }; - const id = UUIDToMongoId[dto.id] ?? dto.id + const id = UUIDToMongoId[dto.id] ?? dto.id; ssoConfig = await samlConfigDAL.findById(id); } @@ -249,15 +227,8 @@ export const samlConfigServiceFactory = ({ // when dto is type id means it's internally used if (dto.type === "org") { - const { permission } = await permissionService.getOrgPermission( - dto.actor, - dto.actorId, - ssoConfig!.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Sso - ); + const { permission } = await permissionService.getOrgPermission(dto.actor, dto.actorId, ssoConfig.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso); } const { entryPointTag, @@ -272,8 +243,7 @@ export const samlConfigServiceFactory = ({ } = ssoConfig; const orgBot = await orgBotDAL.findOne({ orgId: ssoConfig.orgId }); - if (!orgBot) - throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" }); + if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" }); const key = infisicalSymmetricDecrypt({ ciphertext: orgBot.encryptedSymmetricKey, iv: orgBot.symmetricKeyIV, @@ -330,8 +300,7 @@ export const samlConfigServiceFactory = ({ const appCfg = getConfig(); let user = await userDAL.findUserByEmail(email); const isSamlSignUpDisabled = !isSignupAllowed && !user; - if (isSamlSignUpDisabled) - throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" }); + if (isSamlSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" }); const organization = await orgDAL.findOrgById(orgId); if (!organization) throw new BadRequestError({ message: "Org not found" }); @@ -400,7 +369,7 @@ export const samlConfigServiceFactory = ({ isUserCompleted, ...(relayState ? { - callbackPort: JSON.parse(relayState).callbackPort as string + callbackPort: (JSON.parse(relayState) as { callbackPort: string }).callbackPort } : {}) }, diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-approver-dal.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-approver-dal.ts index cee303436d..f324394994 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-approver-dal.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-approver-dal.ts @@ -2,9 +2,7 @@ import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; import { ormify } from "@app/lib/knex"; -export type TSecretApprovalPolicyApproverDALFactory = ReturnType< - typeof secretApprovalPolicyApproverDALFactory ->; +export type TSecretApprovalPolicyApproverDALFactory = ReturnType; export const secretApprovalPolicyApproverDALFactory = (db: TDbClient) => { const sapApproverOrm = ormify(db, TableName.SecretApprovalPolicyApprover); diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts index ea895262d5..eec3d9a1d1 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts @@ -3,13 +3,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; import { TableName, TSecretApprovalPolicies } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { - buildFindFilter, - mergeOneToManyRelation, - ormify, - selectAllTableCols, - TFindFilter -} from "@app/lib/knex"; +import { buildFindFilter, mergeOneToManyRelation, ormify, selectAllTableCols, TFindFilter } from "@app/lib/knex"; export type TSecretApprovalPolicyDALFactory = ReturnType; @@ -18,12 +12,9 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => { const sapFindQuery = (tx: Knex, filter: TFindFilter) => tx(TableName.SecretApprovalPolicy) + // eslint-disable-next-line .where(buildFindFilter(filter)) - .join( - TableName.Environment, - `${TableName.SecretApprovalPolicy}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretApprovalPolicy}.envId`, `${TableName.Environment}.id`) .join( TableName.SecretApprovalPolicyApprover, `${TableName.SecretApprovalPolicy}.id`, @@ -59,10 +50,7 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => { } }; - const find = async ( - filter: TFindFilter, - tx?: Knex - ) => { + const find = async (filter: TFindFilter, tx?: Knex) => { try { const docs = await sapFindQuery(tx || db, filter); const formatedDoc = mergeOneToManyRelation( diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts index 078d688c58..b5688545ca 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts @@ -2,10 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability"; import picomatch from "picomatch"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { containsGlobPatterns } from "@app/lib/picomatch"; import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal"; @@ -34,9 +31,7 @@ type TSecretApprovalPolicyServiceFactoryDep = { projectMembershipDAL: Pick; }; -export type TSecretApprovalPolicyServiceFactory = ReturnType< - typeof secretApprovalPolicyServiceFactory ->; +export type TSecretApprovalPolicyServiceFactory = ReturnType; export const secretApprovalPolicyServiceFactory = ({ secretApprovalPolicyDAL, @@ -105,18 +100,10 @@ export const secretApprovalPolicyServiceFactory = ({ secretPolicyId }: TUpdateSapDTO) => { const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId); - if (!secretApprovalPolicy) - throw new BadRequestError({ message: "Secret approval policy not found" }); + if (!secretApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - secretApprovalPolicy.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.SecretApproval - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, secretApprovalPolicy.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => { const doc = await secretApprovalPolicyDAL.updateById( @@ -162,11 +149,7 @@ export const secretApprovalPolicyServiceFactory = ({ const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId); if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - sapPolicy.projectId - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, sapPolicy.projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Delete, ProjectPermissionSub.SecretApproval @@ -178,20 +161,13 @@ export const secretApprovalPolicyServiceFactory = ({ const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, projectId }: TListSapDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretApproval - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); const sapPolicies = await secretApprovalPolicyDAL.find({ projectId }); return sapPolicies; }; - const getSecretApprovalPolicy = async ( - projectId: string, - environment: string, - secretPath: string - ) => { + const getSecretApprovalPolicy = async (projectId: string, environment: string, secretPath: string) => { const env = await projectEnvDAL.findOne({ slug: environment, projectId }); if (!env) throw new BadRequestError({ message: "Environment not found" }); @@ -199,14 +175,11 @@ export const secretApprovalPolicyServiceFactory = ({ if (!policies.length) return; // this will filter policies either without scoped to secret path or the one that matches with secret path const policiesFilteredByPath = policies.filter( - ({ secretPath: policyPath }) => - !policyPath || picomatch.isMatch(secretPath, policyPath, { strictSlashes: false }) + ({ secretPath: policyPath }) => !policyPath || picomatch.isMatch(secretPath, policyPath, { strictSlashes: false }) ); // now sort by priority. exact secret path gets first match followed by glob followed by just env scoped // if that is tie get by first createdAt - const policiesByPriority = policiesFilteredByPath.sort( - (a, b) => getPolicyScore(b) - getPolicyScore(a) - ); + const policiesByPriority = policiesFilteredByPath.sort((a, b) => getPolicyScore(b) - getPolicyScore(a)); const finalPolicy = policiesByPriority.shift(); return finalPolicy; }; diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts index cda07eff98..05fe1b8f8b 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts @@ -1,15 +1,14 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { SecretApprovalRequestsSchema, TableName, TSecretApprovalRequests } from "@app/db/schemas"; -import { DatabaseError } from "@app/lib/errors"; import { - ormify, - selectAllTableCols, - sqlNestRelationships, - stripUndefinedInWhere, - TFindFilter -} from "@app/lib/knex"; + SecretApprovalRequestsSchema, + TableName, + TSecretApprovalRequests, + TSecretApprovalRequestsSecrets +} from "@app/db/schemas"; +import { DatabaseError } from "@app/lib/errors"; +import { ormify, selectAllTableCols, sqlNestRelationships, stripUndefinedInWhere, TFindFilter } from "@app/lib/knex"; import { RequestState } from "./secret-approval-request-types"; @@ -31,11 +30,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { const findQuery = (filter: TFindFilter, tx: Knex) => tx(TableName.SecretApprovalRequest) .where(filter) - .join( - TableName.SecretFolder, - `${TableName.SecretApprovalRequest}.folderId`, - `${TableName.SecretFolder}.id` - ) + .join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`) .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .join( TableName.SecretApprovalPolicy, @@ -87,8 +82,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { { key: "reviewerMemberId", label: "reviewers" as const, - mapper: ({ reviewerMemberId: member, reviewerStatus: status }) => - member ? { member, status } : undefined + mapper: ({ reviewerMemberId: member, reviewerStatus: status }) => (member ? { member, status } : undefined) }, { key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId } ] @@ -109,26 +103,19 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { .with( "temp", (tx || db)(TableName.SecretApprovalRequest) - .join( - TableName.SecretFolder, - `${TableName.SecretApprovalRequest}.folderId`, - `${TableName.SecretFolder}.id` - ) - .join( - TableName.Environment, - `${TableName.SecretFolder}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .join( TableName.SecretApprovalPolicyApprover, `${TableName.SecretApprovalRequest}.policyId`, `${TableName.SecretApprovalPolicyApprover}.policyId` ) .where({ projectId }) - .andWhere((bd) => - bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .andWhere( + (bd) => + void bd + .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) + .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) ) .select("status", `${TableName.SecretApprovalRequest}.id`) .groupBy(`${TableName.SecretApprovalRequest}.id`, "status") @@ -141,11 +128,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { return { open: parseInt( - (docs.find(({ status }) => status === RequestState.Open)?.count as string) || "0", + (docs.find(({ status }) => status === RequestState.Open) as { count: string })?.count || "0", 10 ), closed: parseInt( - (docs.find(({ status }) => status === RequestState.Closed)?.count as string) || "0", + (docs.find(({ status }) => status === RequestState.Closed) as { count: string })?.count || "0", 10 ) }; @@ -155,31 +142,15 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { }; const findByProjectId = async ( - { - status, - limit = 20, - offset = 0, - projectId, - committer, - environment, - membershipId - }: TFindQueryFilter, + { status, limit = 20, offset = 0, projectId, committer, environment, membershipId }: TFindQueryFilter, tx?: Knex ) => { try { // akhilmhdh: If ever u wanted a 1 to so many relationship connected with pagination // this is the place u wanna look at. const query = (tx || db)(TableName.SecretApprovalRequest) - .join( - TableName.SecretFolder, - `${TableName.SecretApprovalRequest}.folderId`, - `${TableName.SecretFolder}.id` - ) - .join( - TableName.Environment, - `${TableName.SecretFolder}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .join( TableName.SecretApprovalPolicy, `${TableName.SecretApprovalRequest}.policyId`, @@ -195,7 +166,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { `${TableName.SecretApprovalRequest}.id`, `${TableName.SecretApprovalRequestReviewer}.requestId` ) - .leftJoin( + .leftJoin( TableName.SecretApprovalRequestSecret, `${TableName.SecretApprovalRequestSecret}.requestId`, `${TableName.SecretApprovalRequest}.id` @@ -208,10 +179,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { committerId: committer }) ) - .andWhere((bd) => - bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .andWhere( + (bd) => + void bd + .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) + .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) ) .select(selectAllTableCols(TableName.SecretApprovalRequest)) .select( @@ -257,8 +229,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { { key: "reviewerMemberId", label: "reviewers" as const, - mapper: ({ reviewerMemberId: member, reviewerStatus: s }) => - member ? { member, status: s } : undefined + mapper: ({ reviewerMemberId: member, reviewerStatus: s }) => (member ? { member, status: s } : undefined) }, { key: "approverId", diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-reviewer-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-reviewer-dal.ts index a2a93f2582..13478f38d7 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-reviewer-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-reviewer-dal.ts @@ -2,9 +2,7 @@ import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; import { ormify } from "@app/lib/knex"; -export type TSecretApprovalRequestReviewerDALFactory = ReturnType< - typeof secretApprovalRequestReviewerDALFactory ->; +export type TSecretApprovalRequestReviewerDALFactory = ReturnType; export const secretApprovalRequestReviewerDALFactory = (db: TDbClient) => { const secretApprovalRequestReviewerOrm = ormify(db, TableName.SecretApprovalRequestReviewer); diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts index a0d25ae650..9b4742255f 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts @@ -1,13 +1,11 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { SecretApprovalRequestsSecretsSchema, TableName } from "@app/db/schemas"; +import { SecretApprovalRequestsSecretsSchema, TableName, TSecretTags } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; -export type TSecretApprovalRequestSecretDALFactory = ReturnType< - typeof secretApprovalRequestSecretDALFactory ->; +export type TSecretApprovalRequestSecretDALFactory = ReturnType; export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { const secretApprovalRequestSecretOrm = ormify(db, TableName.SecretApprovalRequestSecret); @@ -25,16 +23,8 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { `${TableName.SecretApprovalRequestSecret}.id`, `${TableName.SecretApprovalRequestSecretTag}.secretId` ) - .leftJoin( - TableName.SecretTag, - `${TableName.SecretApprovalRequestSecretTag}.tagId`, - `${TableName.SecretTag}.id` - ) - .leftJoin( - TableName.Secret, - `${TableName.SecretApprovalRequestSecret}.secretId`, - `${TableName.Secret}.id` - ) + .leftJoin(TableName.SecretTag, `${TableName.SecretApprovalRequestSecretTag}.tagId`, `${TableName.SecretTag}.id`) + .leftJoin(TableName.Secret, `${TableName.SecretApprovalRequestSecret}.secretId`, `${TableName.Secret}.id`) .leftJoin( TableName.SecretVersion, `${TableName.SecretVersion}.id`, @@ -45,7 +35,7 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { `${TableName.SecretVersionTag}.${TableName.SecretVersion}Id`, `${TableName.SecretVersion}.id` ) - .leftJoin( + .leftJoin( db.ref(TableName.SecretTag).as("secVerTag"), `${TableName.SecretVersionTag}.${TableName.SecretTag}Id`, db.ref("id").withSchema("secVerTag") @@ -75,37 +65,24 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { db.ref("secretValueCiphertext").withSchema(TableName.Secret).as("orgSecValueCiphertext"), db.ref("secretCommentIV").withSchema(TableName.Secret).as("orgSecCommentIV"), db.ref("secretCommentTag").withSchema(TableName.Secret).as("orgSecCommentTag"), - db - .ref("secretCommentCiphertext") - .withSchema(TableName.Secret) - .as("orgSecCommentCiphertext") + db.ref("secretCommentCiphertext").withSchema(TableName.Secret).as("orgSecCommentCiphertext") ) .select( db.ref("version").withSchema(TableName.SecretVersion).as("secVerVersion"), db.ref("secretKeyIV").withSchema(TableName.SecretVersion).as("secVerKeyIV"), db.ref("secretKeyTag").withSchema(TableName.SecretVersion).as("secVerKeyTag"), - db - .ref("secretKeyCiphertext") - .withSchema(TableName.SecretVersion) - .as("secVerKeyCiphertext"), + db.ref("secretKeyCiphertext").withSchema(TableName.SecretVersion).as("secVerKeyCiphertext"), db.ref("secretValueIV").withSchema(TableName.SecretVersion).as("secVerValueIV"), db.ref("secretValueTag").withSchema(TableName.SecretVersion).as("secVerValueTag"), - db - .ref("secretValueCiphertext") - .withSchema(TableName.SecretVersion) - .as("secVerValueCiphertext"), + db.ref("secretValueCiphertext").withSchema(TableName.SecretVersion).as("secVerValueCiphertext"), db.ref("secretCommentIV").withSchema(TableName.SecretVersion).as("secVerCommentIV"), db.ref("secretCommentTag").withSchema(TableName.SecretVersion).as("secVerCommentTag"), - db - .ref("secretCommentCiphertext") - .withSchema(TableName.SecretVersion) - .as("secVerCommentCiphertext") + db.ref("secretCommentCiphertext").withSchema(TableName.SecretVersion).as("secVerCommentCiphertext") ); const formatedDoc = sqlNestRelationships({ data: doc, key: "id", - parentMapper: (data) => - SecretApprovalRequestsSecretsSchema.omit({ secretVersion: true }).parse(data), + parentMapper: (data) => SecretApprovalRequestsSecretsSchema.omit({ secretVersion: true }).parse(data), childrenMapper: [ { key: "tagJnId", @@ -186,15 +163,14 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { { key: "secVerTagId", label: "tags" as const, - mapper: ({ - secVerTagId: id, - secVerTagName: name, - secVerTagSlug: slug, - secVerTagColor: color - }) => ({ + mapper: ({ secVerTagId: id, secVerTagName: name, secVerTagSlug: slug, secVerTagColor: color }) => ({ + // eslint-disable-next-line id, + // eslint-disable-next-line name, + // eslint-disable-next-line slug, + // eslint-disable-next-line color }) } diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts index 81be863047..d1ecd51edf 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -42,10 +42,7 @@ type TSecretApprovalRequestServiceFactoryDep = { secretApprovalRequestDAL: TSecretApprovalRequestDALFactory; secretApprovalRequestSecretDAL: TSecretApprovalRequestSecretDALFactory; secretApprovalRequestReviewerDAL: TSecretApprovalRequestReviewerDALFactory; - folderDAL: Pick< - TSecretFolderDALFactory, - "findBySecretPath" | "findById" | "findSecretPathByFolderIds" - >; + folderDAL: Pick; secretTagDAL: Pick; secretBlindIndexDAL: Pick; snapshotService: Pick; @@ -61,9 +58,7 @@ type TSecretApprovalRequestServiceFactoryDep = { secretQueueService: Pick; }; -export type TSecretApprovalRequestServiceFactory = ReturnType< - typeof secretApprovalRequestServiceFactory ->; +export type TSecretApprovalRequestServiceFactory = ReturnType; export const secretApprovalRequestServiceFactory = ({ secretApprovalRequestDAL, @@ -79,14 +74,9 @@ export const secretApprovalRequestServiceFactory = ({ secretQueueService }: TSecretApprovalRequestServiceFactoryDep) => { const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => { - if (actor === ActorType.SERVICE) - throw new BadRequestError({ message: "Cannot use service token" }); + if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); - const { membership } = await permissionService.getProjectPermission( - actor as ActorType.USER, - actorId, - projectId - ); + const { membership } = await permissionService.getProjectPermission(actor as ActorType.USER, actorId, projectId); const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id); return count; @@ -102,8 +92,7 @@ export const secretApprovalRequestServiceFactory = ({ limit, offset }: TListApprovalsDTO) => { - if (actor === ActorType.SERVICE) - throw new BadRequestError({ message: "Cannot use service token" }); + if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId); const approvals = await secretApprovalRequestDAL.findByProjectId({ @@ -119,12 +108,10 @@ export const secretApprovalRequestServiceFactory = ({ }; const getSecretApprovalDetails = async ({ actor, actorId, id }: TSecretApprovalDetailsDTO) => { - if (actor === ActorType.SERVICE) - throw new BadRequestError({ message: "Cannot use service token" }); + if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); const secretApprovalRequest = await secretApprovalRequestDAL.findById(id); - if (!secretApprovalRequest) - throw new BadRequestError({ message: "Secret approval request not found" }); + if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); const { policy } = secretApprovalRequest; const { membership } = await permissionService.getProjectPermission( @@ -149,8 +136,7 @@ export const secretApprovalRequestServiceFactory = ({ const reviewApproval = async ({ approvalId, actor, status, actorId }: TReviewRequestDTO) => { const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); - if (!secretApprovalRequest) - throw new BadRequestError({ message: "Secret approval request not found" }); + if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy } = secretApprovalRequest; @@ -191,8 +177,7 @@ export const secretApprovalRequestServiceFactory = ({ const updateApprovalStatus = async ({ actorId, status, approvalId, actor }: TStatusChangeDTO) => { const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); - if (!secretApprovalRequest) - throw new BadRequestError({ message: "Secret approval request not found" }); + if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy } = secretApprovalRequest; @@ -209,8 +194,7 @@ export const secretApprovalRequestServiceFactory = ({ throw new UnauthorizedError({ message: "User has no access" }); } - if (secretApprovalRequest.hasMerged) - throw new BadRequestError({ message: "Approval request has been merged" }); + if (secretApprovalRequest.hasMerged) throw new BadRequestError({ message: "Approval request has been merged" }); if (secretApprovalRequest.status === RequestState.Closed && status === RequestState.Closed) throw new BadRequestError({ message: "Approval request is already closed" }); if (secretApprovalRequest.status === RequestState.Open && status === RequestState.Open) @@ -223,22 +207,13 @@ export const secretApprovalRequestServiceFactory = ({ return { ...secretApprovalRequest, ...updatedRequest }; }; - const mergeSecretApprovalRequest = async ({ - approvalId, - actor, - actorId - }: TMergeSecretApprovalRequestDTO) => { + const mergeSecretApprovalRequest = async ({ approvalId, actor, actorId }: TMergeSecretApprovalRequestDTO) => { const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); - if (!secretApprovalRequest) - throw new BadRequestError({ message: "Secret approval request not found" }); + if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy, folderId, projectId } = secretApprovalRequest; - const { membership } = await permissionService.getProjectPermission( - ActorType.USER, - actorId, - projectId - ); + const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId); if ( membership.role !== ProjectMembershipRole.Admin && secretApprovalRequest.committerId !== membership.id && @@ -256,28 +231,24 @@ export const secretApprovalRequestServiceFactory = ({ (approverId) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED ).length; - if (!hasMinApproval) - throw new BadRequestError({ message: "Doesn't have minimum approvals needed" }); - const secretApprovalSecrets = await secretApprovalRequestSecretDAL.findByRequestId( - secretApprovalRequest.id - ); + if (!hasMinApproval) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" }); + const secretApprovalSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id); if (!secretApprovalSecrets) throw new BadRequestError({ message: "No secrets found" }); const conflicts: Array<{ secretId: string; op: CommitType }> = []; let secretCreationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Create); if (secretCreationCommits.length) { - const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = - await secretService.fnSecretBlindIndexCheckV2({ - folderId, - inputSecrets: secretCreationCommits.map(({ secretBlindIndex }) => { - if (!secretBlindIndex) { - throw new BadRequestError({ - message: "Missing secret blind index" - }); - } - return { secretBlindIndex }; - }) - }); + const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = await secretService.fnSecretBlindIndexCheckV2({ + folderId, + inputSecrets: secretCreationCommits.map(({ secretBlindIndex }) => { + if (!secretBlindIndex) { + throw new BadRequestError({ + message: "Missing secret blind index" + }); + } + return { secretBlindIndex }; + }) + }); secretCreationCommits .filter(({ secretBlindIndex }) => conflictGroupByBlindIndex[secretBlindIndex || ""]) .forEach((el) => { @@ -290,23 +261,19 @@ export const secretApprovalRequestServiceFactory = ({ let secretUpdationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Update); if (secretUpdationCommits.length) { - const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = - await secretService.fnSecretBlindIndexCheckV2({ - folderId, - inputSecrets: secretUpdationCommits - .filter( - ({ secretBlindIndex, secret }) => - secret && secret.secretBlindIndex !== secretBlindIndex - ) - .map(({ secretBlindIndex }) => { - if (!secretBlindIndex) { - throw new BadRequestError({ - message: "Missing secret blind index" - }); - } - return { secretBlindIndex }; - }) - }); + const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = await secretService.fnSecretBlindIndexCheckV2({ + folderId, + inputSecrets: secretUpdationCommits + .filter(({ secretBlindIndex, secret }) => secret && secret.secretBlindIndex !== secretBlindIndex) + .map(({ secretBlindIndex }) => { + if (!secretBlindIndex) { + throw new BadRequestError({ + message: "Missing secret blind index" + }); + } + return { secretBlindIndex }; + }) + }); secretUpdationCommits .filter( ({ secretBlindIndex, secretId }) => @@ -318,14 +285,11 @@ export const secretApprovalRequestServiceFactory = ({ secretUpdationCommits = secretUpdationCommits.filter( ({ secretBlindIndex, secretId }) => - Boolean(secretId) && - (secretBlindIndex ? !conflictGroupByBlindIndex[secretBlindIndex] : true) + Boolean(secretId) && (secretBlindIndex ? !conflictGroupByBlindIndex[secretBlindIndex] : true) ); } - const secretDeletionCommits = secretApprovalSecrets.filter( - ({ op }) => op === CommitType.Delete - ); + const secretDeletionCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Delete); const mergeStatus = await secretApprovalRequestDAL.transaction(async (tx) => { const newSecrets = secretCreationCommits.length @@ -442,27 +406,20 @@ export const secretApprovalRequestServiceFactory = ({ secretPath, environment }: TGenerateSecretApprovalRequestDTO) => { - if (actor === ActorType.SERVICE) - throw new BadRequestError({ message: "Cannot use service token" }); + if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); - const { permission, membership } = await permissionService.getProjectPermission( - actor, - actorId, - projectId - ); + const { permission, membership } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Read, subject(ProjectPermissionSub.Secrets, { environment, secretPath }) ); const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath); - if (!folder) - throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" }); + if (!folder) throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" }); const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); const commits: Omit[] = []; const commitTagIds: Record = {}; @@ -496,38 +453,28 @@ export const secretApprovalRequestServiceFactory = ({ // get all blind index // Find all those secrets // if not throw not found - const { keyName2BlindIndex, secrets: secretsToBeUpdated } = - await secretService.fnSecretBlindIndexCheck({ - inputSecrets: updatedSecrets, - folderId, - isNew: false, - blindIndexCfg - }); + const { keyName2BlindIndex, secrets: secretsToBeUpdated } = await secretService.fnSecretBlindIndexCheck({ + inputSecrets: updatedSecrets, + folderId, + isNew: false, + blindIndexCfg + }); // now find any secret that needs to update its name // same process as above - const nameUpdatedSecrets = updatedSecrets.filter(({ newSecretName }) => - Boolean(newSecretName) - ); - const { keyName2BlindIndex: newKeyName2BlindIndex } = - await secretService.fnSecretBlindIndexCheck({ - inputSecrets: nameUpdatedSecrets, - folderId, - isNew: true, - blindIndexCfg - }); + const nameUpdatedSecrets = updatedSecrets.filter(({ newSecretName }) => Boolean(newSecretName)); + const { keyName2BlindIndex: newKeyName2BlindIndex } = await secretService.fnSecretBlindIndexCheck({ + inputSecrets: nameUpdatedSecrets, + folderId, + isNew: true, + blindIndexCfg + }); - const secsGroupedByBlindIndex = groupBy( - secretsToBeUpdated, - (el) => el.secretBlindIndex as string - ); + const secsGroupedByBlindIndex = groupBy(secretsToBeUpdated, (el) => el.secretBlindIndex as string); const updatedSecretIds = updatedSecrets.map( (el) => secsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id ); - const latestSecretVersions = await secretVersionDAL.findLatestVersionMany( - folderId, - updatedSecretIds - ); + const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(folderId, updatedSecretIds); commits.push( ...updatedSecrets.map(({ newSecretName, secretName, tagIds, ...el }) => { const secretId = secsGroupedByBlindIndex[keyName2BlindIndex[secretName]][0].id; @@ -562,17 +509,13 @@ export const secretApprovalRequestServiceFactory = ({ blindIndexCfg }); const secretsGroupedByBlindIndex = groupBy(secrets, (i) => { - if (!i.secretBlindIndex) - throw new BadRequestError({ message: "Missing secret blind index" }); + if (!i.secretBlindIndex) throw new BadRequestError({ message: "Missing secret blind index" }); return i.secretBlindIndex; }); const deletedSecretIds = deletedSecrets.map( (el) => secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id ); - const latestSecretVersions = await secretVersionDAL.findLatestVersionMany( - folderId, - deletedSecretIds - ); + const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(folderId, deletedSecretIds); commits.push( ...deletedSecrets.map((el) => { const secretId = secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id; diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-types.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-types.ts index c010277d5b..008b977e6e 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-types.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-types.ts @@ -1,8 +1,4 @@ -import { - TImmutableDBKeys, - TSecretApprovalPolicies, - TSecretApprovalRequestsSecrets -} from "@app/db/schemas"; +import { TImmutableDBKeys, TSecretApprovalPolicies, TSecretApprovalRequestsSecrets } from "@app/db/schemas"; import { TProjectPermission } from "@app/lib/types"; export enum CommitType { @@ -24,14 +20,7 @@ export enum ApprovalStatus { type TApprovalCreateSecret = Omit< TSecretApprovalRequestsSecrets, - | TImmutableDBKeys - | "version" - | "algorithm" - | "keyEncoding" - | "requestId" - | "op" - | "secretVersion" - | "secretBlindIndex" + TImmutableDBKeys | "version" | "algorithm" | "keyEncoding" | "requestId" | "op" | "secretVersion" | "secretBlindIndex" > & { secretName: string; tagIds?: string[]; diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-dal.ts b/backend/src/ee/services/secret-rotation/secret-rotation-dal.ts index d1504e3d70..7feafdc6be 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-dal.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-dal.ts @@ -14,21 +14,13 @@ export const secretRotationDALFactory = (db: TDbClient) => { const findQuery = (filter: TFindFilter, tx: Knex) => tx(TableName.SecretRotation) .where(filter) - .join( - TableName.Environment, - `${TableName.SecretRotation}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretRotation}.envId`, `${TableName.Environment}.id`) .leftJoin( TableName.SecretRotationOutput, `${TableName.SecretRotation}.id`, `${TableName.SecretRotationOutput}.rotationId` ) - .join( - TableName.Secret, - `${TableName.SecretRotationOutput}.secretId`, - `${TableName.Secret}.id` - ) + .join(TableName.Secret, `${TableName.SecretRotationOutput}.secretId`, `${TableName.Secret}.id`) .select(selectAllTableCols(TableName.SecretRotation)) .select(tx.ref("name").withSchema(TableName.Environment).as("envName")) .select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug")) @@ -102,11 +94,7 @@ export const secretRotationDALFactory = (db: TDbClient) => { const findById = async (id: string, tx?: Knex) => { try { const doc = await (tx || db)(TableName.SecretRotation) - .join( - TableName.Environment, - `${TableName.SecretRotation}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretRotation}.envId`, `${TableName.Environment}.id`) .where({ [`${TableName.SecretRotation}.id` as "id"]: id }) .select(selectAllTableCols(TableName.SecretRotation)) .select( @@ -125,8 +113,7 @@ export const secretRotationDALFactory = (db: TDbClient) => { } }; - const findRotationOutputsByRotationId = async (rotationId: string) => - secretRotationOutputOrm.find({ rotationId }); + const findRotationOutputsByRotationId = async (rotationId: string) => secretRotationOutputOrm.find({ rotationId }); return { ...secretRotationOrm, diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts index bcd96e0900..c67477bfd9 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts @@ -1,3 +1,8 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-param-reassign */ import axios from "axios"; import jmespath from "jmespath"; @@ -6,12 +11,7 @@ import knex from "knex"; import { getConfig } from "@app/lib/config/env"; import { alphaNumericNanoId } from "@app/lib/nanoid"; -import { - TAssignOp, - TDbProviderClients, - TDirectAssignOp, - THttpProviderFunction -} from "../templates/types"; +import { TAssignOp, TDbProviderClients, TDirectAssignOp, THttpProviderFunction } from "../templates/types"; import { TSecretRotationData, TSecretRotationDbFn } from "./secret-rotation-queue-types"; const REGEX = /\${([^}]+)}/g; @@ -37,7 +37,7 @@ export const interpolate = (data: any, getValue: (key: string) => unknown) => { if ((data as { ref: string })?.ref) return getValue((data as { ref: string }).ref); const temp = data as Record; // for converting ts object to record type Object.keys(temp).forEach((key) => { - temp[key as keyof typeof temp] = interpolate(data[key as keyof typeof temp], getValue); + temp[key] = interpolate(data[key], getValue); }); } return data; @@ -59,10 +59,7 @@ const getInterpolationValue = (variables: TSecretRotationData) => (key: string) return variables[type as keyof TSecretRotationData][keyName]; }; -export const secretRotationHttpFn = async ( - func: THttpProviderFunction, - variables: TSecretRotationData -) => { +export const secretRotationHttpFn = async (func: THttpProviderFunction, variables: TSecretRotationData) => { // string interpolation const headers = interpolate(func.header, getInterpolationValue(variables)); const url = interpolate(func.url, getInterpolationValue(variables)); @@ -112,10 +109,7 @@ export const secretRotationDbFn = async ({ return data; }; -export const secretRotationPreSetFn = ( - op: Record, - variables: TSecretRotationData -) => { +export const secretRotationPreSetFn = (op: Record, variables: TSecretRotationData) => { const getValFn = getInterpolationValue(variables); Object.entries(op || {}).forEach(([key, assignFn]) => { const [type, keyName] = key.split(".") as [keyof TSecretRotationData, string]; @@ -123,10 +117,7 @@ export const secretRotationPreSetFn = ( }); }; -export const secretRotationHttpSetFn = async ( - func: THttpProviderFunction, - variables: TSecretRotationData -) => { +export const secretRotationHttpSetFn = async (func: THttpProviderFunction, variables: TSecretRotationData) => { const getValFn = getInterpolationValue(variables); // http setter const res = await secretRotationHttpFn(func, variables); @@ -140,10 +131,7 @@ export const secretRotationHttpSetFn = async ( }); }; -export const getDbSetQuery = ( - db: TDbProviderClients, - variables: { username: string; password: string } -) => { +export const getDbSetQuery = (db: TDbProviderClients, variables: { username: string; password: string }) => { if (db === TDbProviderClients.Pg) { return { query: `ALTER USER ?? WITH PASSWORD '${variables.password}'`, diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts index 5c4dc5e30b..9e69f0a8fe 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts @@ -6,6 +6,7 @@ import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { daysToMillisecond, secondsToMillis } from "@app/lib/dates"; +import { BadRequestError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; @@ -17,11 +18,7 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; import { TSecretRotationDALFactory } from "../secret-rotation-dal"; import { rotationTemplates } from "../templates"; -import { - TDbProviderClients, - TProviderFunctionTypes, - TSecretRotationProviderTemplate -} from "../templates/types"; +import { TDbProviderClients, TProviderFunctionTypes, TSecretRotationProviderTemplate } from "../templates/types"; import { getDbSetQuery, secretRotationDbFn, @@ -29,12 +26,7 @@ import { secretRotationHttpSetFn, secretRotationPreSetFn } from "./secret-rotation-queue-fn"; -import { - TSecretRotationData, - TSecretRotationDbFn, - TSecretRotationEncData -} from "./secret-rotation-queue-types"; -import { BadRequestError } from "@app/lib/errors"; +import { TSecretRotationData, TSecretRotationDbFn, TSecretRotationEncData } from "./secret-rotation-queue-types"; export type TSecretRotationQueueFactory = ReturnType; @@ -70,7 +62,7 @@ export const secretRotationQueueFactory = ({ }: TSecretRotationQueueFactoryDep) => { const addToQueue = async (rotationId: string, interval: number) => { const appCfg = getConfig(); - queue.queue( + await queue.queue( QueueName.SecretRotation, QueueJobs.SecretRotation, { rotationId }, @@ -78,10 +70,7 @@ export const secretRotationQueueFactory = ({ jobId: rotationId, repeat: { // on prod it this will be in days, in development this will be second - every: - appCfg.NODE_ENV === "development" - ? secondsToMillis(interval) - : daysToMillisecond(interval), + every: appCfg.NODE_ENV === "development" ? secondsToMillis(interval) : daysToMillisecond(interval), immediately: true } } @@ -95,10 +84,7 @@ export const secretRotationQueueFactory = ({ QueueJobs.SecretRotation, { // on prod it this will be in days, in development this will be second - every: - appCfg.NODE_ENV === "development" - ? secondsToMillis(interval) - : daysToMillisecond(interval) + every: appCfg.NODE_ENV === "development" ? secondsToMillis(interval) : daysToMillisecond(interval) }, rotationId ); @@ -108,22 +94,16 @@ export const secretRotationQueueFactory = ({ const { rotationId } = job.data; logger.info(`secretRotationQueue.process: [rotationDocument=${rotationId}]`); const secretRotation = await secretRotationDAL.findById(rotationId); - const rotationProvider = rotationTemplates.find( - ({ name }) => name === secretRotation?.provider - ); + const rotationProvider = rotationTemplates.find(({ name }) => name === secretRotation?.provider); try { - if (!rotationProvider || !secretRotation) - throw new DisableRotationErrors({ message: "Provider not found" }); + if (!rotationProvider || !secretRotation) throw new DisableRotationErrors({ message: "Provider not found" }); const rotationOutputs = await secretRotationDAL.findRotationOutputsByRotationId(rotationId); - if (!rotationOutputs.length) - throw new DisableRotationErrors({ message: "Secrets not found" }); + if (!rotationOutputs.length) throw new DisableRotationErrors({ message: "Secrets not found" }); // deep copy - const provider = JSON.parse( - JSON.stringify(rotationProvider) - ) as TSecretRotationProviderTemplate; + const provider = JSON.parse(JSON.stringify(rotationProvider)) as TSecretRotationProviderTemplate; // now get the encrypted variable values // in includes the inputs, the previous outputs @@ -156,20 +136,11 @@ export const secretRotationQueueFactory = ({ ? variables.inputs.username2 : variables.inputs.username1; } else { - newCredential.internal.username = lastCred - ? lastCred.internal.username - : variables.inputs.username1; + newCredential.internal.username = lastCred ? lastCred.internal.username : variables.inputs.username1; } // set a random value for new password newCredential.internal.rotated_password = alphaNumericNanoId(32); - const { - admin_username: username, - admin_password: password, - host, - database, - port, - ca - } = newCredential.inputs; + const { admin_username: username, admin_password: password, host, database, port, ca } = newCredential.inputs; const dbFunctionArg = { username, password, @@ -177,10 +148,7 @@ export const secretRotationQueueFactory = ({ database, port, ca: ca as string, - client: - provider.template.client === TDbProviderClients.MySql - ? "mysql2" - : provider.template.client + client: provider.template.client === TDbProviderClients.MySql ? "mysql2" : provider.template.client } as TSecretRotationDbFn; // set function await secretRotationDbFn({ @@ -265,7 +233,7 @@ export const secretRotationQueueFactory = ({ return { ...el, secretId: id, - secretBlindIndex: el.secretBlindIndex as string + secretBlindIndex: el.secretBlindIndex }; }), tx @@ -288,7 +256,7 @@ export const secretRotationQueueFactory = ({ logger.error(error); if (error instanceof DisableRotationErrors) { if (job.id) { - queue.stopRepeatableJobByJobId(QueueName.SecretRotation, job.id); + await queue.stopRepeatableJobByJobId(QueueName.SecretRotation, job.id); } } diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-service.ts b/backend/src/ee/services/secret-rotation/secret-rotation-service.ts index 88f555d94c..e10d7fa63b 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-service.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-service.ts @@ -47,10 +47,7 @@ export const secretRotationServiceFactory = ({ }: TSecretRotationServiceFactoryDep) => { const getProviderTemplates = async ({ actor, actorId, projectId }: TProjectPermission) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRotation - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation); return { custom: [], @@ -93,8 +90,7 @@ export const secretRotationServiceFactory = ({ const plan = await licenseService.getPlan(project.orgId); if (!plan.secretRotation) throw new BadRequestError({ - message: - "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation." + message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation." }); const selectedTemplate = rotationTemplates.find(({ name }) => name === provider); @@ -152,24 +148,14 @@ export const secretRotationServiceFactory = ({ const [doc] = await secretRotationDAL.find({ id: rotationId }); if (!doc) throw new BadRequestError({ message: "Rotation not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - doc.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRotation - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation); return doc; }; const getByProjectId = async ({ actorId, projectId, actor }: TListByProjectIdDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRotation - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation); const doc = await secretRotationDAL.find({ projectId }); return doc; }; @@ -182,19 +168,11 @@ export const secretRotationServiceFactory = ({ const plan = await licenseService.getPlan(project.orgId); if (!plan.secretRotation) throw new BadRequestError({ - message: - "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation." + message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation." }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - doc.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.SecretRotation - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation); await secretRotationQueue.removeFromQueue(doc.id, doc.interval); await secretRotationQueue.addToQueue(doc.id, doc.interval); return doc; @@ -204,11 +182,7 @@ export const secretRotationServiceFactory = ({ const doc = await secretRotationDAL.findById(rotationId); if (!doc) throw new BadRequestError({ message: "Rotation not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - doc.projectId - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Delete, ProjectPermissionSub.SecretRotation diff --git a/backend/src/ee/services/secret-rotation/templates/mysql.ts b/backend/src/ee/services/secret-rotation/templates/mysql.ts index 86a382d6e7..723560a3e8 100644 --- a/backend/src/ee/services/secret-rotation/templates/mysql.ts +++ b/backend/src/ee/services/secret-rotation/templates/mysql.ts @@ -23,15 +23,7 @@ export const MYSQL_TEMPLATE = { }, ca: { type: "string", desc: "SSL certificate for db auth(string)" } }, - required: [ - "admin_username", - "admin_password", - "host", - "database", - "username1", - "username2", - "port" - ], + required: ["admin_username", "admin_password", "host", "database", "username1", "username2", "port"], additionalProperties: false }, outputs: { diff --git a/backend/src/ee/services/secret-rotation/templates/postgres.ts b/backend/src/ee/services/secret-rotation/templates/postgres.ts index 318ca650d1..c894631cb2 100644 --- a/backend/src/ee/services/secret-rotation/templates/postgres.ts +++ b/backend/src/ee/services/secret-rotation/templates/postgres.ts @@ -23,15 +23,7 @@ export const POSTGRES_TEMPLATE = { }, ca: { type: "string", desc: "SSL certificate for db auth(string)" } }, - required: [ - "admin_username", - "admin_password", - "host", - "database", - "username1", - "username2", - "port" - ], + required: ["admin_username", "admin_password", "host", "database", "username1", "username2", "port"], additionalProperties: false }, outputs: { diff --git a/backend/src/ee/services/secret-scanning/git-app-dal.ts b/backend/src/ee/services/secret-scanning/git-app-dal.ts index 8a3ec706e7..8044b0d6b8 100644 --- a/backend/src/ee/services/secret-scanning/git-app-dal.ts +++ b/backend/src/ee/services/secret-scanning/git-app-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TGitAppOrgInsert } from "@app/db/schemas"; +import { TableName, TGitAppOrgInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -12,11 +12,7 @@ export const gitAppDALFactory = (db: TDbClient) => { const upsert = async (data: TGitAppOrgInsert, tx?: Knex) => { try { - const [doc] = await (tx || db)(TableName.GitAppOrg) - .insert(data) - .onConflict("orgId") - .merge() - .returning("*"); + const [doc] = await (tx || db)(TableName.GitAppOrg).insert(data).onConflict("orgId").merge().returning("*"); return doc; } catch (error) { throw new DatabaseError({ error, name: "UpsertGitAppOrm" }); diff --git a/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts b/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts index 9956d88ec5..11f8eb53cc 100644 --- a/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts +++ b/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TGitAppInstallSessionsInsert } from "@app/db/schemas"; +import { TableName, TGitAppInstallSessionsInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts b/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts index 4b5dcb378d..828322ad20 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretScanningGitRisksInsert } from "@app/db/schemas"; +import { TableName, TSecretScanningGitRisksInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -12,10 +12,7 @@ export const secretScanningDALFactory = (db: TDbClient) => { const upsert = async (data: TSecretScanningGitRisksInsert[], tx?: Knex) => { try { - const docs = await (tx || db)(TableName.SecretScanningGitRisk) - .insert(data) - .onConflict("fingerprint") - .merge(); + const docs = await (tx || db)(TableName.SecretScanningGitRisk).insert(data).onConflict("fingerprint").merge(); return docs; } catch (error) { throw new DatabaseError({ error, name: "GitRiskUpsert" }); diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts b/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts index b444cf56b4..2e74a1caff 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts @@ -1,3 +1,4 @@ +import { Octokit } from "@octokit/rest"; import { exec } from "child_process"; import { mkdir, readFile, rm, writeFile } from "fs"; import { tmpdir } from "os"; @@ -11,7 +12,7 @@ export function createTempFolder(): Promise { const tempFolderName = Math.random().toString(36).substring(2); const tempFolderPath = join(tempDir, tempFolderName); - mkdir(tempFolderPath, (err: any) => { + mkdir(tempFolderPath, (err) => { if (err) { reject(err); } else { @@ -115,7 +116,7 @@ export function convertKeysToLowercase(obj: T): T { } export async function scanFullRepoContentAndGetFindings( - octokit: any, + octokit: Octokit, installationId: string, repositoryFullName: string ): Promise { @@ -125,11 +126,13 @@ export async function scanFullRepoContentAndGetFindings( try { const { data: { token } - } = await octokit.apps.createInstallationAccessToken({ installation_id: installationId }); + } = await octokit.apps.createInstallationAccessToken({ + installation_id: Number(installationId) + }); await cloneRepo(token, repositoryFullName, repoPath); await runInfisicalScanOnRepo(repoPath, findingsPath); const findingsData = await readFindingsFile(findingsPath); - return JSON.parse(findingsData); + return JSON.parse(findingsData) as SecretMatch[]; } finally { await deleteTempFolder(tempFolder); } @@ -144,7 +147,7 @@ export async function scanContentAndGetFindings(textContent: string): Promise { if (!Object.keys(allFindingsByFingerprint).length) return; - secretScanningDAL.upsert( + await secretScanningDAL.upsert( Object.keys(allFindingsByFingerprint).map((key) => ({ installationId, email: allFindingsByFingerprint[key].Email, @@ -186,7 +179,9 @@ export const secretScanningQueueFactory = ({ }); const findings = await scanFullRepoContentAndGetFindings( - octokit, + // this is because of collision of octokit in probot and github + // eslint-disable-next-line + octokit as any, installationId, repository.fullName ); diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts index 63aae869f0..e150f30f30 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts @@ -4,10 +4,7 @@ import { ForbiddenError } from "@casl/ability"; import { WebhookEventMap } from "@octokit/webhooks-types"; import { ProbotOctokit } from "probot"; -import { - OrgPermissionActions, - OrgPermissionSubjects -} from "@app/ee/services/permission/org-permission"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { getConfig } from "@app/lib/config/env"; import { UnauthorizedError } from "@app/lib/errors"; @@ -44,30 +41,19 @@ export const secretScanningServiceFactory = ({ }: TSecretScanningServiceFactoryDep) => { const createInstallationSession = async ({ actor, orgId, actorId }: TInstallAppSessionDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.SecretScanning - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning); const sessionId = crypto.randomBytes(16).toString("hex"); await gitAppInstallSessionDAL.upsert({ orgId, sessionId, userId: actorId }); return { sessionId }; }; - const linkInstallationToOrg = async ({ - sessionId, - actorId, - installationId, - actor - }: TLinkInstallSessionDTO) => { + const linkInstallationToOrg = async ({ sessionId, actorId, installationId, actor }: TLinkInstallSessionDTO) => { const session = await gitAppInstallSessionDAL.findOne({ sessionId }); if (!session) throw new UnauthorizedError({ message: "Session not found" }); const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.SecretScanning - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning); const installatedApp = await gitAppOrgDAL.transaction(async (tx) => { await gitAppInstallSessionDAL.deleteById(session.id, tx); return gitAppOrgDAL.upsert({ orgId: session.orgId, installationId, userId: actorId }, tx); @@ -99,10 +85,7 @@ export const secretScanningServiceFactory = ({ const getOrgInstallationStatus = async ({ actorId, orgId, actor }: TGetOrgInstallStatusDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.SecretScanning - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning); const appInstallation = await gitAppOrgDAL.findOne({ orgId }); return Boolean(appInstallation); @@ -110,26 +93,14 @@ export const secretScanningServiceFactory = ({ const getRisksByOrg = async ({ actor, orgId, actorId }: TGetOrgRisksDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.SecretScanning - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning); const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] }); return { risks }; }; - const updateRiskStatus = async ({ - actorId, - orgId, - actor, - riskId, - status - }: TUpdateRiskStatusDTO) => { + const updateRiskStatus = async ({ actorId, orgId, actor, riskId, status }: TUpdateRiskStatusDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.SecretScanning - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning); const isRiskResolved = Boolean( [ @@ -169,11 +140,7 @@ export const secretScanningServiceFactory = ({ const handleRepoDeleteEvent = async (installationId: string, repositoryIds: string[]) => { await secretScanningDAL.transaction(async (tx) => { if (repositoryIds.length) { - await Promise.all( - repositoryIds.map((repoId) => - secretScanningDAL.delete({ repositoryId: repoId }, tx) - ) - ); + await Promise.all(repositoryIds.map((repoId) => secretScanningDAL.delete({ repositoryId: repoId }, tx))); } await gitAppOrgDAL.delete({ installationId }, tx); }); diff --git a/backend/src/ee/services/secret-snapshot/secret-snapshot-service.ts b/backend/src/ee/services/secret-snapshot/secret-snapshot-service.ts index d1e5bad6b4..26148958fa 100644 --- a/backend/src/ee/services/secret-snapshot/secret-snapshot-service.ts +++ b/backend/src/ee/services/secret-snapshot/secret-snapshot-service.ts @@ -29,17 +29,11 @@ type TSecretSnapshotServiceFactoryDep = { snapshotSecretDAL: TSnapshotSecretDALFactory; snapshotFolderDAL: TSnapshotFolderDALFactory; secretVersionDAL: Pick; - folderVersionDAL: Pick< - TSecretFolderVersionDALFactory, - "findLatestVersionByFolderId" | "insertMany" - >; + folderVersionDAL: Pick; secretDAL: Pick; secretTagDAL: Pick; secretVersionTagDAL: Pick; - folderDAL: Pick< - TSecretFolderDALFactory, - "findById" | "findBySecretPath" | "delete" | "insertMany" - >; + folderDAL: Pick; permissionService: Pick; licenseService: Pick; }; @@ -67,10 +61,7 @@ export const secretSnapshotServiceFactory = ({ path }: TProjectSnapshotCountDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRollback - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found" }); @@ -89,40 +80,26 @@ export const secretSnapshotServiceFactory = ({ offset = 0 }: TProjectSnapshotListDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRollback - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found" }); - const snapshots = await snapshotDAL.find( - { folderId: folder.id }, - { limit, offset, sort: [["createdAt", "desc"]] } - ); + const snapshots = await snapshotDAL.find({ folderId: folder.id }, { limit, offset, sort: [["createdAt", "desc"]] }); return snapshots; }; const getSnapshotData = async ({ actorId, actor, id }: TGetSnapshotDataDTO) => { const snapshot = await snapshotDAL.findSecretSnapshotDataById(id); if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - snapshot.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRollback - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); return snapshot; }; const performSnapshot = async (folderId: string) => { try { - if (!licenseService.isValidLicense) - throw new InternalServerError({ message: "Invalid license" }); + if (!licenseService.isValidLicense) throw new InternalServerError({ message: "Invalid license" }); const snapshot = await snapshotDAL.transaction(async (tx) => { const folder = await folderDAL.findById(folderId, tx); @@ -170,11 +147,7 @@ export const secretSnapshotServiceFactory = ({ const snapshot = await snapshotDAL.findById(snapshotId); if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - snapshot.projectId - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback @@ -199,9 +172,7 @@ export const secretSnapshotServiceFactory = ({ id, // this means don't bump up the version if not root folder // because below ones can be same version as nothing changed - version: deletedTopLevelFolders[folderId] - ? latestFolderVersion + 1 - : latestFolderVersion, + version: deletedTopLevelFolders[folderId] ? latestFolderVersion + 1 : latestFolderVersion, name, parentId: folderId })) @@ -211,22 +182,10 @@ export const secretSnapshotServiceFactory = ({ const secrets = await secretDAL.insertMany( rollbackSnaps.flatMap(({ secretVersions, folderId }) => secretVersions.map( - ({ - latestSecretVersion, - version, - updatedAt, - createdAt, - secretId, - envId, - id, - tags, - ...el - }) => ({ + ({ latestSecretVersion, version, updatedAt, createdAt, secretId, envId, id, tags, ...el }) => ({ ...el, id: secretId, - version: deletedTopLevelSecsGroupById[secretId] - ? latestSecretVersion + 1 - : latestSecretVersion, + version: deletedTopLevelSecsGroupById[secretId] ? latestSecretVersion + 1 : latestSecretVersion, folderId }) ) @@ -239,8 +198,7 @@ export const secretSnapshotServiceFactory = ({ secretVersions.forEach((secVer) => { secVer.tags.forEach((tag) => { secretTagsToBeInsert.push({ secretsId: secVer.secretId, secret_tagsId: tag.id }); - if (!secretVerTagToBeInsert?.[secVer.secretId]) - secretVerTagToBeInsert[secVer.secretId] = []; + if (!secretVerTagToBeInsert?.[secVer.secretId]) secretVerTagToBeInsert[secVer.secretId] = []; secretVerTagToBeInsert[secVer.secretId].push(tag.id); }); }); diff --git a/backend/src/ee/services/secret-snapshot/snapshot-dal.ts b/backend/src/ee/services/secret-snapshot/snapshot-dal.ts index 66c72ca535..41524c6eb8 100644 --- a/backend/src/ee/services/secret-snapshot/snapshot-dal.ts +++ b/backend/src/ee/services/secret-snapshot/snapshot-dal.ts @@ -57,11 +57,7 @@ export const snapshotDALFactory = (db: TDbClient) => { const data = await (tx || db)(TableName.Snapshot) .where(`${TableName.Snapshot}.id`, snapshotId) .join(TableName.Environment, `${TableName.Snapshot}.envId`, `${TableName.Environment}.id`) - .leftJoin( - TableName.SnapshotSecret, - `${TableName.Snapshot}.id`, - `${TableName.SnapshotSecret}.snapshotId` - ) + .leftJoin(TableName.SnapshotSecret, `${TableName.Snapshot}.id`, `${TableName.SnapshotSecret}.snapshotId`) .leftJoin( TableName.SecretVersion, `${TableName.SnapshotSecret}.secretVersionId`, @@ -77,11 +73,7 @@ export const snapshotDALFactory = (db: TDbClient) => { `${TableName.SecretVersionTag}.${TableName.SecretTag}Id`, `${TableName.SecretTag}.id` ) - .leftJoin( - TableName.SnapshotFolder, - `${TableName.SnapshotFolder}.snapshotId`, - `${TableName.Snapshot}.id` - ) + .leftJoin(TableName.SnapshotFolder, `${TableName.SnapshotFolder}.snapshotId`, `${TableName.Snapshot}.id`) .leftJoin( TableName.SecretFolderVersion, `${TableName.SnapshotFolder}.folderVersionId`, @@ -131,13 +123,13 @@ export const snapshotDALFactory = (db: TDbClient) => { { key: "tagVersionId", label: "tags" as const, - mapper: ({ - tagId: id, - tagName: name, - tagSlug: slug, - tagColor: color, - tagVersionId: vId - }) => ({ id, name, slug, color, vId }) + mapper: ({ tagId: id, tagName: name, tagSlug: slug, tagColor: color, tagVersionId: vId }) => ({ + id, + name, + slug, + color, + vId + }) } ] }, @@ -162,7 +154,8 @@ export const snapshotDALFactory = (db: TDbClient) => { try { const data = await (tx || db) .withRecursive("parent", (qb) => { - qb.from(TableName.Snapshot) + void qb + .from(TableName.Snapshot) .leftJoin( TableName.SnapshotFolder, `${TableName.SnapshotFolder}.snapshotId`, @@ -180,44 +173,37 @@ export const snapshotDALFactory = (db: TDbClient) => { db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") ) .where(`${TableName.Snapshot}.id`, snapshotId) - .union((cb) => - cb - .select(selectAllTableCols(TableName.Snapshot)) - .select({ depth: db.raw("parent.depth + 1") }) - .select( - db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"), - db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") - ) - .from(TableName.Snapshot) - .join( - db(TableName.Snapshot) - .groupBy("folderId") - .max("createdAt") - .select("folderId") - .as("latestVersion"), - `${TableName.Snapshot}.createdAt`, - "latestVersion.max" - ) - .leftJoin( - TableName.SnapshotFolder, - `${TableName.SnapshotFolder}.snapshotId`, - `${TableName.Snapshot}.id` - ) - .leftJoin( - TableName.SecretFolderVersion, - `${TableName.SnapshotFolder}.folderVersionId`, - `${TableName.SecretFolderVersion}.id` - ) - .join("parent", "parent.folderVerId", `${TableName.Snapshot}.folderId`) + .union( + (cb) => + void cb + .select(selectAllTableCols(TableName.Snapshot)) + .select({ depth: db.raw("parent.depth + 1") }) + .select( + db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"), + db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") + ) + .from(TableName.Snapshot) + .join( + db(TableName.Snapshot).groupBy("folderId").max("createdAt").select("folderId").as("latestVersion"), + `${TableName.Snapshot}.createdAt`, + "latestVersion.max" + ) + .leftJoin( + TableName.SnapshotFolder, + `${TableName.SnapshotFolder}.snapshotId`, + `${TableName.Snapshot}.id` + ) + .leftJoin( + TableName.SecretFolderVersion, + `${TableName.SnapshotFolder}.folderVersionId`, + `${TableName.SecretFolderVersion}.id` + ) + .join("parent", "parent.folderVerId", `${TableName.Snapshot}.folderId`) ); }) .orderBy("depth", "asc") .from("parent") - .leftJoin( - TableName.SnapshotSecret, - `parent.id`, - `${TableName.SnapshotSecret}.snapshotId` - ) + .leftJoin(TableName.SnapshotSecret, `parent.id`, `${TableName.SnapshotSecret}.snapshotId`) .leftJoin( TableName.SecretVersion, `${TableName.SnapshotSecret}.secretVersionId`, @@ -270,11 +256,7 @@ export const snapshotDALFactory = (db: TDbClient) => { const formated = sqlNestRelationships({ data, key: "snapshotId", - parentMapper: ({ - snapshotId: id, - snapshotFolderId: folderId, - snapshotParentFolderId: parentFolderId - }) => ({ + parentMapper: ({ snapshotId: id, snapshotFolderId: folderId, snapshotParentFolderId: parentFolderId }) => ({ id, folderId, parentFolderId @@ -285,19 +267,19 @@ export const snapshotDALFactory = (db: TDbClient) => { label: "secretVersions" as const, mapper: (el) => ({ ...SecretVersionsSchema.parse(el), - latestSecretVersion: el.latestSecretVersion + latestSecretVersion: el.latestSecretVersion as number }), childrenMapper: [ { key: "tagVersionId", label: "tags" as const, - mapper: ({ - tagId: id, - tagName: name, - tagSlug: slug, - tagColor: color, - tagVersionId: vId - }) => ({ id, name, slug, color, vId }) + mapper: ({ tagId: id, tagName: name, tagSlug: slug, tagColor: color, tagVersionId: vId }) => ({ + id, + name, + slug, + color, + vId + }) } ] }, @@ -307,7 +289,7 @@ export const snapshotDALFactory = (db: TDbClient) => { mapper: ({ folderVerId: id, folderVerName: name, latestFolderVersion }) => ({ id, name, - latestFolderVersion + latestFolderVersion: latestFolderVersion as number }) } ] @@ -326,11 +308,7 @@ export const snapshotDALFactory = (db: TDbClient) => { const docs = await (tx || db)(TableName.Snapshot) .where(`${TableName.Snapshot}.folderId`, folderId) .join( - (tx || db)(TableName.Snapshot) - .groupBy("folderId") - .max("createdAt") - .select("folderId") - .as("latestVersion"), + (tx || db)(TableName.Snapshot).groupBy("folderId").max("createdAt").select("folderId").as("latestVersion"), (bd) => { bd.on(`${TableName.Snapshot}.folderId`, "latestVersion.folderId").andOn( `${TableName.Snapshot}.createdAt`, diff --git a/backend/src/ee/services/trusted-ip/trusted-ip-service.ts b/backend/src/ee/services/trusted-ip/trusted-ip-service.ts index 72b0eef9f7..a443a32f03 100644 --- a/backend/src/ee/services/trusted-ip/trusted-ip-service.ts +++ b/backend/src/ee/services/trusted-ip/trusted-ip-service.ts @@ -28,36 +28,22 @@ export const trustedIpServiceFactory = ({ }: TTrustedIpServiceFactoryDep) => { const listIpsByProjectId = async ({ projectId, actor, actorId }: TProjectPermission) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.IpAllowList - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList); const trustedIps = await trustedIpDAL.find({ projectId }); return trustedIps; }; - const addProjectIp = async ({ - projectId, - actorId, - actor, - ipAddress: ip, - comment, - isActive - }: TCreateIpDTO) => { + const addProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, isActive }: TCreateIpDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.IpAllowList - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); const project = await projectDAL.findById(projectId); const plan = await licenseService.getPlan(project.orgId); if (!plan.ipAllowlisting) throw new BadRequestError({ - message: - "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." + message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." }); const isValidIp = isValidIpOrCidr(ip); @@ -79,26 +65,15 @@ export const trustedIpServiceFactory = ({ return { trustedIp, project }; // for audit log }; - const updateProjectIp = async ({ - projectId, - actorId, - actor, - ipAddress: ip, - comment, - trustedIpId - }: TUpdateIpDTO) => { + const updateProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, trustedIpId }: TUpdateIpDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.IpAllowList - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); const project = await projectDAL.findById(projectId); const plan = await licenseService.getPlan(project.orgId); if (!plan.ipAllowlisting) throw new BadRequestError({ - message: - "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." + message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." }); const isValidIp = isValidIpOrCidr(ip); @@ -124,17 +99,13 @@ export const trustedIpServiceFactory = ({ const deleteProjectIp = async ({ projectId, actorId, actor, trustedIpId }: TDeleteIpDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.IpAllowList - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); const project = await projectDAL.findById(projectId); const plan = await licenseService.getPlan(project.orgId); if (!plan.ipAllowlisting) throw new BadRequestError({ - message: - "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." + message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range." }); const [trustedIp] = await trustedIpDAL.delete({ projectId, id: trustedIpId }); diff --git a/backend/src/lib/casl/index.ts b/backend/src/lib/casl/index.ts index 1e853cc4d2..9e5cb29d3d 100644 --- a/backend/src/lib/casl/index.ts +++ b/backend/src/lib/casl/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { buildMongoQueryMatcher, MongoAbility } from "@casl/ability"; import { FieldCondition, FieldInstruction, JsInterpreter } from "@ucast/mongo2js"; import picomatch from "picomatch"; @@ -12,7 +13,7 @@ const $glob: FieldInstruction = { }; const glob: JsInterpreter> = (node, object, context) => { - const secretPath = context.get(object, node.field); + const secretPath = context.get(object, node.field) as string; const permissionSecretGlobPath = node.value; return picomatch.isMatch(secretPath, permissionSecretGlobPath, { strictSlashes: false }); }; @@ -23,7 +24,7 @@ export const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob }); * Extracts and formats permissions from a CASL Ability object or a raw permission set. */ const extractPermissions = (ability: MongoAbility) => - ability.rules.map((permission) => `${permission.action}_${permission.subject}`); + ability.rules.map((permission) => `${permission.action as string}_${permission.subject as string}`); /** * Compares two sets of permissions to determine if the first set is at least as privileged as the second set. diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 25d985f417..11c1a3a366 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -38,9 +38,7 @@ const envSchema = z // Telemetry TELEMETRY_ENABLED: zodStrBool.default("true"), POSTHOG_HOST: zpStr(z.string().optional().default("https://app.posthog.com")), - POSTHOG_PROJECT_API_KEY: zpStr( - z.string().optional().default("phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE") - ), + POSTHOG_PROJECT_API_KEY: zpStr(z.string().optional().default("phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE")), LOOPS_API_KEY: zpStr(z.string().optional()), // jwt options AUTH_SECRET: zpStr(z.string()).default(process.env.JWT_AUTH_SECRET), // for those still using old JWT_AUTH_SECRET @@ -56,7 +54,12 @@ const envSchema = z CLIENT_SECRET_GITHUB_LOGIN: zpStr(z.string().optional()), CLIENT_ID_GITLAB_LOGIN: zpStr(z.string().optional()), CLIENT_SECRET_GITLAB_LOGIN: zpStr(z.string().optional()), - CLIENT_GITLAB_LOGIN_URL: zpStr(z.string().optional().default(process.env.URL_GITLAB_LOGIN ?? GITLAB_URL)), // fallback since URL_GITLAB_LOGIN has been renamed + CLIENT_GITLAB_LOGIN_URL: zpStr( + z + .string() + .optional() + .default(process.env.URL_GITLAB_LOGIN ?? GITLAB_URL) + ), // fallback since URL_GITLAB_LOGIN has been renamed // integration client secrets // heroku CLIENT_ID_HEROKU: zpStr(z.string().optional()), @@ -121,7 +124,7 @@ export const initEnvConfig = (logger: Logger) => { logger.error(parsedEnv.error.issues); process.exit(-1); } - + envCfg = Object.freeze(parsedEnv.data); return envCfg; }; diff --git a/backend/src/lib/config/request.ts b/backend/src/lib/config/request.ts index 0917137271..8636b74763 100644 --- a/backend/src/lib/config/request.ts +++ b/backend/src/lib/config/request.ts @@ -5,6 +5,7 @@ export const request = axios.create(); axiosRetry(request, { retries: 3, + // eslint-disable-next-line retryDelay: axiosRetry.exponentialDelay, retryCondition: (err) => axiosRetry.isNetworkError(err) || axiosRetry.isRetryableError(err) }); diff --git a/backend/src/lib/crypto/encryption.ts b/backend/src/lib/crypto/encryption.ts index ef1a7afe02..74febccec8 100644 --- a/backend/src/lib/crypto/encryption.ts +++ b/backend/src/lib/crypto/encryption.ts @@ -20,11 +20,7 @@ export const BLOCK_SIZE_BYTES_16 = 16; export const decryptSymmetric = ({ ciphertext, iv, tag, key }: TDecryptSymmetricInput): string => { const secretKey = crypto.createSecretKey(key, "base64"); - const decipher = crypto.createDecipheriv( - SecretEncryptionAlgo.AES_256_GCM, - secretKey, - Buffer.from(iv, "base64") - ); + const decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, secretKey, Buffer.from(iv, "base64")); decipher.setAuthTag(Buffer.from(tag, "base64")); let cleartext = decipher.update(ciphertext, "base64", "utf8"); cleartext += decipher.final("utf8"); @@ -62,17 +58,8 @@ export const encryptSymmetric128BitHexKeyUTF8 = (plaintext: string, key: string) }; }; -export const decryptSymmetric128BitHexKeyUTF8 = ({ - ciphertext, - iv, - tag, - key -}: TDecryptSymmetricInput): string => { - const decipher = crypto.createDecipheriv( - SecretEncryptionAlgo.AES_256_GCM, - key, - Buffer.from(iv, "base64") - ); +export const decryptSymmetric128BitHexKeyUTF8 = ({ ciphertext, iv, tag, key }: TDecryptSymmetricInput): string => { + const decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, key, Buffer.from(iv, "base64")); decipher.setAuthTag(Buffer.from(tag, "base64")); @@ -104,12 +91,7 @@ export type TDecryptAsymmetricInput = { privateKey: string; }; -export const decryptAsymmetric = ({ - ciphertext, - nonce, - publicKey, - privateKey -}: TDecryptAsymmetricInput) => { +export const decryptAsymmetric = ({ ciphertext, nonce, publicKey, privateKey }: TDecryptAsymmetricInput) => { const plaintext: Uint8Array | null = nacl.box.open( naclUtils.decodeBase64(ciphertext), naclUtils.decodeBase64(nonce), @@ -223,7 +205,7 @@ export const infisicalSymmetricEncypt = (data: string) => { throw new Error("Missing both encryption keys"); }; -export const infisicalSymmetricDecrypt = ({ +export const infisicalSymmetricDecrypt = ({ keyEncoding, ciphertext, tag, diff --git a/backend/src/lib/fn/array.ts b/backend/src/lib/fn/array.ts index abe8e34661..1e075101b2 100644 --- a/backend/src/lib/fn/array.ts +++ b/backend/src/lib/fn/array.ts @@ -23,13 +23,10 @@ export const groupBy = ( * to convert each item in the list to a comparable identity * value */ -export const unique = ( - array: readonly T[], - toKey?: (item: T) => K -): T[] => { +export const unique = (array: readonly T[], toKey?: (item: T) => K): T[] => { const valueMap = array.reduce( (acc, item) => { - const key = toKey ? toKey(item) : (item as any as string | number | symbol); + const key = toKey ? toKey(item) : (item as unknown as string | number | symbol); if (acc[key]) return acc; acc[key] = item; return acc; diff --git a/backend/src/lib/fn/object.ts b/backend/src/lib/fn/object.ts index 2fadc685cf..87db803434 100644 --- a/backend/src/lib/fn/object.ts +++ b/backend/src/lib/fn/object.ts @@ -2,10 +2,7 @@ * Pick a list of properties from an object * into a new object */ -export const pick = ( - obj: T, - keys: TKeys[] -): Pick => { +export const pick = (obj: T, keys: TKeys[]): Pick => { if (!obj) return {} as Pick; return keys.reduce( (acc, key) => { @@ -21,9 +18,9 @@ export const pick = ( * object. Optional second argument shakes out values * by custom evaluation. */ -export const shake = ( +export const shake = ( obj: T, - filter: (value: any) => boolean = (x) => x === undefined || x === null + filter: (value: unknown) => boolean = (x) => x === undefined || x === null ): Omit => { if (!obj) return {} as T; const keys = Object.keys(obj) as (keyof T)[]; diff --git a/backend/src/lib/ip/index.ts b/backend/src/lib/ip/index.ts index f14ed4f414..30f710d19b 100644 --- a/backend/src/lib/ip/index.ts +++ b/backend/src/lib/ip/index.ts @@ -111,13 +111,7 @@ export type TIp = { /** * Validates the IP address [ipAddress] against the trusted IPs [trustedIps]. */ -export const checkIPAgainstBlocklist = ({ - ipAddress, - trustedIps -}: { - ipAddress: string; - trustedIps: TIp[]; -}) => { +export const checkIPAgainstBlocklist = ({ ipAddress, trustedIps }: { ipAddress: string; trustedIps: TIp[] }) => { const blockList = new net.BlockList(); for (const trustedIp of trustedIps) { diff --git a/backend/src/lib/knex/index.ts b/backend/src/lib/knex/index.ts index 515089e65b..37fae624ef 100644 --- a/backend/src/lib/knex/index.ts +++ b/backend/src/lib/knex/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ import { Knex } from "knex"; import { Tables } from "knex/types/tables"; @@ -15,22 +16,22 @@ export const withTransaction = (db: Knex, dal: K) => ({ ...dal }); -export type TFindFilter = Partial & { +export type TFindFilter = Partial & { $in?: Partial<{ [k in keyof R]: R[k][] }>; }; export const buildFindFilter = - ({ $in, ...filter }: TFindFilter) => + ({ $in, ...filter }: TFindFilter) => (bd: Knex.QueryBuilder) => { - bd.where(filter); + void bd.where(filter); if ($in) { Object.entries($in).forEach(([key, val]) => { - bd.whereIn(key as any, val as any); + void bd.whereIn(key as never, val as never); }); } return bd; }; -export type TFindOpt = { +export type TFindOpt = { limit?: number; offset?: number; sort?: Array<[keyof R, "asc" | "desc"] | [keyof R, "asc" | "desc", "first" | "last"]>; @@ -40,11 +41,7 @@ export type TFindOpt = { // What is ormify // It is to inject typical operations like find, findOne, update, delete, create // This will avoid writing most common ones each time -export const ormify = ( - db: Knex, - tableName: Tname, - dal?: DbOps -) => ({ +export const ormify = (db: Knex, tableName: Tname, dal?: DbOps) => ({ transaction: async (cb: (tx: Knex) => Promise) => db.transaction(async (trx) => { const res = await cb(trx); @@ -53,7 +50,7 @@ export const ormify = ( findById: async (id: string, tx?: Knex) => { try { const result = await (tx || db)(tableName) - .where({ id } as any) + .where({ id } as never) .first("*"); return result; } catch (error) { @@ -74,12 +71,10 @@ export const ormify = ( ) => { try { const query = (tx || db)(tableName).where(buildFindFilter(filter)); - if (limit) query.limit(limit); - if (offset) query.offset(offset); + if (limit) void query.limit(limit); + if (offset) void query.offset(offset); if (sort) { - query.orderBy( - sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })) - ); + void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls }))); } const res = await query; return res; @@ -90,7 +85,7 @@ export const ormify = ( create: async (data: Tables[Tname]["insert"], tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .insert(data as any) + .insert(data as never) .returning("*"); return res; } catch (error) { @@ -101,7 +96,7 @@ export const ormify = ( try { if (!data.length) return []; const res = await (tx || db)(tableName) - .insert(data as any) + .insert(data as never) .returning("*"); return res; } catch (error) { @@ -111,23 +106,19 @@ export const ormify = ( updateById: async (id: string, data: Tables[Tname]["update"], tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .where({ id } as any) - .update(data as any) + .where({ id } as never) + .update(data as never) .returning("*"); return res; } catch (error) { throw new DatabaseError({ error, name: "Update by id" }); } }, - update: async ( - filter: TFindFilter, - data: Tables[Tname]["update"], - tx?: Knex - ) => { + update: async (filter: TFindFilter, data: Tables[Tname]["update"], tx?: Knex) => { try { const res = await (tx || db)(tableName) .where(buildFindFilter(filter)) - .update(data as any) + .update(data as never) .returning("*"); return res; } catch (error) { @@ -137,7 +128,7 @@ export const ormify = ( deleteById: async (id: string, tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .where({ id } as any) + .where({ id } as never) .delete() .returning("*"); return res; @@ -147,10 +138,7 @@ export const ormify = ( }, delete: async (filter: TFindFilter, tx?: Knex) => { try { - const res = await (tx || db)(tableName) - .where(buildFindFilter(filter)) - .delete() - .returning("*"); + const res = await (tx || db)(tableName).where(buildFindFilter(filter)).delete().returning("*"); return res; } catch (error) { throw new DatabaseError({ error, name: "Delete" }); diff --git a/backend/src/lib/knex/join.ts b/backend/src/lib/knex/join.ts index 59144fbcc1..6580bfa3d6 100644 --- a/backend/src/lib/knex/join.ts +++ b/backend/src/lib/knex/join.ts @@ -1,7 +1,16 @@ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// TODO(akhilmhdh): make this better later + export const mergeOneToManyRelation = < - T extends Record, + T extends Record, Pk extends keyof T, - P extends Record, + P extends Record, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint C extends any, Ck extends string = "child" >( @@ -22,7 +31,7 @@ export const mergeOneToManyRelation = < const parent = parentMapper(row) as any; parent[childKey] = []; groupedRecord.push(parent); - prevPkId = pk; + prevPkId = pk as string; prevPkIndex += 1; } groupedRecord[prevPkIndex][childKey].push(childMapper(row)); @@ -41,6 +50,7 @@ export type TSqlPackRelationships< childrenMapper: C; }; +// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint export type TChildMapper = { key: keyof T; label: U; @@ -82,7 +92,7 @@ const sqlChildMapper = < const ck = `${prefix}-${label}-${doc[childPk]}`; const val = mapper(doc); if (!lookupTable.has(ck)) { - if (typeof val !== "undefined" && val !== null) docsByPk[pk as keyof P][label].push(val); + if (typeof val !== "undefined" && val !== null) docsByPk[pk][label].push(val); lookupTable.add(ck); } if (nestedMappers && val) { diff --git a/backend/src/lib/logger/index.ts b/backend/src/lib/logger/index.ts index df012e4347..21cb66920f 100644 --- a/backend/src/lib/logger/index.ts +++ b/backend/src/lib/logger/index.ts @@ -1 +1 @@ -export { initLogger,logger } from "./logger"; +export { initLogger, logger } from "./logger"; diff --git a/backend/src/lib/logger/logger.ts b/backend/src/lib/logger/logger.ts index 82db1725c2..67e200c8a7 100644 --- a/backend/src/lib/logger/logger.ts +++ b/backend/src/lib/logger/logger.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ // logger follows a singleton pattern // easier to use it that's all. import pino, { Logger } from "pino"; @@ -14,10 +15,10 @@ const logLevelToSeverityLookup: Record = { // eslint-disable-next-line import/no-mutable-exports export let logger: Readonly; -// akhilmhdh: -// The logger is not placed in the main app config to avoid a circular dependency. -// The config requires the logger to display errors when an invalid environment is supplied. -// On the other hand, the logger needs the config to obtain credentials for AWS or other transports. +// akhilmhdh: +// The logger is not placed in the main app config to avoid a circular dependency. +// The config requires the logger to display errors when an invalid environment is supplied. +// On the other hand, the logger needs the config to obtain credentials for AWS or other transports. // By keeping the logger separate, it becomes an independent package. const loggerConfig = z.object({ @@ -66,6 +67,7 @@ export const initLogger = async () => { }) } }, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument transport ); return logger; diff --git a/backend/src/lib/zod/index.ts b/backend/src/lib/zod/index.ts index 331a5fbb68..a3cded66b1 100644 --- a/backend/src/lib/zod/index.ts +++ b/backend/src/lib/zod/index.ts @@ -1,10 +1,7 @@ -import { z,ZodTypeAny } from "zod"; +import { z, ZodTypeAny } from "zod"; // this is a patched zod string to remove empty string to undefined -export const zpStr = ( - schema: T, - opt: { stripNull: boolean } = { stripNull: true } -) => +export const zpStr = (schema: T, opt: { stripNull: boolean } = { stripNull: true }) => z.preprocess((val) => { if (opt.stripNull && val === null) return undefined; if (typeof val !== "string") return val; diff --git a/backend/src/main.ts b/backend/src/main.ts index 4891157adf..c1a3d7207b 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -18,19 +18,21 @@ const run = async () => { const server = await main({ db, smtp, logger, queue }); const bootstrap = await bootstrapCheck({ db }); + // eslint-disable-next-line process.on("SIGINT", async () => { await server.close(); await db.destroy(); process.exit(0); }); + // eslint-disable-next-line process.on("SIGTERM", async () => { await server.close(); await db.destroy(); process.exit(0); }); - server.listen({ + await server.listen({ port: appCfg.PORT, host: appCfg.HOST, listenTextResolver: (address) => { @@ -40,4 +42,4 @@ const run = async () => { }); }; -run(); +void run(); diff --git a/backend/src/queue/queue-service.ts b/backend/src/queue/queue-service.ts index 8a170487fb..c46b60ca9f 100644 --- a/backend/src/queue/queue-service.ts +++ b/backend/src/queue/queue-service.ts @@ -63,37 +63,32 @@ export type TQueueJobTypes = { export type TQueueServiceFactory = ReturnType; export const queueServiceFactory = (redisUrl: string) => { const connection = new Redis(redisUrl, { maxRetriesPerRequest: null }); - const queueContainer: Record< + const queueContainer = {} as Record< QueueName, Queue - > = {} as any; - const workerContainer: Record< + >; + const workerContainer = {} as Record< QueueName, Worker - > = {} as any; + >; const start = ( name: T, - jobFn: ( - job: Job - ) => Promise + jobFn: (job: Job) => Promise ) => { if (queueContainer[name]) { throw new Error(`${name} queue is already initialized`); } - queueContainer[name] = new Queue( - name as string, - { connection } - ); - workerContainer[name] = new Worker< - TQueueJobTypes[T]["payload"], - void, - TQueueJobTypes[T]["name"] - >(name, jobFn, { connection }); + queueContainer[name] = new Queue(name as string, { + connection + }); + workerContainer[name] = new Worker(name, jobFn, { + connection + }); }; - const listen = async < + const listen = < T extends QueueName, U extends keyof WorkerListener >( diff --git a/backend/src/server/config/rateLimiter.ts b/backend/src/server/config/rateLimiter.ts index 7982cff63c..444158cbf4 100644 --- a/backend/src/server/config/rateLimiter.ts +++ b/backend/src/server/config/rateLimiter.ts @@ -6,7 +6,7 @@ import { getConfig } from "@app/lib/config/env"; export const globalRateLimiterCfg = (): RateLimitPluginOptions => { const appCfg = getConfig(); const redis = appCfg.isRedisConfigured - ? new Redis(appCfg.REDIS_URL as string, { connectTimeout: 500, maxRetriesPerRequest: 1 }) + ? new Redis(appCfg.REDIS_URL, { connectTimeout: 500, maxRetriesPerRequest: 1 }) : null; return { diff --git a/backend/src/server/plugins/auth/inject-identity.ts b/backend/src/server/plugins/auth/inject-identity.ts index f60b9f4c57..04d4cbe0e1 100644 --- a/backend/src/server/plugins/auth/inject-identity.ts +++ b/backend/src/server/plugins/auth/inject-identity.ts @@ -5,12 +5,7 @@ import jwt, { JwtPayload } from "jsonwebtoken"; import { TServiceTokens, TUsers } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; import { UnauthorizedError } from "@app/lib/errors"; -import { - ActorType, - AuthMode, - AuthModeJwtTokenPayload, - AuthTokenType -} from "@app/services/auth/auth-type"; +import { ActorType, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types"; export type TAuthMode = @@ -87,16 +82,12 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => { switch (authMode) { case AuthMode.JWT: { - const { user, tokenVersionId } = - await server.services.authToken.fnValidateJwtIdentity(token); + const { user, tokenVersionId } = await server.services.authToken.fnValidateJwtIdentity(token); req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor }; break; } case AuthMode.IDENTITY_ACCESS_TOKEN: { - const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken( - token, - req.realIp - ); + const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp); req.auth = { authMode: AuthMode.IDENTITY_ACCESS_TOKEN, actor, @@ -106,9 +97,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => { break; } case AuthMode.SERVICE_TOKEN: { - const serviceToken = await server.services.serviceToken.fnValidateServiceToken( - token as string - ); + const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token); req.auth = { authMode: AuthMode.SERVICE_TOKEN as const, serviceToken, diff --git a/backend/src/server/plugins/auth/superAdmin.ts b/backend/src/server/plugins/auth/superAdmin.ts index 2cd7181bd8..d5dee581b8 100644 --- a/backend/src/server/plugins/auth/superAdmin.ts +++ b/backend/src/server/plugins/auth/superAdmin.ts @@ -1,12 +1,17 @@ -import { FastifyRequest } from "fastify"; +import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify"; import { UnauthorizedError } from "@app/lib/errors"; import { ActorType } from "@app/services/auth/auth-type"; -export const verifySuperAdmin = async (req: T) => { +export const verifySuperAdmin = ( + req: T, + _res: FastifyReply, + done: HookHandlerDoneFunction +) => { if (req.auth.actor !== ActorType.USER || !req.auth.user.superAdmin) throw new UnauthorizedError({ name: "Unauthorized access", message: "Requires superadmin access" }); + done(); }; diff --git a/backend/src/server/plugins/auth/verify-auth.ts b/backend/src/server/plugins/auth/verify-auth.ts index cfd856dbe7..a1274f356e 100644 --- a/backend/src/server/plugins/auth/verify-auth.ts +++ b/backend/src/server/plugins/auth/verify-auth.ts @@ -1,17 +1,17 @@ -import { FastifyRequest } from "fastify"; +import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify"; import { UnauthorizedError } from "@app/lib/errors"; import { AuthMode } from "@app/services/auth/auth-type"; export const verifyAuth = (authStrats: AuthMode[]) => - async (req: T) => { + (req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => { if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array"); - if (!req.auth) - throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" }); + if (!req.auth) throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" }); const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode); if (!isAccessAllowed) { throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` }); } + done(); }; diff --git a/backend/src/server/plugins/error-handler.ts b/backend/src/server/plugins/error-handler.ts index cacc91885e..8587c93bd8 100644 --- a/backend/src/server/plugins/error-handler.ts +++ b/backend/src/server/plugins/error-handler.ts @@ -2,33 +2,27 @@ import { ForbiddenError } from "@casl/ability"; import fastifyPlugin from "fastify-plugin"; import { ZodError } from "zod"; -import { - BadRequestError, - DatabaseError, - ForbiddenRequestError, - InternalServerError, - UnauthorizedError -} from "@app/lib/errors"; +import { BadRequestError, DatabaseError, InternalServerError, UnauthorizedError } from "@app/lib/errors"; export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => { server.setErrorHandler((error, req, res) => { req.log.error(error); if (error instanceof BadRequestError) { - res.status(400).send({ statusCode: 400, message: error.message, error: error.name }); + void res.status(400).send({ statusCode: 400, message: error.message, error: error.name }); } else if (error instanceof UnauthorizedError) { - res.status(403).send({ statusCode: 403, message: error.message, error: error.name }); + void res.status(403).send({ statusCode: 403, message: error.message, error: error.name }); } else if (error instanceof DatabaseError || error instanceof InternalServerError) { - res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name }); + void res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name }); } else if (error instanceof ZodError) { - res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues }); + void res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues }); } else if (error instanceof ForbiddenError) { - res.status(401).send({ + void res.status(401).send({ statusCode: 401, error: "PermissionDenied", message: `You are not allowed to ${error.action} on ${error.subjectType}` }); } else { - res.send(error); + void res.send(error); } }); }); diff --git a/backend/src/server/plugins/external-nextjs.ts b/backend/src/server/plugins/external-nextjs.ts index 010e92f96f..89cf451254 100644 --- a/backend/src/server/plugins/external-nextjs.ts +++ b/backend/src/server/plugins/external-nextjs.ts @@ -20,17 +20,19 @@ export const registerExternalNextjs = async ( if (standaloneMode) { const nextJsBuildPath = path.join(dir, "frontend-build"); - const { default: conf } = await import( + const { default: conf } = (await import( path.join(dir, "frontend-build/.next/required-server-files.json"), // @ts-expect-error type { assert: { type: "json" } } - ); + )) as { default: { config: string } }; + /* eslint-disable */ const { default: NextServer } = ( await import(path.join(dir, "frontend-build/node_modules/next/dist/server/next-server.js")) ).default; + const nextApp = new NextServer({ dev: false, dir: nextJsBuildPath, @@ -52,5 +54,6 @@ export const registerExternalNextjs = async ( }); server.addHook("onClose", () => nextApp.close()); await nextApp.prepare(); + /* eslint-enable */ } }; diff --git a/backend/src/server/plugins/secret-scanner.ts b/backend/src/server/plugins/secret-scanner.ts index f90b391147..8790d54d4e 100644 --- a/backend/src/server/plugins/secret-scanner.ts +++ b/backend/src/server/plugins/secret-scanner.ts @@ -1,3 +1,4 @@ +import { PushEvent } from "@octokit/webhooks-types"; import { Probot } from "probot"; import SmeeClient from "smee-client"; @@ -22,7 +23,7 @@ export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => app.on("push", async (context) => { const { payload } = context; - await server.services.secretScanning.handleRepoPushEvent(payload as any); + await server.services.secretScanning.handleRepoPushEvent(payload as PushEvent); }); }; @@ -49,16 +50,17 @@ export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => method: "POST", url: "/", handler: async (req, res) => { - const eventName = req.headers["x-github-event"] as any; + const eventName = req.headers["x-github-event"]; const signatureSHA256 = req.headers["x-hub-signature-256"] as string; const id = req.headers["x-github-delivery"] as string; await probot.webhooks.verifyAndReceive({ id, + // @ts-expect-error type name: eventName, payload: req.body as string, signature: signatureSHA256 }); - res.send("ok"); + void res.send("ok"); } }); } diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index f6971b7ea0..113060b65f 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -92,10 +92,7 @@ import { serviceTokenDALFactory } from "@app/services/service-token/service-toke import { serviceTokenServiceFactory } from "@app/services/service-token/service-token-service"; import { TSmtpService } from "@app/services/smtp/smtp-service"; import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; -import { - getServerCfg, - superAdminServiceFactory -} from "@app/services/super-admin/super-admin-service"; +import { getServerCfg, superAdminServiceFactory } from "@app/services/super-admin/super-admin-service"; import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service"; import { userDALFactory } from "@app/services/user/user-dal"; import { userServiceFactory } from "@app/services/user/user-service"; @@ -112,13 +109,9 @@ import { registerV3Routes } from "./v3"; export const registerRoutes = async ( server: FastifyZodProvider, - { - db, - smtp: smtpService, - queue: queueService - }: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory } + { db, smtp: smtpService, queue: queueService }: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory } ) => { - server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" }); + await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" }); // db layers const userDAL = userDALFactory(db); diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index e5ea127c5c..b8b61216bf 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -39,10 +39,10 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: (req, _, done) => { - verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req); - verifySuperAdmin(req); - done(); + onRequest: (req, res, done) => { + verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req, res, () => { + verifySuperAdmin(req, res, done); + }); }, handler: async (req) => { const config = await server.services.superAdmin.updateServerCfg(req.body); @@ -97,7 +97,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { } }); - res.setCookie("jid", token.refresh, { + void res.setCookie("jid", token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v1/auth-router.ts b/backend/src/server/routes/v1/auth-router.ts index 871b56c1f0..2dc0a5d50b 100644 --- a/backend/src/server/routes/v1/auth-router.ts +++ b/backend/src/server/routes/v1/auth-router.ts @@ -5,18 +5,14 @@ import { getConfig } from "@app/lib/config/env"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; import { authRateLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; -import { - AuthMode, - AuthModeRefreshJwtTokenPayload, - AuthTokenType -} from "@app/services/auth/auth-type"; +import { AuthMode, AuthModeRefreshJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; export const registerAuthRoutes = async (server: FastifyZodProvider) => { server.route({ url: "/logout", method: "POST", - config:{ - rateLimit:authRateLimit + config: { + rateLimit: authRateLimit }, schema: { response: { @@ -31,7 +27,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => { if (req.auth.authMode === AuthMode.JWT) { await server.services.login.logout(req.permission.id, req.auth.tokenVersionId); } - res.cookie("jid", "", { + void res.cookie("jid", "", { httpOnly: true, path: "/", sameSite: "strict", @@ -74,10 +70,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => { message: "Failed to find refresh token" }); - const decodedToken = jwt.verify( - refreshToken, - appCfg.AUTH_SECRET - ) as AuthModeRefreshJwtTokenPayload; + const decodedToken = jwt.verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload; if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN) throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" }); @@ -85,8 +78,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => { decodedToken.tokenVersionId, decodedToken.userId ); - if (!tokenVersion) - throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" }); + if (!tokenVersion) throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" }); if (decodedToken.refreshVersion !== tokenVersion.refreshVersion) throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" }); diff --git a/backend/src/server/routes/v1/identity-access-token-router.ts b/backend/src/server/routes/v1/identity-access-token-router.ts index b39fe08a2d..4ddf7b74a9 100644 --- a/backend/src/server/routes/v1/identity-access-token-router.ts +++ b/backend/src/server/routes/v1/identity-access-token-router.ts @@ -18,10 +18,9 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid } }, handler: async (req) => { - const { accessToken, identityAccessToken } = - await server.services.identityAccessToken.renewAccessToken({ - accessToken: req.body.accessToken - }); + const { accessToken, identityAccessToken } = await server.services.identityAccessToken.renewAccessToken({ + accessToken: req.body.accessToken + }); return { accessToken, tokenType: "Bearer" as const, diff --git a/backend/src/server/routes/v1/identity-ua.ts b/backend/src/server/routes/v1/identity-ua.ts index 1c7c6e5f7b..d92d2a61a5 100644 --- a/backend/src/server/routes/v1/identity-ua.ts +++ b/backend/src/server/routes/v1/identity-ua.ts @@ -39,11 +39,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, handler: async (req) => { const { identityUa, accessToken, identityAccessToken, validClientSecretInfo } = - await server.services.identityUa.login( - req.body.clientId, - req.body.clientSecret, - req.realIp - ); + await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, @@ -128,10 +124,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { identityId: identityUniversalAuth.identityId, accessTokenTTL: identityUniversalAuth.accessTokenTTL, accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL, - accessTokenTrustedIps: - identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[], - clientSecretTrustedIps: - identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[], + accessTokenTrustedIps: identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[], + clientSecretTrustedIps: identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[], accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit } } @@ -197,10 +191,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { identityId: identityUniversalAuth.identityId, accessTokenTTL: identityUniversalAuth.accessTokenTTL, accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL, - accessTokenTrustedIps: - identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[], - clientSecretTrustedIps: - identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[], + accessTokenTrustedIps: identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[], + clientSecretTrustedIps: identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[], accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit } } @@ -267,13 +259,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { clientSecret, clientSecretData, orgId } = - await server.services.identityUa.createUaClientSecret({ - actor: req.permission.type, - actorId: req.permission.id, - identityId: req.params.identityId, - ...req.body - }); + const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({ + actor: req.permission.type, + actorId: req.permission.id, + identityId: req.params.identityId, + ...req.body + }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, @@ -306,12 +297,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { clientSecrets: clientSecretData, orgId } = - await server.services.identityUa.getUaClientSecrets({ - actor: req.permission.type, - actorId: req.permission.id, - identityId: req.params.identityId - }); + const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({ + actor: req.permission.type, + actorId: req.permission.id, + identityId: req.params.identityId + }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, diff --git a/backend/src/server/routes/v1/integration-router.ts b/backend/src/server/routes/v1/integration-router.ts index db73bf293e..a7df57a543 100644 --- a/backend/src/server/routes/v1/integration-router.ts +++ b/backend/src/server/routes/v1/integration-router.ts @@ -57,6 +57,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { projectId: integrationAuth.projectId, event: { type: EventType.CREATE_INTEGRATION, + // eslint-disable-next-line metadata: shake({ integrationId: integration.id.toString(), integration: integration.integration, @@ -71,6 +72,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { targetServiceId: integration.targetServiceId, path: integration.path, region: integration.region + // eslint-disable-next-line }) as any } }); @@ -138,6 +140,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { projectId: integration.projectId, event: { type: EventType.DELETE_INTEGRATION, + // eslint-disable-next-line metadata: shake({ integrationId: integration.id, integration: integration.integration, @@ -152,6 +155,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { targetServiceId: integration.targetServiceId, path: integration.path, region: integration.region + // eslint-disable-next-line }) as any } }); diff --git a/backend/src/server/routes/v1/organization-router.ts b/backend/src/server/routes/v1/organization-router.ts index f5fd06c87a..1d74e8b1a8 100644 --- a/backend/src/server/routes/v1/organization-router.ts +++ b/backend/src/server/routes/v1/organization-router.ts @@ -1,11 +1,6 @@ import { z } from "zod"; -import { - IncidentContactsSchema, - OrganizationsSchema, - OrgMembershipsSchema, - UsersSchema -} from "@app/db/schemas"; +import { IncidentContactsSchema, OrganizationsSchema, OrgMembershipsSchema, UsersSchema } from "@app/db/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -42,10 +37,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const organization = await server.services.org.findOrganizationById( - req.permission.id, - req.params.organizationId - ); + const organization = await server.services.org.findOrganizationById(req.permission.id, req.params.organizationId); return { organization }; } }); @@ -76,10 +68,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const users = await server.services.org.findAllOrgMembers( - req.permission.id, - req.params.organizationId - ); + const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId); return { users }; } }); diff --git a/backend/src/server/routes/v1/password-router.ts b/backend/src/server/routes/v1/password-router.ts index 8ec7697f75..d5c5054df0 100644 --- a/backend/src/server/routes/v1/password-router.ts +++ b/backend/src/server/routes/v1/password-router.ts @@ -12,7 +12,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/srp1", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -39,7 +39,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/change-password", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -64,7 +64,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { const appCfg = getConfig(); await server.services.password.changePassword({ ...req.body, userId: req.permission.id }); - res.cookie("jid", appCfg.COOKIE_SECRET_SIGN_KEY, { + void res.cookie("jid", appCfg.COOKIE_SECRET_SIGN_KEY, { httpOnly: true, path: "/", sameSite: "strict", @@ -78,7 +78,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/email/password-reset", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -103,7 +103,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/email/password-reset-verify", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -119,10 +119,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { token, user } = await server.services.password.verifyPasswordResetEmail( - req.body.email, - req.body.code - ); + const { token, user } = await server.services.password.verifyPasswordResetEmail(req.body.email, req.body.code); return { message: "Successfully verified email", @@ -136,7 +133,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/backup-private-key", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, onRequest: verifyAuth([AuthMode.JWT]), schema: { @@ -156,10 +153,10 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; const backupPrivateKey = await server.services.password.createBackupPrivateKey({ ...req.body, - userId: token.userId, + userId: token.userId }); if (!backupPrivateKey) throw new Error("Failed to create backup key"); @@ -171,7 +168,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "GET", url: "/backup-private-key", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { response: { @@ -182,10 +179,8 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! - const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser( - token.userId - ); + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; + const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser(token.userId); if (!backupPrivateKey) throw new Error("Failed to find backup key"); return { message: "Successfully fetched backup private key", backupPrivateKey }; @@ -213,10 +208,10 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; await server.services.password.resetPasswordByBackupKey({ ...req.body, - userId: token.userId, + userId: token.userId }); return { message: "Successfully updated backup private key" }; diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index bacfcb1bbd..7d28f470a3 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -1,11 +1,6 @@ import { z } from "zod"; -import { - OrgMembershipsSchema, - ProjectMembershipsSchema, - UserEncryptionKeysSchema, - UsersSchema -} from "@app/db/schemas"; +import { OrgMembershipsSchema, ProjectMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index 5e8ee8b46d..b7574e35ce 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -255,7 +255,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ invitee: UsersSchema, - latestKey: ProjectKeysSchema + latestKey: ProjectKeysSchema.optional() }) } }, diff --git a/backend/src/server/routes/v1/secret-folder-router.ts b/backend/src/server/routes/v1/secret-folder-router.ts index c717678682..4a152f52e3 100644 --- a/backend/src/server/routes/v1/secret-folder-router.ts +++ b/backend/src/server/routes/v1/secret-folder-router.ts @@ -25,12 +25,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const path = req.body.path || req.body.directory; const folder = await server.services.folder.createFolder({ @@ -79,12 +74,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const path = req.body.path || req.body.directory; const { folder, old } = await server.services.folder.updateFolder({ @@ -133,12 +123,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const path = req.body.path || req.body.directory; const folder = await server.services.folder.deleteFolder({ @@ -183,12 +168,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const path = req.query.path || req.query.directory; const folders = await server.services.folder.getFolders({ diff --git a/backend/src/server/routes/v1/secret-import-router.ts b/backend/src/server/routes/v1/secret-import-router.ts index f27f9e0c2e..80f980a901 100644 --- a/backend/src/server/routes/v1/secret-import-router.ts +++ b/backend/src/server/routes/v1/secret-import-router.ts @@ -31,12 +31,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secretImport = await server.services.secretImport.createImport({ actorId: req.permission.id, @@ -97,12 +92,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secretImport = await server.services.secretImport.updateImport({ actorId: req.permission.id, @@ -155,12 +145,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secretImport = await server.services.secretImport.deleteImport({ actorId: req.permission.id, @@ -211,12 +196,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secretImports = await server.services.secretImport.getImports({ actorId: req.permission.id, @@ -268,12 +248,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const importedSecrets = await server.services.secretImport.getSecretsFromImports({ actorId: req.permission.id, diff --git a/backend/src/server/routes/v1/sso-router.ts b/backend/src/server/routes/v1/sso-router.ts index f3d5288b01..9c7c85b04d 100644 --- a/backend/src/server/routes/v1/sso-router.ts +++ b/backend/src/server/routes/v1/sso-router.ts @@ -1,3 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +// All the any rules are disabled because passport typesense with fastify is really poor + import { Authenticator } from "@fastify/passport"; import fastifySession from "@fastify/session"; import { Strategy as GitHubStrategy } from "passport-github"; @@ -19,9 +27,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { await server.register(passport.initialize()); await server.register(passport.secureSession()); // passport oauth strategy for Google - const isGoogleOauthActive = Boolean( - appCfg.CLIENT_ID_GOOGLE_LOGIN && appCfg.CLIENT_SECRET_GOOGLE_LOGIN - ); + const isGoogleOauthActive = Boolean(appCfg.CLIENT_ID_GOOGLE_LOGIN && appCfg.CLIENT_SECRET_GOOGLE_LOGIN); if (isGoogleOauthActive) { passport.use( new GoogleStrategy( @@ -32,6 +38,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { callbackURL: `${appCfg.SITE_URL}/api/v1/sso/google`, scope: ["profile", " email"] }, + // eslint-disable-next-line async (req, _accessToken, _refreshToken, profile, cb) => { try { const email = profile?.emails?.[0]?.value; @@ -61,9 +68,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { } // Passport strategy for Github - const isGithubOauthActive = Boolean( - appCfg.CLIENT_SECRET_GITHUB_LOGIN && appCfg.CLIENT_ID_GITHUB_LOGIN - ); + const isGithubOauthActive = Boolean(appCfg.CLIENT_SECRET_GITHUB_LOGIN && appCfg.CLIENT_ID_GITHUB_LOGIN); if (isGithubOauthActive) { passport.use( new GitHubStrategy( @@ -74,6 +79,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`, scope: ["user:email"] }, + // eslint-disable-next-line async (req, accessToken, _refreshToken, profile, cb) => { try { const ghEmails = await fetchGithubEmails(accessToken); @@ -99,9 +105,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { // passport strategy for gitlab const isGitlabOauthActive = Boolean( - appCfg.CLIENT_ID_GITLAB_LOGIN && - appCfg.CLIENT_SECRET_GITLAB_LOGIN && - appCfg.CLIENT_GITLAB_LOGIN_URL + appCfg.CLIENT_ID_GITLAB_LOGIN && appCfg.CLIENT_SECRET_GITLAB_LOGIN && appCfg.CLIENT_GITLAB_LOGIN_URL ); if (isGitlabOauthActive) { passport.use( @@ -152,6 +156,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { state: req.query.callback_port, authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any )(req, res), handler: () => {} @@ -165,19 +170,15 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { failureRedirect: "/login/provider/error", authInfo: false // this is due to zod type difference - }) as any, + }) as never, handler: (req, res) => { if (req.passportUser.isUserCompleted) { return res.redirect( - `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } return res.redirect( - `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } }); @@ -214,15 +215,11 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { handler: (req, res) => { if (req.passportUser.isUserCompleted) { return res.redirect( - `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } return res.redirect( - `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } }); @@ -242,6 +239,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { state: req.query.callback_port, authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any )(req, res), handler: () => {} @@ -255,19 +253,16 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { failureRedirect: "/login/provider/error", authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any, handler: (req, res) => { if (req.passportUser.isUserCompleted) { return res.redirect( - `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } return res.redirect( - `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent( - req.passportUser.providerAuthToken - )}` + `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` ); } }); diff --git a/backend/src/server/routes/v1/user-action-router.ts b/backend/src/server/routes/v1/user-action-router.ts index 5ce66eb794..c730cdb91d 100644 --- a/backend/src/server/routes/v1/user-action-router.ts +++ b/backend/src/server/routes/v1/user-action-router.ts @@ -21,10 +21,7 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const userAction = await server.services.user.createUserAction( - req.permission.id, - req.body.action - ); + const userAction = await server.services.user.createUserAction(req.permission.id, req.body.action); return { userAction, message: "Successfully recorded user action" }; } }); @@ -44,10 +41,7 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const userAction = await server.services.user.getUserAction( - req.permission.id, - req.query.action - ); + const userAction = await server.services.user.getUserAction(req.permission.id, req.query.action); return { userAction }; } }); diff --git a/backend/src/server/routes/v1/webhook-router.ts b/backend/src/server/routes/v1/webhook-router.ts index 558192f68b..2b3e663982 100644 --- a/backend/src/server/routes/v1/webhook-router.ts +++ b/backend/src/server/routes/v1/webhook-router.ts @@ -183,7 +183,11 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { querystring: z.object({ workspaceId: z.string().trim(), environment: z.string().trim().optional(), - secretPath: z.string().trim().optional().transform((val)=> val?removeTrailingSlash(val):val) + secretPath: z + .string() + .trim() + .optional() + .transform((val) => (val ? removeTrailingSlash(val) : val)) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/index.ts b/backend/src/server/routes/v2/index.ts index a73f9de528..1f423c084f 100644 --- a/backend/src/server/routes/v2/index.ts +++ b/backend/src/server/routes/v2/index.ts @@ -19,8 +19,8 @@ export const registerV2Routes = async (server: FastifyZodProvider) => { ); await server.register( async (projectServer) => { - projectServer.register(registerProjectRouter); - projectServer.register(registerIdentityProjectRouter); + await projectServer.register(registerProjectRouter); + await projectServer.register(registerIdentityProjectRouter); }, { prefix: "/workspace" } ); diff --git a/backend/src/server/routes/v2/mfa-router.ts b/backend/src/server/routes/v2/mfa-router.ts index 02006a4704..cbe7f1cbfe 100644 --- a/backend/src/server/routes/v2/mfa-router.ts +++ b/backend/src/server/routes/v2/mfa-router.ts @@ -1,8 +1,8 @@ -import jwt, { JwtPayload } from "jsonwebtoken"; +import jwt from "jsonwebtoken"; import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; -import { AuthTokenType } from "@app/services/auth/auth-type"; +import { AuthModeMfaJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; export const registerMfaRouter = async (server: FastifyZodProvider) => { const cfg = getConfig(); @@ -12,18 +12,17 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { const authorizationHeader = req.headers.authorization; if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) { - res.status(401).send({ error: "Missing bearer token" }); + void res.status(401).send({ error: "Missing bearer token" }); return res; } const token = authorizationHeader.split(" ")[1]; if (!token) { - res.status(401).send({ error: "Missing bearer token" }); + void res.status(401).send({ error: "Missing bearer token" }); return res; } - const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as JwtPayload; - if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) - throw new Error("Unauthorized access"); + const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as AuthModeMfaJwtTokenPayload; + if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) throw new Error("Unauthorized access"); const user = await server.store.user.findById(decodedToken.userId); if (!user) throw new Error("User not found"); @@ -79,7 +78,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { mfaToken: req.body.mfaToken }); - res.setCookie("jid", token.refresh, { + void res.setCookie("jid", token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v2/organization-router.ts b/backend/src/server/routes/v2/organization-router.ts index d2fa7d4502..667ef406ee 100644 --- a/backend/src/server/routes/v2/organization-router.ts +++ b/backend/src/server/routes/v2/organization-router.ts @@ -1,11 +1,6 @@ import { z } from "zod"; -import { - OrganizationsSchema, - OrgMembershipsSchema, - UserEncryptionKeysSchema, - UsersSchema -} from "@app/db/schemas"; +import { OrganizationsSchema, OrgMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { ActorType, AuthMode } from "@app/services/auth/auth-type"; @@ -38,10 +33,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { handler: async (req) => { if (req.auth.actor !== ActorType.USER) return; - const users = await server.services.org.findAllOrgMembers( - req.permission.id, - req.params.organizationId - ); + const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId); return { users }; } }); diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/project-router.ts index 86f25d89d7..e90a360600 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/project-router.ts @@ -37,7 +37,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { event: { type: EventType.GET_WORKSPACE_KEY, metadata: { - keyId: key.id + keyId: key?.id as string } } }); diff --git a/backend/src/server/routes/v2/user-router.ts b/backend/src/server/routes/v2/user-router.ts index 071a70539a..8061aa0e55 100644 --- a/backend/src/server/routes/v2/user-router.ts +++ b/backend/src/server/routes/v2/user-router.ts @@ -1,11 +1,6 @@ import { z } from "zod"; -import { - AuthTokenSessionsSchema, - OrganizationsSchema, - UserEncryptionKeysSchema, - UsersSchema -} from "@app/db/schemas"; +import { AuthTokenSessionsSchema, OrganizationsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; import { ApiKeysSchema } from "@app/db/schemas/api-keys"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMethod, AuthMode } from "@app/services/auth/auth-type"; @@ -47,11 +42,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => { }, preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]), handler: async (req) => { - const user = await server.services.user.updateUserName( - req.permission.id, - req.body.firstName, - req.body.lastName - ); + const user = await server.services.user.updateUserName(req.permission.id, req.body.firstName, req.body.lastName); return { user }; } }); @@ -71,10 +62,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => { }, preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]), handler: async (req) => { - const user = await server.services.user.updateAuthMethods( - req.permission.id, - req.body.authMethods - ); + const user = await server.services.user.updateAuthMethods(req.permission.id, req.body.authMethods); return { user }; } }); @@ -128,11 +116,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const apiKeys = await server.services.apiKey.createApiKey( - req.permission.id, - req.body.name, - req.body.expiresIn - ); + const apiKeys = await server.services.apiKey.createApiKey(req.permission.id, req.body.name, req.body.expiresIn); return apiKeys; } }); @@ -152,10 +136,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const apiKeyData = await server.services.apiKey.deleteApiKey( - req.permission.id, - req.params.apiKeyDataId - ); + const apiKeyData = await server.services.apiKey.deleteApiKey(req.permission.id, req.params.apiKeyDataId); return { apiKeyData }; } }); diff --git a/backend/src/server/routes/v3/login-router.ts b/backend/src/server/routes/v3/login-router.ts index 1c513c183c..0cda8e5fff 100644 --- a/backend/src/server/routes/v3/login-router.ts +++ b/backend/src/server/routes/v3/login-router.ts @@ -81,7 +81,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { return { mfaEnabled: true, token: data.token } as const; // for discriminated union } - res.setCookie("jid", data.token.refresh, { + void res.setCookie("jid", data.token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index db14eb0f60..8df8533b8c 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -61,12 +61,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { // just for delivery hero usecase let { secretPath, environment, workspaceId } = req.query; @@ -80,8 +75,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } } - if (!workspaceId || !environment) - throw new BadRequestError({ message: "Missing workspace id or environment" }); + if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" }); const { secrets, imports } = await server.services.secret.getSecretsRaw({ actorId: req.permission.id, @@ -144,12 +138,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { let { secretPath, environment, workspaceId } = req.query; if (req.auth.actor === ActorType.SERVICE) { @@ -162,8 +151,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } } - if (!workspaceId || !environment) - throw new BadRequestError({ message: "Missing workspace id or environment" }); + if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" }); const secret = await server.services.secret.getSecretByNameRaw({ actorId: req.permission.id, @@ -218,9 +206,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { workspaceId: z.string().trim(), environment: z.string().trim(), secretPath: z.string().trim().default("/").transform(removeTrailingSlash), - secretValue: z - .string() - .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), + secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), secretComment: z.string().trim().optional().default(""), skipMultilineEncoding: z.boolean().optional(), type: z.nativeEnum(SecretType).default(SecretType.Shared) @@ -231,12 +217,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secret = await server.services.secret.createSecretRaw({ actorId: req.permission.id, @@ -293,9 +274,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { body: z.object({ workspaceId: z.string().trim(), environment: z.string().trim(), - secretValue: z - .string() - .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), + secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), secretPath: z.string().trim().default("/").transform(removeTrailingSlash), skipMultilineEncoding: z.boolean().optional(), type: z.nativeEnum(SecretType).default(SecretType.Shared) @@ -306,12 +285,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secret = await server.services.secret.updateSecretRaw({ actorId: req.permission.id, @@ -375,12 +349,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secret = await server.services.secret.deleteSecretRaw({ actorId: req.permission.id, @@ -474,12 +443,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { secrets, imports } = await server.services.secret.getSecrets({ actorId: req.permission.id, @@ -549,12 +513,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const secret = await server.services.secret.getSecretByName({ actorId: req.permission.id, @@ -634,18 +593,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) ) }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { workspaceId: projectId, @@ -673,32 +625,31 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Create]: [ - { - secretName: req.params.secretName, - secretValueCiphertext, - secretValueIV, - secretValueTag, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretKeyTag, - secretKeyCiphertext, - secretKeyIV - } - ] - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Create]: [ + { + secretName: req.params.secretName, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretCommentIV, + secretCommentTag, + secretCommentCiphertext, + skipMultilineEncoding, + secretKeyTag, + secretKeyCiphertext, + secretKeyIV + } + ] + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, @@ -810,18 +761,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) ) }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { secretValueCiphertext, @@ -854,34 +798,33 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Update]: [ - { - secretName: req.params.secretName, - newSecretName, - secretValueCiphertext, - secretValueIV, - secretValueTag, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretKeyTag, - secretKeyCiphertext, - secretKeyIV, - tagIds: tags - } - ] - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Update]: [ + { + secretName: req.params.secretName, + newSecretName, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretCommentIV, + secretCommentTag, + secretCommentCiphertext, + skipMultilineEncoding, + secretKeyTag, + secretKeyCiphertext, + secretKeyIV, + tagIds: tags + } + ] + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, @@ -980,18 +923,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }) ) }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { secretPath, type, workspaceId: projectId, secretId, environment } = req.body; if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) { @@ -1003,22 +939,21 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Delete]: [ - { - secretName: req.params.secretName - } - ] - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Delete]: [ + { + secretName: req.params.secretName + } + ] + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, @@ -1110,18 +1045,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { z.object({ secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body; if (req.permission.type === ActorType.USER) { @@ -1133,18 +1061,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared") - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared") + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, @@ -1236,18 +1163,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { z.object({ secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body; if (req.permission.type === ActorType.USER) { @@ -1259,18 +1179,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared") - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared") + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, @@ -1350,18 +1269,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { z.object({ secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() }), - z - .object({ approval: SecretApprovalRequestsSchema }) - .describe("When secret protection policy is enabled") + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") ]) } }, - onRequest: verifyAuth([ - AuthMode.JWT, - AuthMode.API_KEY, - AuthMode.SERVICE_TOKEN, - AuthMode.IDENTITY_ACCESS_TOKEN - ]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body; if (req.permission.type === ActorType.USER) { @@ -1373,18 +1285,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { projectId }); if (policy) { - const approval = - await server.services.secretApprovalRequest.generateSecretApprovalRequest({ - actorId: req.permission.id, - actor: req.permission.type, - secretPath, - environment, - projectId, - policy, - data: { - [CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared") - } - }); + const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ + actorId: req.permission.id, + actor: req.permission.type, + secretPath, + environment, + projectId, + policy, + data: { + [CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared") + } + }); await server.services.auditLog.createAuditLog({ projectId: req.body.workspaceId, ...req.auditLogInfo, diff --git a/backend/src/server/routes/v3/signup-router.ts b/backend/src/server/routes/v3/signup-router.ts index fe64a4ec22..0640685078 100644 --- a/backend/src/server/routes/v3/signup-router.ts +++ b/backend/src/server/routes/v3/signup-router.ts @@ -48,10 +48,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { token, user } = await server.services.signup.verifyEmailSignup( - req.body.email, - req.body.code - ); + const { token, user } = await server.services.signup.verifyEmailSignup(req.body.email, req.body.code); return { message: "Successfuly verified email", token, user }; } }); @@ -93,21 +90,16 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { if (!userAgent) throw new Error("user agent header is required"); const appCfg = getConfig(); - const { user, accessToken, refreshToken } = - await server.services.signup.completeEmailAccountSignup({ - ...req.body, - ip: req.realIp, - userAgent, - authorization: req.headers.authorization as string - }); + const { user, accessToken, refreshToken } = await server.services.signup.completeEmailAccountSignup({ + ...req.body, + ip: req.realIp, + userAgent, + authorization: req.headers.authorization as string + }); - server.services.telemetry.sendLoopsEvent( - user.email, - user.firstName || "", - user.lastName || "" - ); + void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || ""); - server.services.telemetry.sendPostHogEvents({ + void server.services.telemetry.sendPostHogEvents({ event: PostHogEventTypes.UserSignedUp, distinctId: user.email, properties: { @@ -116,7 +108,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { } }); - res.setCookie("jid", refreshToken, { + await res.setCookie("jid", refreshToken, { httpOnly: true, path: "/", sameSite: "strict", @@ -161,14 +153,13 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { if (!userAgent) throw new Error("user agent header is required"); const appCfg = getConfig(); - const { user, accessToken, refreshToken } = - await server.services.signup.completeAccountInvite({ - ...req.body, - ip: req.realIp, - userAgent - }); + const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({ + ...req.body, + ip: req.realIp, + userAgent + }); - res.setCookie("jid", refreshToken, { + await res.setCookie("jid", refreshToken, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/services/api-key/api-key-service.ts b/backend/src/services/api-key/api-key-service.ts index 23057e1a47..39ccbecce7 100644 --- a/backend/src/services/api-key/api-key-service.ts +++ b/backend/src/services/api-key/api-key-service.ts @@ -45,8 +45,7 @@ export const apiKeyServiceFactory = ({ apiKeyDAL, userDAL }: TApiKeyServiceFacto const deleteApiKey = async (userId: string, apiKeyId: string) => { const [apiKeyData] = await apiKeyDAL.delete({ id: apiKeyId, userId }); - if (!apiKeyData) - throw new BadRequestError({ message: "Failed to find api key", name: "delete api key" }); + if (!apiKeyData) throw new BadRequestError({ message: "Failed to find api key", name: "delete api key" }); return formatApiKey(apiKeyData); }; diff --git a/backend/src/services/auth-token/auth-token-dal.ts b/backend/src/services/auth-token/auth-token-dal.ts index edd8ef74c1..075ae73846 100644 --- a/backend/src/services/auth-token/auth-token-dal.ts +++ b/backend/src/services/auth-token/auth-token-dal.ts @@ -7,16 +7,12 @@ import { ormify } from "@app/lib/knex"; import { TDeleteTokenForUserDALDTO } from "./auth-token-types"; -export type TTokenDALConfig = {}; - export type TTokenDALFactory = ReturnType; export const tokenDALFactory = (db: TDbClient) => { const authOrm = ormify(db, TableName.AuthTokens); - const findOneTokenSession = async ( - filter: Partial - ): Promise => { + const findOneTokenSession = async (filter: Partial): Promise => { try { const doc = await db(TableName.AuthTokenSession).where(filter).first(); return doc; @@ -31,20 +27,14 @@ export const tokenDALFactory = (db: TDbClient) => { orgId }: TDeleteTokenForUserDALDTO): Promise => { try { - const doc = await db(TableName.AuthTokens) - .where({ userId, type, orgId }) - .delete() - .returning("*"); + const doc = await db(TableName.AuthTokens).where({ userId, type, orgId }).delete().returning("*"); return doc; } catch (error) { throw new DatabaseError({ error, name: "DeleteTokenForUser" }); } }; - const decrementTriesField = async ({ - userId, - type - }: TDeleteTokenForUserDALDTO): Promise => { + const decrementTriesField = async ({ userId, type }: TDeleteTokenForUserDALDTO): Promise => { try { await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1); } catch (error) { @@ -101,10 +91,7 @@ export const tokenDALFactory = (db: TDbClient) => { const deleteTokenSession = async (filter: Partial, tx?: Knex) => { try { - const sessions = await (tx || db)(TableName.AuthTokenSession) - .where(filter) - .del() - .returning("*"); + const sessions = await (tx || db)(TableName.AuthTokenSession).where(filter).del().returning("*"); return sessions; } catch (error) { throw new DatabaseError({ name: "Delete token session", error }); diff --git a/backend/src/services/auth-token/auth-token-service.ts b/backend/src/services/auth-token/auth-token-service.ts index d196912090..7fae75c303 100644 --- a/backend/src/services/auth-token/auth-token-service.ts +++ b/backend/src/services/auth-token/auth-token-service.ts @@ -9,12 +9,7 @@ import { UnauthorizedError } from "@app/lib/errors"; import { AuthModeJwtTokenPayload } from "../auth/auth-type"; import { TUserDALFactory } from "../user/user-dal"; import { TTokenDALFactory } from "./auth-token-dal"; -import { - TCreateTokenForUserDTO, - TIssueAuthTokenDTO, - TokenType, - TValidateTokenForUserDTO -} from "./auth-token-types"; +import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types"; type TAuthTokenServiceFactoryDep = { tokenDAL: TTokenDALFactory; @@ -125,14 +120,10 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact return session; }; - const clearTokenSessionById = async ( - userId: string, - sessionId: string - ): Promise => + const clearTokenSessionById = async (userId: string, sessionId: string): Promise => tokenDAL.incrementTokenSessionVersion(userId, sessionId); - const getUserTokenSessionById = async (id: string, userId: string) => - tokenDAL.findOneTokenSession({ id, userId }); + const getUserTokenSessionById = async (id: string, userId: string) => tokenDAL.findOneTokenSession({ id, userId }); const getTokenSessionByUser = async (userId: string) => tokenDAL.findTokenSessions({ userId }); @@ -145,8 +136,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact userId: token.userId }); if (!session) throw new UnauthorizedError({ name: "Session not found" }); - if (token.accessVersion !== session.accessVersion) - throw new UnauthorizedError({ name: "Stale session" }); + if (token.accessVersion !== session.accessVersion) throw new UnauthorizedError({ name: "Stale session" }); const user = await userDAL.findById(session.userId); if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" }); diff --git a/backend/src/services/auth/auth-fns.ts b/backend/src/services/auth/auth-fns.ts index 91f34345c2..3e65f7e055 100644 --- a/backend/src/services/auth/auth-fns.ts +++ b/backend/src/services/auth/auth-fns.ts @@ -3,19 +3,12 @@ import jwt from "jsonwebtoken"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; -import { - AuthModeProviderJwtTokenPayload, - AuthModeProviderSignUpTokenPayload, - AuthTokenType -} from "./auth-type"; +import { AuthModeProviderJwtTokenPayload, AuthModeProviderSignUpTokenPayload, AuthTokenType } from "./auth-type"; export const validateProviderAuthToken = (providerToken: string, email: string) => { if (!providerToken) throw new UnauthorizedError(); const appCfg = getConfig(); - const decodedToken = jwt.verify( - providerToken, - appCfg.AUTH_SECRET - ) as AuthModeProviderJwtTokenPayload; + const decodedToken = jwt.verify(providerToken, appCfg.AUTH_SECRET) as AuthModeProviderJwtTokenPayload; if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError(); if (decodedToken.email !== email) throw new Error("Invalid auth credentials"); @@ -23,10 +16,7 @@ export const validateProviderAuthToken = (providerToken: string, email: string) export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => { const appCfg = getConfig(); - const [AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE] = <[string, string]>token?.split(" ", 2) ?? [ - null, - null - ]; + const [AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE] = <[string, string]>token?.split(" ", 2) ?? [null, null]; if (AUTH_TOKEN_TYPE === null) { throw new BadRequestError({ message: "Missing Authorization Header in the request header." }); } @@ -41,10 +31,7 @@ export const validateSignUpAuthorization = (token: string, userId: string, valid }); } - const decodedToken = jwt.verify( - AUTH_TOKEN_VALUE, - appCfg.AUTH_SECRET - ) as AuthModeProviderSignUpTokenPayload; + const decodedToken = jwt.verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload; if (!validate) return decodedToken; if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw new UnauthorizedError(); diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index e10fe68303..d63baeaca0 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -25,11 +25,7 @@ type TAuthLoginServiceFactoryDep = { }; export type TAuthLoginFactory = ReturnType; -export const authLoginServiceFactory = ({ - userDAL, - tokenService, - smtpService -}: TAuthLoginServiceFactoryDep) => { +export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }: TAuthLoginServiceFactoryDep) => { /* * Private * Not exported. This is to update user device list @@ -37,9 +33,7 @@ export const authLoginServiceFactory = ({ */ const updateUserDeviceSession = async (user: TUsers, ip: string, userAgent: string) => { const devices = await UserDeviceSchema.parseAsync(user.devices || []); - const isDeviceSeen = devices.some( - (device) => device.ip === ip && device.userAgent === userAgent - ); + const isDeviceSeen = devices.some((device) => device.ip === ip && device.userAgent === userAgent); if (!isDeviceSeen) { const newDeviceList = devices.concat([{ ip, userAgent }]); @@ -159,8 +153,7 @@ export const authLoginServiceFactory = ({ validateProviderAuthToken(providerAuthToken as string, email); } - if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) - throw new Error("Failed to authenticate. Try again?"); + if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?"); const isValidClientProof = await srpCheckClientProof( userEnc.salt, userEnc.verifier, @@ -176,11 +169,9 @@ export const authLoginServiceFactory = ({ }); // send multi factor auth token if they it enabled if (userEnc.isMfaEnabled) { - const mfaToken = jwt.sign( - { authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId }, - cfg.AUTH_SECRET, - { expiresIn: cfg.JWT_MFA_LIFETIME } - ); + const mfaToken = jwt.sign({ authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId }, cfg.AUTH_SECRET, { + expiresIn: cfg.JWT_MFA_LIFETIME + }); await sendUserMfaCode(userEnc.userId, userEnc.email); return { isMfaEnabled: true, token: mfaToken } as const; @@ -230,8 +221,7 @@ export const authLoginServiceFactory = ({ let user = await userDAL.findUserByEmail(email); const appCfg = getConfig(); const isOauthSignUpDisabled = !isSignupAllowed && !user; - if (isOauthSignUpDisabled) - throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" }); + if (isOauthSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" }); if (!user) { user = await userDAL.create({ email, firstName, lastName, authMethods: [authMethod] }); diff --git a/backend/src/services/auth/auth-password-service.ts b/backend/src/services/auth/auth-password-service.ts index 3ea6561842..ff07d422f3 100644 --- a/backend/src/services/auth/auth-password-service.ts +++ b/backend/src/services/auth/auth-password-service.ts @@ -9,11 +9,7 @@ import { TokenType } from "../auth-token/auth-token-types"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; import { TUserDALFactory } from "../user/user-dal"; import { TAuthDALFactory } from "./auth-dal"; -import { - TChangePasswordDTO, - TCreateBackupPrivateKeyDTO, - TResetPasswordViaBackupKeyDTO -} from "./auth-password-type"; +import { TChangePasswordDTO, TCreateBackupPrivateKeyDTO, TResetPasswordViaBackupKeyDTO } from "./auth-password-type"; import { AuthTokenType } from "./auth-type"; type TAuthPasswordServiceFactoryDep = { @@ -70,8 +66,7 @@ export const authPaswordServiceFactory = ({ serverPrivateKey: null, clientPublicKey: null }); - if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) - throw new Error("Failed to authenticate. Try again?"); + if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?"); const isValidClientProof = await srpCheckClientProof( userEnc.salt, userEnc.verifier, @@ -200,8 +195,7 @@ export const authPaswordServiceFactory = ({ throw new Error("Failed to find user"); } - if (!userEnc.clientPublicKey || !userEnc.serverPrivateKey) - throw new Error("failed to create backup key"); + if (!userEnc.clientPublicKey || !userEnc.serverPrivateKey) throw new Error("failed to create backup key"); const isValidClientProff = await srpCheckClientProof( userEnc.salt, userEnc.verifier, diff --git a/backend/src/services/auth/auth-signup-service.ts b/backend/src/services/auth/auth-signup-service.ts index 17e45845f3..6090a2129f 100644 --- a/backend/src/services/auth/auth-signup-service.ts +++ b/backend/src/services/auth/auth-signup-service.ts @@ -148,9 +148,7 @@ export const authSignupServiceFactory = ({ }); const hasSamlEnabled = user?.authMethods?.some((authMethod) => - [AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes( - authMethod as AuthMethod - ) + [AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(authMethod as AuthMethod) ); if (!hasSamlEnabled) { @@ -162,9 +160,7 @@ export const authSignupServiceFactory = ({ { userId: user.id, status: OrgMembershipStatus.Accepted } ); const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))]; - await Promise.allSettled( - uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId)) - ); + await Promise.allSettled(uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId))); const tokenSession = await tokenService.getUserTokenSession({ userAgent, @@ -259,9 +255,7 @@ export const authSignupServiceFactory = ({ tx ); const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))]; - await Promise.allSettled( - uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId)) - ); + await Promise.allSettled(uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId))); return { info: us, key: userEncKey }; }); diff --git a/backend/src/services/auth/auth-type.ts b/backend/src/services/auth/auth-type.ts index 183c6170e1..26417b0e87 100644 --- a/backend/src/services/auth/auth-type.ts +++ b/backend/src/services/auth/auth-type.ts @@ -41,6 +41,11 @@ export type AuthModeJwtTokenPayload = { accessVersion: number; }; +export type AuthModeMfaJwtTokenPayload = { + authTokenType: AuthTokenType.MFA_TOKEN; + userId: string; +}; + export type AuthModeRefreshJwtTokenPayload = { authTokenType: AuthTokenType.REFRESH_TOKEN; userId: string; diff --git a/backend/src/services/identity-access-token/identity-access-token-dal.ts b/backend/src/services/identity-access-token/identity-access-token-dal.ts index 5919136a08..42fb5bba5b 100644 --- a/backend/src/services/identity-access-token/identity-access-token-dal.ts +++ b/backend/src/services/identity-access-token/identity-access-token-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TIdentityAccessTokens } from "@app/db/schemas"; +import { TableName, TIdentityAccessTokens } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols } from "@app/lib/knex"; @@ -14,11 +14,7 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => { try { const doc = await (tx || db)(TableName.IdentityAccessToken) .where(filter) - .join( - TableName.Identity, - `${TableName.Identity}.id`, - `${TableName.IdentityAccessToken}.identityId` - ) + .join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityAccessToken}.identityId`) .leftJoin( TableName.IdentityUaClientSecret, `${TableName.IdentityAccessToken}.identityUAClientSecretId`, diff --git a/backend/src/services/identity-access-token/identity-access-token-service.ts b/backend/src/services/identity-access-token/identity-access-token-service.ts index 7509b9dfff..cdc8effe2d 100644 --- a/backend/src/services/identity-access-token/identity-access-token-service.ts +++ b/backend/src/services/identity-access-token/identity-access-token-service.ts @@ -7,18 +7,13 @@ import { checkIPAgainstBlocklist, TIp } from "@app/lib/ip"; import { AuthTokenType } from "../auth/auth-type"; import { TIdentityAccessTokenDALFactory } from "./identity-access-token-dal"; -import { - TIdentityAccessTokenJwtPayload, - TRenewAccessTokenDTO -} from "./identity-access-token-types"; +import { TIdentityAccessTokenJwtPayload, TRenewAccessTokenDTO } from "./identity-access-token-types"; type TIdentityAccessTokenServiceFactoryDep = { identityAccessTokenDAL: TIdentityAccessTokenDALFactory; }; -export type TIdentityAccessTokenServiceFactory = ReturnType< - typeof identityAccessTokenServiceFactory ->; +export type TIdentityAccessTokenServiceFactory = ReturnType; export const identityAccessTokenServiceFactory = ({ identityAccessTokenDAL @@ -88,9 +83,10 @@ export const identityAccessTokenServiceFactory = ({ const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => { const appCfg = getConfig(); - const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload; - if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) - throw new UnauthorizedError(); + const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & { + identityAccessTokenId: string; + }; + if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) throw new UnauthorizedError(); const identityAccessToken = await identityAccessTokenDAL.findOne({ [`${TableName.IdentityAccessToken}.id` as "id"]: decodedToken.identityAccessTokenId, @@ -100,20 +96,14 @@ export const identityAccessTokenServiceFactory = ({ validateAccessTokenExp(identityAccessToken); - const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById( - identityAccessToken.id, - { - accessTokenLastRenewedAt: new Date() - } - ); + const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById(identityAccessToken.id, { + accessTokenLastRenewedAt: new Date() + }); return { accessToken, identityAccessToken: updatedIdentityAccessToken }; }; - const fnValidateIdentityAccessToken = async ( - token: TIdentityAccessTokenJwtPayload, - ipAddress?: string - ) => { + const fnValidateIdentityAccessToken = async (token: TIdentityAccessTokenJwtPayload, ipAddress?: string) => { const identityAccessToken = await identityAccessTokenDAL.findOne({ [`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId, isAccessTokenRevoked: false diff --git a/backend/src/services/identity-project/identity-project-dal.ts b/backend/src/services/identity-project/identity-project-dal.ts index fd906cf103..dbb864387a 100644 --- a/backend/src/services/identity-project/identity-project-dal.ts +++ b/backend/src/services/identity-project/identity-project-dal.ts @@ -14,11 +14,7 @@ export const identityProjectDALFactory = (db: TDbClient) => { try { const docs = await (tx || db)(TableName.IdentityProjectMembership) .where(`${TableName.IdentityProjectMembership}.projectId`, projectId) - .join( - TableName.Identity, - `${TableName.IdentityProjectMembership}.identityId`, - `${TableName.Identity}.id` - ) + .join(TableName.Identity, `${TableName.IdentityProjectMembership}.identityId`, `${TableName.Identity}.id`) .leftJoin( TableName.ProjectRoles, `${TableName.IdentityProjectMembership}.roleId`, diff --git a/backend/src/services/identity-project/identity-project-service.ts b/backend/src/services/identity-project/identity-project-service.ts index d8c42dde66..05e0bd68bd 100644 --- a/backend/src/services/identity-project/identity-project-service.ts +++ b/backend/src/services/identity-project/identity-project-service.ts @@ -2,10 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import { ProjectMembershipRole, TProjectRoles } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors"; @@ -24,10 +21,7 @@ type TIdentityProjectServiceFactoryDep = { identityProjectDAL: TIdentityProjectDALFactory; projectDAL: Pick; identityOrgMembershipDAL: Pick; - permissionService: Pick< - TPermissionServiceFactory, - "getProjectPermission" | "getProjectPermissionByRole" - >; + permissionService: Pick; }; export type TIdentityProjectServiceFactory = ReturnType; @@ -38,18 +32,9 @@ export const identityProjectServiceFactory = ({ identityOrgMembershipDAL, projectDAL }: TIdentityProjectServiceFactoryDep) => { - const createProjectIdentity = async ({ - identityId, - actor, - actorId, - projectId, - role - }: TCreateProjectIdentityDTO) => { + const createProjectIdentity = async ({ identityId, actor, actorId, projectId, role }: TCreateProjectIdentityDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Identity); const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId }); if (existingIdentity) @@ -67,8 +52,10 @@ export const identityProjectServiceFactory = ({ message: `Failed to find identity with id ${identityId}` }); - const { permission: rolePermission, role: customRole } = - await permissionService.getProjectPermissionByRole(role, project.id); + const { permission: rolePermission, role: customRole } = await permissionService.getProjectPermissionByRole( + role, + project.id + ); const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); if (!hasPriviledge) throw new ForbiddenRequestError({ @@ -85,18 +72,9 @@ export const identityProjectServiceFactory = ({ return projectIdentity; }; - const updateProjectIdentity = async ({ - projectId, - identityId, - role, - actor, - actorId - }: TUpdateProjectIdentityDTO) => { + const updateProjectIdentity = async ({ projectId, identityId, role, actor, actorId }: TUpdateProjectIdentityDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity); const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId }); if (!projectIdentity) @@ -115,8 +93,10 @@ export const identityProjectServiceFactory = ({ let customRole: TProjectRoles | undefined; if (role) { - const { permission: rolePermission, role: customOrgRole } = - await permissionService.getProjectPermissionByRole(role, projectIdentity.projectId); + const { permission: rolePermission, role: customOrgRole } = await permissionService.getProjectPermissionByRole( + role, + projectIdentity.projectId + ); const isCustomRole = Boolean(customOrgRole); const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission); @@ -135,12 +115,7 @@ export const identityProjectServiceFactory = ({ return updatedProjectIdentity; }; - const deleteProjectIdentity = async ({ - identityId, - actorId, - actor, - projectId - }: TDeleteProjectIdentityDTO) => { + const deleteProjectIdentity = async ({ identityId, actorId, actor, projectId }: TDeleteProjectIdentityDTO) => { const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId }); if (!identityProjectMembership) throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` }); @@ -150,10 +125,7 @@ export const identityProjectServiceFactory = ({ actorId, identityProjectMembership.projectId ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity); const { permission: identityRolePermission } = await permissionService.getProjectPermission( ActorType.IDENTITY, identityId, @@ -169,10 +141,7 @@ export const identityProjectServiceFactory = ({ const listProjectIdentities = async ({ projectId, actor, actorId }: TListProjectIdentityDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity); const identityMemberhips = await identityProjectDAL.findByProjectId(projectId); return identityMemberhips; diff --git a/backend/src/services/identity-ua/identity-ua-service.ts b/backend/src/services/identity-ua/identity-ua-service.ts index 1eb528977a..aa5c3c8955 100644 --- a/backend/src/services/identity-ua/identity-ua-service.ts +++ b/backend/src/services/identity-ua/identity-ua-service.ts @@ -6,10 +6,7 @@ import jwt from "jsonwebtoken"; import { IdentityAuthMethod } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; -import { - OrgPermissionActions, - OrgPermissionSubjects -} from "@app/ee/services/permission/org-permission"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { getConfig } from "@app/lib/config/env"; @@ -71,8 +68,7 @@ export const identityUaServiceFactory = ({ ); if (!validClientSecretInfo) throw new UnauthorizedError(); - const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = - validClientSecretInfo; + const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo; if (clientSecretTTL > 0) { const clientSecretCreated = new Date(validClientSecretInfo.createdAt); const ttlInMilliseconds = clientSecretTTL * 1000; @@ -97,16 +93,12 @@ export const identityUaServiceFactory = ({ isClientSecretRevoked: true }); throw new UnauthorizedError({ - message: - "Failed to authenticate identity credentials due to client secret number of uses limit reached" + message: "Failed to authenticate identity credentials due to client secret number of uses limit reached" }); } const identityAccessToken = await identityUaDAL.transaction(async (tx) => { - const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage( - validClientSecretInfo.id, - tx - ); + const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage(validClientSecretInfo.id, tx); const newToken = await identityAccessTokenDAL.create( { identityId: identityUa.identityId, @@ -132,10 +124,7 @@ export const identityUaServiceFactory = ({ } as TIdentityAccessTokenJwtPayload, appCfg.AUTH_SECRET, { - expiresIn: - identityAccessToken.accessTokenMaxTTL === 0 - ? undefined - : identityAccessToken.accessTokenMaxTTL + expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL } ); return { accessToken, identityUa, validClientSecretInfo, identityAccessToken }; @@ -162,35 +151,26 @@ export const identityUaServiceFactory = ({ throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" }); } - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); const plan = await licenseService.getPlan(identityMembershipOrg.orgId); - const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map( - (clientSecretTrustedIp) => { - if ( - !plan.ipAllowlisting && - clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && - clientSecretTrustedIp.ipAddress !== "::/0" - ) - throw new BadRequestError({ - message: - "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." - }); - if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress)) - throw new BadRequestError({ - message: "The IP is not a valid IPv4, IPv6, or CIDR block" - }); - return extractIPDetails(clientSecretTrustedIp.ipAddress); - } - ); + const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => { + if ( + !plan.ipAllowlisting && + clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && + clientSecretTrustedIp.ipAddress !== "::/0" + ) + throw new BadRequestError({ + message: + "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." + }); + if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress)) + throw new BadRequestError({ + message: "The IP is not a valid IPv4, IPv6, or CIDR block" + }); + return extractIPDetails(clientSecretTrustedIp.ipAddress); + }); const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => { if ( !plan.ipAllowlisting && @@ -254,41 +234,31 @@ export const identityUaServiceFactory = ({ if ( (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) > 0 && - (accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) > - (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) + (accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) ) { throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" }); } - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const plan = await licenseService.getPlan(identityMembershipOrg.orgId); - const reformattedClientSecretTrustedIps = clientSecretTrustedIps?.map( - (clientSecretTrustedIp) => { - if ( - !plan.ipAllowlisting && - clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && - clientSecretTrustedIp.ipAddress !== "::/0" - ) - throw new BadRequestError({ - message: - "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." - }); - if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress)) - throw new BadRequestError({ - message: "The IP is not a valid IPv4, IPv6, or CIDR block" - }); - return extractIPDetails(clientSecretTrustedIp.ipAddress); - } - ); + const reformattedClientSecretTrustedIps = clientSecretTrustedIps?.map((clientSecretTrustedIp) => { + if ( + !plan.ipAllowlisting && + clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && + clientSecretTrustedIp.ipAddress !== "::/0" + ) + throw new BadRequestError({ + message: + "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." + }); + if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress)) + throw new BadRequestError({ + message: "The IP is not a valid IPv4, IPv6, or CIDR block" + }); + return extractIPDetails(clientSecretTrustedIp.ipAddress); + }); const reformattedAccessTokenTrustedIps = accessTokenTrustedIps?.map((accessTokenTrustedIp) => { if ( !plan.ipAllowlisting && @@ -330,15 +300,8 @@ export const identityUaServiceFactory = ({ const uaIdentityAuth = await identityUaDAL.findOne({ identityId }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId }; }; @@ -356,15 +319,8 @@ export const identityUaServiceFactory = ({ throw new BadRequestError({ message: "The identity does not have universal auth" }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -409,15 +365,8 @@ export const identityUaServiceFactory = ({ throw new BadRequestError({ message: "The identity does not have universal auth" }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -441,27 +390,15 @@ export const identityUaServiceFactory = ({ return { clientSecrets, orgId: identityMembershipOrg.orgId }; }; - const revokeUaClientSecret = async ({ - identityId, - actorId, - actor, - clientSecretId - }: TRevokeUaClientSecretDTO) => { + const revokeUaClientSecret = async ({ identityId, actorId, actor, clientSecretId }: TRevokeUaClientSecretDTO) => { const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) throw new BadRequestError({ message: "The identity does not have universal auth" }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityMembershipOrg.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Delete, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, diff --git a/backend/src/services/identity/identity-org-dal.ts b/backend/src/services/identity/identity-org-dal.ts index c5413d058f..95d742f334 100644 --- a/backend/src/services/identity/identity-org-dal.ts +++ b/backend/src/services/identity/identity-org-dal.ts @@ -14,11 +14,7 @@ export const identityOrgDALFactory = (db: TDbClient) => { try { const [data] = await (tx || db)(TableName.IdentityOrgMembership) .where(filter) - .join( - TableName.Identity, - `${TableName.IdentityOrgMembership}.identityId`, - `${TableName.Identity}.id` - ) + .join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`) .select(selectAllTableCols(TableName.IdentityOrgMembership)) .select(db.ref("name").withSchema(TableName.Identity)) .select(db.ref("authMethod").withSchema(TableName.Identity)); @@ -35,16 +31,8 @@ export const identityOrgDALFactory = (db: TDbClient) => { try { const docs = await (tx || db)(TableName.IdentityOrgMembership) .where(`${TableName.IdentityOrgMembership}.orgId`, orgId) - .join( - TableName.Identity, - `${TableName.IdentityOrgMembership}.identityId`, - `${TableName.Identity}.id` - ) - .leftJoin( - TableName.OrgRoles, - `${TableName.IdentityOrgMembership}.roleId`, - `${TableName.OrgRoles}.id` - ) + .join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`) + .leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .select(selectAllTableCols(TableName.IdentityOrgMembership)) // cr stands for custom role .select(db.ref("id").as("crId").withSchema(TableName.OrgRoles)) diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 09fb5fb362..3dd4940348 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -1,10 +1,7 @@ import { ForbiddenError } from "@casl/ability"; import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas"; -import { - OrgPermissionActions, - OrgPermissionSubjects -} from "@app/ee/services/permission/org-permission"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors"; @@ -30,17 +27,15 @@ export const identityServiceFactory = ({ }: TIdentityServiceFactoryDep) => { const createIdentity = async ({ name, role, actor, orgId, actorId }: TCreateIdentityDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); - const { permission: rolePermission, role: customRole } = - await permissionService.getOrgPermissionByRole(role, orgId); + const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole( + role, + orgId + ); const isCustomRole = Boolean(customRole); const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission); - if (!hasRequiredPriviledges) - throw new BadRequestError({ message: "Failed to create a more privileged identity" }); + if (!hasRequiredPriviledges) throw new BadRequestError({ message: "Failed to create a more privileged identity" }); const identity = await identityDAL.transaction(async (tx) => { const newIdentity = await identityDAL.create({ name }, tx); @@ -56,24 +51,15 @@ export const identityServiceFactory = ({ return newIdentity; }); - return identity; }; const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => { const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); - if (!identityOrgMembership) - throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); + if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityOrgMembership.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: identityRolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -86,8 +72,10 @@ export const identityServiceFactory = ({ let customRole: TOrgRoles | undefined; if (role) { - const { permission: rolePermission, role: customOrgRole } = - await permissionService.getOrgPermissionByRole(role, identityOrgMembership.orgId); + const { permission: rolePermission, role: customOrgRole } = await permissionService.getOrgPermissionByRole( + role, + identityOrgMembership.orgId + ); const isCustomRole = Boolean(customOrgRole); const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission); @@ -97,9 +85,7 @@ export const identityServiceFactory = ({ } const identity = await identityDAL.transaction(async (tx) => { - const newIdentity = name - ? await identityDAL.updateById(id, { name }, tx) - : await identityDAL.findById(id, tx); + const newIdentity = name ? await identityDAL.updateById(id, { name }, tx) : await identityDAL.findById(id, tx); if (role) { await identityOrgMembershipDAL.update( { identityId: id }, @@ -118,18 +104,10 @@ export const identityServiceFactory = ({ const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => { const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); - if (!identityOrgMembership) - throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); + if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); - const { permission } = await permissionService.getOrgPermission( - actor, - actorId, - identityOrgMembership.orgId - ); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Delete, - OrgPermissionSubjects.Identity - ); + const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity); const { permission: identityRolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, id, @@ -145,10 +123,7 @@ export const identityServiceFactory = ({ const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Identity - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId); return identityMemberhips; diff --git a/backend/src/services/integration-auth/integration-app-list.ts b/backend/src/services/integration-auth/integration-app-list.ts index 39e629606b..17b1b63ad7 100644 --- a/backend/src/services/integration-auth/integration-app-list.ts +++ b/backend/src/services/integration-auth/integration-app-list.ts @@ -22,11 +22,7 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) interface GCPApp { projectNumber: string; projectId: string; - lifecycleState: - | "ACTIVE" - | "LIFECYCLE_STATE_UNSPECIFIED" - | "DELETE_REQUESTED" - | "DELETE_IN_PROGRESS"; + lifecycleState: "ACTIVE" | "LIFECYCLE_STATE_UNSPECIFIED" | "DELETE_REQUESTED" | "DELETE_IN_PROGRESS"; name: string; createTime: string; parent: { @@ -59,8 +55,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) ...(pageToken ? { pageToken } : {}) }); - const res: GCPGetProjectsRes = ( - await request.get(`${IntegrationUrls.GCP_API_URL}/v1/projects`, { + const res = ( + await request.get(`${IntegrationUrls.GCP_API_URL}/v1/projects`, { params, headers: { Authorization: `Bearer ${accessToken}`, @@ -81,8 +77,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) // eslint-disable-next-line for await (const gcpApp of gcpApps) { try { - const res: GCPGetServiceRes = ( - await request.get( + const res = ( + await request.get( `${IntegrationUrls.GCP_SERVICE_USAGE_URL}/v1/projects/${gcpApp.projectId}/services/${IntegrationUrls.GCP_SECRET_MANAGER_SERVICE_NAME}`, { headers: { @@ -113,7 +109,7 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) */ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.HEROKU_API_URL}/apps`, { + await request.get<{ name: string }[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, { headers: { Accept: "application/vnd.heroku+json; version=3", Authorization: `Bearer ${accessToken}` @@ -121,7 +117,7 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name })); @@ -131,15 +127,9 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { /** * Return list of names of apps for Vercel integration */ -const getAppsVercel = async ({ - accessToken, - teamId -}: { - teamId?: string | null; - accessToken: string; -}) => { +const getAppsVercel = async ({ accessToken, teamId }: { teamId?: string | null; accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, { + await request.get<{ projects: { name: string; id: string }[] }>(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -154,7 +144,7 @@ const getAppsVercel = async ({ }) ).data; - const apps = res.projects.map((a: any) => ({ + const apps = res.projects.map((a) => ({ name: a.name, appId: a.id })); @@ -166,7 +156,7 @@ const getAppsVercel = async ({ * Return list of sites for Netlify integration */ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => { - const apps: any = []; + const apps: Array<{ name: string; appId: string }> = []; let page = 1; const perPage = 10; let hasMorePages = true; @@ -179,15 +169,18 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => { filter: "all" }); - const { data } = await request.get(`${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; site_id: string }[]>( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.site_id @@ -238,8 +231,8 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { } ); - if (response.data.length > 0) { - repos = repos.concat(response.data); + if ((response.data as GitHubApp[]).length > 0) { + repos = repos.concat(response.data as GitHubApp[]); page += 1; } else { hasMore = false; @@ -267,7 +260,7 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { */ const getAppsRender = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.RENDER_API_URL}/v1/services`, { + await request.get<{ service: { name: string; id: string } }[]>(`${IntegrationUrls.RENDER_API_URL}/v1/services`, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json", @@ -276,7 +269,7 @@ const getAppsRender = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.service.name, appId: a.service.id })); @@ -309,7 +302,9 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { projects: { edges } } } - } = await request.post( + } = await request.post<{ + data: { projects: { edges: { node: { name: string; id: string } }[] } }; + }>( IntegrationUrls.RAILWAY_API_URL, { query, @@ -324,7 +319,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { } ); - const apps = edges.map((e: any) => ({ + const apps = edges.map((e) => ({ name: e.node.name, appId: e.node.id })); @@ -335,24 +330,21 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { /** * Return list of sites for Laravel Forge integration */ -const getAppsLaravelForge = async ({ - accessToken, - serverId -}: { - accessToken: string; - serverId?: string; -}) => { +const getAppsLaravelForge = async ({ accessToken, serverId }: { accessToken: string; serverId?: string }) => { const res = ( - await request.get(`${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`, { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json", - "Content-Type": "application/json" + await request.get<{ sites: { name: string; id: string }[] }>( + `${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json", + "Content-Type": "application/json" + } } - }) + ) ).data.sites; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -382,8 +374,8 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { } `; - const res: FlyioApp[] = ( - await request.post( + const res = ( + await request.post<{ data: { apps: { nodes: FlyioApp[] } } }>( IntegrationUrls.FLYIO_API_URL, { query, @@ -401,7 +393,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { ) ).data.data.apps.nodes; - const apps = res.map((a: FlyioApp) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -414,7 +406,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { */ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, { + await request.get<{ reponame: string }[]>(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, { headers: { "Circle-Token": accessToken, "Accept-Encoding": "application/json" @@ -422,7 +414,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res?.map((a: any) => ({ + const apps = res?.map((a) => ({ name: a?.reponame })); @@ -431,7 +423,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, { + await request.get<{ id: string; slug: string }[]>(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, { headers: { Authorization: `token ${accessToken}`, "Accept-Encoding": "application/json" @@ -439,7 +431,7 @@ const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res?.map((a: any) => ({ + const apps = res?.map((a) => ({ name: a?.slug?.split("/")[1], appId: a?.id })); @@ -450,15 +442,9 @@ const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { /** * Return list of projects for Terraform Cloud integration */ -const getAppsTerraformCloud = async ({ - accessToken, - workspacesId -}: { - accessToken: string; - workspacesId?: string; -}) => { +const getAppsTerraformCloud = async ({ accessToken, workspacesId }: { accessToken: string; workspacesId?: string }) => { const res = ( - await request.get( + await request.get<{ data: { attributes: { name: string }; id: string } }>( `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${workspacesId}`, { headers: { @@ -510,15 +496,18 @@ const getAppsGitlab = async ({ per_page: String(perPage) }); - const { data } = await request.get(`${gitLabApiUrl}/v4/groups/${teamId}/projects`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${gitLabApiUrl}/v4/groups/${teamId}/projects`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.id @@ -535,7 +524,7 @@ const getAppsGitlab = async ({ // case: fetch projects for individual in GitLab const { id } = ( - await request.get(`${gitLabApiUrl}/v4/user`, { + await request.get<{ id: string }>(`${gitLabApiUrl}/v4/user`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -549,7 +538,7 @@ const getAppsGitlab = async ({ per_page: String(perPage) }); - const { data } = await request.get(`${gitLabApiUrl}/v4/users/${id}/projects`, { + const { data } = await request.get<{ name: string; id: string }[]>(`${gitLabApiUrl}/v4/users/${id}/projects`, { params, headers: { Authorization: `Bearer ${accessToken}`, @@ -557,7 +546,7 @@ const getAppsGitlab = async ({ } }); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.id @@ -580,7 +569,7 @@ const getAppsGitlab = async ({ */ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: string }) => { const res = ( - await request.get(`${url}/app/rest/projects`, { + await request.get<{ project: { name: string; id: string }[] }>(`${url}/app/rest/projects`, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json" @@ -588,7 +577,7 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: }) ).data.project.slice(1); - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -600,14 +589,17 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: * Return list of projects for Supabase integration */ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.SUPABASE_API_URL}/v1/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${IntegrationUrls.SUPABASE_API_URL}/v1/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - const apps = data.map((a: any) => ({ + const apps = data.map((a) => ({ name: a.name, appId: a.id })); @@ -619,14 +611,14 @@ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => { * Return list of accounts for the Checkly integration */ const getAppsCheckly = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`, { + const { data } = await request.get<{ name: string; id: string }[]>(`${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json" } }); - const apps = data.map((a: any) => ({ + const apps = data.map((a) => ({ name: a.name, appId: a.id })); @@ -637,14 +629,8 @@ const getAppsCheckly = async ({ accessToken }: { accessToken: string }) => { /** * Return list of projects for the Cloudflare Pages integration */ -const getAppsCloudflarePages = async ({ - accessToken, - accountId -}: { - accessToken: string; - accountId?: string; -}) => { - const { data } = await request.get( +const getAppsCloudflarePages = async ({ accessToken, accountId }: { accessToken: string; accountId?: string }) => { + const { data } = await request.get<{ result: { name: string; id: string }[] }>( `${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accountId}/pages/projects`, { headers: { @@ -654,7 +640,7 @@ const getAppsCloudflarePages = async ({ } ); - const apps = data.result.map((a: any) => ({ + const apps = data.result.map((a) => ({ name: a.name, appId: a.id })); @@ -664,14 +650,8 @@ const getAppsCloudflarePages = async ({ /** * Return list of projects for the Cloudflare Workers integration */ -const getAppsCloudflareWorkers = async ({ - accessToken, - accountId -}: { - accessToken: string; - accountId?: string; -}) => { - const { data } = await request.get( +const getAppsCloudflareWorkers = async ({ accessToken, accountId }: { accessToken: string; accountId?: string }) => { + const { data } = await request.get<{ result: { id: string }[] }>( `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/services`, { headers: { @@ -681,7 +661,7 @@ const getAppsCloudflareWorkers = async ({ } ); - const apps = data.result.map((a: any) => ({ + const apps = data.result.map((a) => ({ name: a.id, appId: a.id })); @@ -691,13 +671,7 @@ const getAppsCloudflareWorkers = async ({ /** * Return list of repositories for the BitBucket integration based on provided BitBucket workspace */ -const getAppsBitBucket = async ({ - accessToken, - workspaceSlug -}: { - accessToken: string; - workspaceSlug?: string; -}) => { +const getAppsBitBucket = async ({ accessToken, workspaceSlug }: { accessToken: string; workspaceSlug?: string }) => { interface RepositoriesResponse { size: number; page: number; @@ -759,14 +733,17 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => { data: { data: { projects } } - } = await request.get(`${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + } = await request.get<{ data: { projects: { name: string; id: string }[] } }>( + `${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - const apps = projects.map((a: any) => ({ + const apps = projects.map((a) => ({ name: a.name, appId: a.id })); @@ -779,15 +756,18 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => { */ const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.CODEFRESH_API_URL}/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await request.get<{ projects: { projectName: string; id: string }[] }>( + `${IntegrationUrls.CODEFRESH_API_URL}/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) + ) ).data; - const apps = res.projects.map((a: any) => ({ + const apps = res.projects.map((a) => ({ name: a.projectName, appId: a.id })); @@ -799,20 +779,23 @@ const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => { * Return list of projects for Windmill integration */ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ id: string; name: string }[]>( + `${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); // check for write access of secrets in windmill workspaces - const writeAccessCheck = data.map(async (app: any) => { + const writeAccessCheck = data.map(async (app) => { try { const userPath = "u/user/variable"; const folderPath = "f/folder/variable"; - const { data: writeUser } = await request.post( + const { data: writeUser } = await request.post( `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`, { path: userPath, @@ -828,7 +811,7 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { } ); - const { data: writeFolder } = await request.post( + const { data: writeFolder } = await request.post( `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`, { path: folderPath, @@ -846,38 +829,32 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { // is write access is allowed then delete the created secrets from workspace if (writeUser && writeFolder) { - await request.delete( - `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/delete/${userPath}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.delete(`${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/delete/${userPath}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ); + }); - await request.delete( - `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/delete/${folderPath}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.delete(`${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/delete/${folderPath}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ); + }); return app; } return { error: "cannot write secret" }; - } catch (err: any) { - return { error: err.message }; + } catch (err) { + return { error: (err as Error).message }; } }); const appsWriteResponses = await Promise.all(writeAccessCheck); - const appsWithWriteAccess = appsWriteResponses.filter((appRes: any) => !appRes.error); + const appsWithWriteAccess = appsWriteResponses.filter((appRes) => !(appRes as { error: string })?.error); - const apps = appsWithWriteAccess.map((a: any) => ({ + const apps = (appsWithWriteAccess as { id: string; name: string }[]).map((a) => ({ name: a.name, appId: a.id })); @@ -908,7 +885,7 @@ const getAppsDigitalOceanAppPlatform = async ({ accessToken }: { accessToken: st } const res = ( - await request.get(`${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`, { + await request.get<{ apps: DigitalOceanApp[] }>(`${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -916,14 +893,16 @@ const getAppsDigitalOceanAppPlatform = async ({ accessToken }: { accessToken: st }) ).data; - return (res.apps ?? []).map((a: DigitalOceanApp) => ({ + return (res.apps ?? []).map((a) => ({ name: a.spec.name, appId: a.id })); }; const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => { - const res = await request.post( + const res = await request.post<{ + data: { projects: { name: string; tenant: { id: string } }[] }; + }>( IntegrationUrls.HASURA_CLOUD_API_URL, { query: "query MyQuery { projects { name tenant { id } } }" @@ -936,19 +915,15 @@ const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => { } ); - const data = (res?.data?.data?.projects ?? []).map( - ({ name, tenant: { id: appId } }: { name: string; tenant: { id: string } }) => ({ name, appId }) - ); + const data = (res?.data?.data?.projects ?? []).map(({ name, tenant: { id: appId } }) => ({ + name, + appId + })); return data; }; /** * Return list of applications for Cloud66 integration - * @param {Object} obj - * @param {String} obj.accessToken - personal access token for Cloud66 API - * @returns {Object[]} apps - Cloud66 apps - * @returns {String} apps.name - name of Cloud66 app - * @returns {String} apps.appId - uid of Cloud66 app */ const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => { interface Cloud66Apps { @@ -979,19 +954,19 @@ const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => { account_name: string; is_cluster: boolean; is_inside_cluster: boolean; - cluster_name: any; + cluster_name: string; application_address: string; configstore_namespace: string; } const stacks = ( - await request.get(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, { + await request.get<{ response: Cloud66Apps[] }>(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" } }) - ).data.response as Cloud66Apps[]; + ).data.response; const apps = stacks.map((app) => ({ name: app.name, @@ -1016,7 +991,7 @@ export const getApps = async ({ workspaceSlug?: string; url?: string | null; }): Promise => { - switch (integration) { + switch (integration as Integrations) { case Integrations.GCP_SECRET_MANAGER: return getAppsGCPSecretManager({ accessToken diff --git a/backend/src/services/integration-auth/integration-auth-service.ts b/backend/src/services/integration-auth/integration-auth-service.ts index 81b180ea43..844e01f3cb 100644 --- a/backend/src/services/integration-auth/integration-auth-service.ts +++ b/backend/src/services/integration-auth/integration-auth-service.ts @@ -1,21 +1,10 @@ import { ForbiddenError } from "@casl/ability"; -import { - SecretEncryptionAlgo, - SecretKeyEncoding, - TIntegrationAuths, - TIntegrationAuthsInsert -} from "@app/db/schemas"; +import { SecretEncryptionAlgo, SecretKeyEncoding, TIntegrationAuths, TIntegrationAuthsInsert } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { request } from "@app/lib/config/request"; -import { - decryptSymmetric128BitHexKeyUTF8, - encryptSymmetric128BitHexKeyUTF8 -} from "@app/lib/crypto"; +import { decryptSymmetric128BitHexKeyUTF8, encryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto"; import { BadRequestError } from "@app/lib/errors"; import { TProjectPermission } from "@app/lib/types"; @@ -70,16 +59,9 @@ export const integrationAuthServiceFactory = ({ projectBotDAL, projectBotService }: TIntegrationAuthServiceFactoryDep) => { - const listIntegrationAuthByProjectId = async ({ - actorId, - actor, - projectId - }: TProjectPermission) => { + const listIntegrationAuthByProjectId = async ({ actorId, actor, projectId }: TProjectPermission) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const authorizations = await integrationAuthDAL.find({ projectId }); return authorizations; }; @@ -88,38 +70,20 @@ export const integrationAuthServiceFactory = ({ const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); return integrationAuth; }; - const oauthExchange = async ({ - projectId, - actorId, - actor, - integration, - url, - code - }: TOauthExchangeDTO) => { + const oauthExchange = async ({ projectId, actorId, actor, integration, url, code }: TOauthExchangeDTO) => { if (!Object.values(Integrations).includes(integration as Integrations)) throw new BadRequestError({ message: "Invalid integration" }); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); const bot = await projectBotDAL.findOne({ isActive: true, projectId }); - if (!bot) - throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" }); + if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" }); const tokenExchange = await exchangeCode({ integration, code, url }); const updateDoc: TIntegrationAuthsInsert = { @@ -178,14 +142,10 @@ export const integrationAuthServiceFactory = ({ throw new BadRequestError({ message: "Invalid integration" }); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); const bot = await projectBotDAL.findOne({ isActive: true, projectId }); - if (!bot) - throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" }); + if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" }); const updateDoc: TIntegrationAuthsInsert = { projectId, @@ -251,11 +211,7 @@ export const integrationAuthServiceFactory = ({ }); } - if ( - integrationAuth.refreshCiphertext && - integrationAuth.refreshIV && - integrationAuth.refreshTag - ) { + if (integrationAuth.refreshCiphertext && integrationAuth.refreshIV && integrationAuth.refreshTag) { const refreshToken = decryptSymmetric128BitHexKeyUTF8({ key: botKey, ciphertext: integrationAuth.refreshCiphertext, @@ -287,11 +243,7 @@ export const integrationAuthServiceFactory = ({ } if (!accessToken) throw new BadRequestError({ message: "Missing access token" }); - if ( - integrationAuth.accessIdTag && - integrationAuth.accessIdIV && - integrationAuth.accessIdCiphertext - ) { + if (integrationAuth.accessIdTag && integrationAuth.accessIdIV && integrationAuth.accessIdCiphertext) { accessId = decryptSymmetric128BitHexKeyUTF8({ key: botKey, ciphertext: integrationAuth.accessIdCiphertext, @@ -302,25 +254,12 @@ export const integrationAuthServiceFactory = ({ return { accessId, accessToken }; }; - const getIntegrationApps = async ({ - actor, - actorId, - teamId, - id, - workspaceSlug - }: TIntegrationAuthAppsDTO) => { + const getIntegrationApps = async ({ actor, actorId, teamId, id, workspaceSlug }: TIntegrationAuthAppsDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken, accessId } = await getIntegrationAccessToken(integrationAuth, botKey); @@ -339,15 +278,8 @@ export const integrationAuthServiceFactory = ({ const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); @@ -359,24 +291,12 @@ export const integrationAuthServiceFactory = ({ return teams; }; - const getVercelBranches = async ({ - appId, - id, - actor, - actorId - }: TIntegrationAuthVercelBranchesDTO) => { + const getVercelBranches = async ({ appId, id, actor, actorId }: TIntegrationAuthVercelBranchesDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); @@ -399,37 +319,22 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getChecklyGroups = async ({ - actorId, - actor, - id, - accountId - }: TIntegrationAuthChecklyGroupsDTO) => { + const getChecklyGroups = async ({ actorId, actor, id, accountId }: TIntegrationAuthChecklyGroupsDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (accountId) { - const { data } = await request.get( - `${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json", - "X-Checkly-Account": accountId - } + const { data } = await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups`, { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json", + "X-Checkly-Account": accountId } - ); + }); return data.map(({ name, id: groupId }) => ({ name, groupId })); } return []; @@ -439,15 +344,8 @@ export const integrationAuthServiceFactory = ({ const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { data } = await request.get<{ results: Array<{ id: string; name: string }> }>( @@ -463,24 +361,12 @@ export const integrationAuthServiceFactory = ({ return data.results.map(({ name, id: orgId }) => ({ name, orgId })); }; - const getQoveryProjects = async ({ - actorId, - actor, - id, - orgId - }: TIntegrationAuthQoveryProjectDTO) => { + const getQoveryProjects = async ({ actorId, actor, id, orgId }: TIntegrationAuthQoveryProjectDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (orgId) { @@ -498,24 +384,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getQoveryEnvs = async ({ - projectId, - id, - actor, - actorId - }: TIntegrationAuthQoveryEnvironmentsDTO) => { + const getQoveryEnvs = async ({ projectId, id, actor, actorId }: TIntegrationAuthQoveryEnvironmentsDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (projectId && projectId !== "none") { @@ -538,24 +412,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getQoveryApps = async ({ - id, - actor, - actorId, - environmentId - }: TIntegrationAuthQoveryScopesDTO) => { + const getQoveryApps = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (environmentId) { @@ -577,24 +439,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getQoveryContainers = async ({ - id, - actor, - actorId, - environmentId - }: TIntegrationAuthQoveryScopesDTO) => { + const getQoveryContainers = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (environmentId) { @@ -616,24 +466,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getQoveryJobs = async ({ - id, - actor, - actorId, - environmentId - }: TIntegrationAuthQoveryScopesDTO) => { + const getQoveryJobs = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (environmentId) { @@ -655,24 +493,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getRailwayEnvironments = async ({ - id, - actor, - actorId, - appId - }: TIntegrationAuthRailwayEnvDTO) => { + const getRailwayEnvironments = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayEnvDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (appId) { @@ -721,24 +547,12 @@ export const integrationAuthServiceFactory = ({ } return []; }; - const getRailwayServices = async ({ - id, - actor, - actorId, - appId - }: TIntegrationAuthRailwayServicesDTO) => { + const getRailwayServices = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayServicesDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (appId) { @@ -806,23 +620,12 @@ export const integrationAuthServiceFactory = ({ return []; }; - const getBitbucketWorkspaces = async ({ - actorId, - actor, - id - }: TIntegrationAuthBitbucketWorkspaceDTO) => { + const getBitbucketWorkspaces = async ({ actorId, actor, id }: TIntegrationAuthBitbucketWorkspaceDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const workspaces: TBitbucketWorkspace[] = []; @@ -834,12 +637,11 @@ export const integrationAuthServiceFactory = ({ const { data }: { data: { values: TBitbucketWorkspace[]; next: string } } = await request.get( workspaceUrl, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ); + }); if (data?.values.length > 0) { data.values.forEach((workspace) => { @@ -856,24 +658,12 @@ export const integrationAuthServiceFactory = ({ return workspaces; }; - const getNorthFlankSecretGroups = async ({ - id, - actor, - actorId, - appId - }: TIntegrationAuthNorthflankSecretGroupDTO) => { + const getNorthFlankSecretGroups = async ({ id, actor, actorId, appId }: TIntegrationAuthNorthflankSecretGroupDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const secretGroups: { name: string; groupId: string }[] = []; @@ -906,7 +696,7 @@ export const integrationAuthServiceFactory = ({ } ); - secrets.forEach((a: any) => { + secrets.forEach((a) => { secretGroups.push({ name: a.name, groupId: a.id @@ -923,41 +713,26 @@ export const integrationAuthServiceFactory = ({ return secretGroups; }; - const getTeamcityBuildConfigs = async ({ - appId, - id, - actorId, - actor - }: TGetIntegrationAuthTeamCityBuildConfigDTO) => { + const getTeamcityBuildConfigs = async ({ appId, id, actorId, actor }: TGetIntegrationAuthTeamCityBuildConfigDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); if (appId) { const { data: { buildType } - } = await request.get<{ buildType: TTeamCityBuildConfig[] }>( - `${integrationAuth.url}/app/rest/buildTypes`, - { - params: { - locator: `project:${appId}` - }, - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" - } + } = await request.get<{ buildType: TTeamCityBuildConfig[] }>(`${integrationAuth.url}/app/rest/buildTypes`, { + params: { + locator: `project:${appId}` + }, + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" } - ); + }); return buildType.map(({ name, id: buildConfigId }) => ({ name, @@ -967,39 +742,20 @@ export const integrationAuthServiceFactory = ({ return []; }; - const deleteIntegrationAuths = async ({ - projectId, - integration, - actor, - actorId - }: TDeleteIntegrationAuthsDTO) => { + const deleteIntegrationAuths = async ({ projectId, integration, actor, actorId }: TDeleteIntegrationAuthsDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); const integrations = await integrationAuthDAL.delete({ integration, projectId }); return integrations; }; - const deleteIntegrationAuthById = async ({ - id, - actorId, - actor - }: TDeleteIntegrationAuthByIdDTO) => { + const deleteIntegrationAuthById = async ({ id, actorId, actor }: TDeleteIntegrationAuthByIdDTO) => { const integrationAuth = await integrationAuthDAL.findById(id); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); const delIntegrationAuth = await integrationAuthDAL.transaction(async (tx) => { const doc = await integrationAuthDAL.deleteById(integrationAuth.id, tx); diff --git a/backend/src/services/integration-auth/integration-list.ts b/backend/src/services/integration-auth/integration-list.ts index 334a60e1d3..d3cabbcb56 100644 --- a/backend/src/services/integration-auth/integration-list.ts +++ b/backend/src/services/integration-auth/integration-list.ts @@ -67,6 +67,7 @@ export enum IntegrationUrls { QOVERY_API_URL = "https://api.qovery.com", TERRAFORM_CLOUD_API_URL = "https://app.terraform.io", CLOUDFLARE_PAGES_API_URL = "https://api.cloudflare.com", + // eslint-disable-next-line CLOUDFLARE_WORKERS_API_URL = "https://api.cloudflare.com", BITBUCKET_API_URL = "https://api.bitbucket.org", CODEFRESH_API_URL = "https://g.codefresh.io/api", diff --git a/backend/src/services/integration-auth/integration-sync-secret.ts b/backend/src/services/integration-auth/integration-sync-secret.ts index 11ff5c5c2d..abb6a7b1ea 100644 --- a/backend/src/services/integration-auth/integration-sync-secret.ts +++ b/backend/src/services/integration-auth/integration-sync-secret.ts @@ -1,4 +1,11 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable no-param-reassign,no-await-in-loop */ +// Taken from old code and too much work at present thus disabling the above any rules +// resolve it later: akhilmhdh - TODO + import { CreateSecretCommand, GetSecretValueCommand, @@ -8,6 +15,7 @@ import { } from "@aws-sdk/client-secrets-manager"; import { Octokit } from "@octokit/rest"; import AWS from "aws-sdk"; +import { AxiosError } from "axios"; import sodium from "libsodium-wrappers"; import isEqual from "lodash.isequal"; import { z } from "zod"; @@ -18,9 +26,7 @@ import { BadRequestError } from "@app/lib/errors"; import { Integrations, IntegrationUrls } from "./integration-list"; -const getSecretKeyValuePair = ( - secrets: Record -) => +const getSecretKeyValuePair = (secrets: Record) => Object.keys(secrets).reduce>((prev, key) => { // eslint-disable-next-line prev[key] = secrets?.[key] === null ? null : secrets?.[key]?.value; @@ -87,8 +93,8 @@ const syncSecretsGCPSecretManager = async ({ ...(pageToken ? { pageToken } : {}) }); - const res: GCPSMListSecretsRes = ( - await request.get( + const res = ( + await request.get( `${IntegrationUrls.GCP_SECRET_MANAGER_URL}/v1/projects/${integration.appId}/secrets${filterParam}`, { params, @@ -281,9 +287,7 @@ const syncSecretsAzureKeyVault = async ({ return result; }; - const getAzureKeyVaultSecrets = await paginateAzureKeyVaultSecrets( - `${integration.app}/secrets?api-version=7.3` - ); + const getAzureKeyVaultSecrets = await paginateAzureKeyVaultSecrets(`${integration.app}/secrets?api-version=7.3`); let lastSlashIndex: number; const res = ( @@ -293,14 +297,11 @@ const syncSecretsAzureKeyVault = async ({ lastSlashIndex = getAzureKeyVaultSecret.id.lastIndexOf("/"); } - const azureKeyVaultSecret = await request.get( - `${getAzureKeyVaultSecret.id}?api-version=7.3`, - { - headers: { - Authorization: `Bearer ${accessToken}` - } + const azureKeyVaultSecret = await request.get(`${getAzureKeyVaultSecret.id}?api-version=7.3`, { + headers: { + Authorization: `Bearer ${accessToken}` } - ); + }); return { ...azureKeyVaultSecret.data, @@ -309,7 +310,7 @@ const syncSecretsAzureKeyVault = async ({ }) ) ).reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), @@ -378,8 +379,9 @@ const syncSecretsAzureKeyVault = async ({ isSecretSet = true; } catch (err) { - const error: any = err; - if (error?.response?.data?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") { + const error = err as AxiosError; + // eslint-disable-next-line + if ((error?.response?.data as any)?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") { await request.post( `${azIntegration.app}/deletedsecrets/${key}/recover?api-version=7.3`, {}, @@ -405,7 +407,7 @@ const syncSecretsAzureKeyVault = async ({ // Sync/push set secrets for await (const setSecret of setSecrets) { const { key, value } = setSecret; - setSecretAzureKeyVault({ + await setSecretAzureKeyVault({ key, value, integration, @@ -425,11 +427,6 @@ const syncSecretsAzureKeyVault = async ({ /** * Sync/push [secrets] to AWS parameter store - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessId - access id for AWS parameter store integration - * @param {String} obj.accessToken - access token for AWS parameter store integration */ const syncSecretsAWSParameterStore = async ({ integration, @@ -463,60 +460,60 @@ const syncSecretsAWSParameterStore = async ({ const parameterList = (await ssm.getParametersByPath(params).promise()).Parameters; - let awsParameterStoreSecretsObj: { - [key: string]: any; - } = {}; - - if (parameterList) { - awsParameterStoreSecretsObj = parameterList.reduce( - (obj: any, secret: any) => ({ + const awsParameterStoreSecretsObj = (parameterList || []) + .filter(({ Name }) => Boolean(Name)) + .reduce( + (obj, secret) => ({ ...obj, - [secret.Name.substring((integration.path as string).length)]: secret + [(secret.Name as string).substring((integration.path as string).length)]: secret }), - {} + {} as Record ); - } // Identify secrets to create - Object.keys(secrets).map(async (key) => { - if (!(key in awsParameterStoreSecretsObj)) { - // case: secret does not exist in AWS parameter store - // -> create secret - await ssm - .putParameter({ - Name: `${integration.path}${key}`, - Type: "SecureString", - Value: secrets[key].value, - Overwrite: true - }) - .promise(); - // case: secret exists in AWS parameter store - } else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) { - // case: secret value doesn't match one in AWS parameter store - // -> update secret - await ssm - .putParameter({ - Name: `${integration.path}${key}`, - Type: "SecureString", - Value: secrets[key].value, - Overwrite: true - }) - .promise(); - } - }); + await Promise.all( + Object.keys(secrets).map(async (key) => { + if (!(key in awsParameterStoreSecretsObj)) { + // case: secret does not exist in AWS parameter store + // -> create secret + await ssm + .putParameter({ + Name: `${integration.path}${key}`, + Type: "SecureString", + Value: secrets[key].value, + Overwrite: true + }) + .promise(); + // case: secret exists in AWS parameter store + } else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) { + // case: secret value doesn't match one in AWS parameter store + // -> update secret + await ssm + .putParameter({ + Name: `${integration.path}${key}`, + Type: "SecureString", + Value: secrets[key].value, + Overwrite: true + }) + .promise(); + } + }) + ); // Identify secrets to delete - Object.keys(awsParameterStoreSecretsObj).map(async (key) => { - if (!(key in secrets)) { - // case: - // -> delete secret - await ssm - .deleteParameter({ - Name: awsParameterStoreSecretsObj[key].Name - }) - .promise(); - } - }); + await Promise.all( + Object.keys(awsParameterStoreSecretsObj).map(async (key) => { + if (!(key in secrets)) { + // case: + // -> delete secret + await ssm + .deleteParameter({ + Name: awsParameterStoreSecretsObj[key].Name as string + }) + .promise(); + } + }) + ); AWS.config.update({ region: undefined, @@ -564,7 +561,7 @@ const syncSecretsAWSSecretManager = async ({ }) ); - let awsSecretManagerSecretObj: { [key: string]: any } = {}; + let awsSecretManagerSecretObj: { [key: string]: AWS.SecretsManager } = {}; if (awsSecretManagerSecret?.SecretString) { awsSecretManagerSecretObj = JSON.parse(awsSecretManagerSecret.SecretString); @@ -680,25 +677,24 @@ const syncSecretsVercel = async ({ : {}) }; - const vercelSecrets: VercelSecret[] = ( - await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const vercelSecrets = ( + await request.get<{ envs: VercelSecret[] }>( + `${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) - ).data.envs.filter((secret: VercelSecret) => { + ) + ).data.envs.filter((secret) => { if (!secret.target.includes(integration.targetEnvironment as string)) { // case: secret does not have the same target environment return false; } - if ( - integration.targetEnvironment === "preview" && - secret.gitBranch && - integration.path !== secret.gitBranch - ) { + if (integration.targetEnvironment === "preview" && secret.gitBranch && integration.path !== secret.gitBranch) { // case: secret on preview environment does not have same target git branch return false; } @@ -712,16 +708,13 @@ const syncSecretsVercel = async ({ if (vercelSecret.type === "encrypted") { // case: secret is encrypted -> need to decrypt const decryptedSecret = ( - await request.get( - `${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${vercelSecret.id}`, - { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${vercelSecret.id}`, { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ) + }) ).data; res[vercelSecret.key] = decryptedSecret; @@ -791,47 +784,36 @@ const syncSecretsVercel = async ({ // Sync/push new secrets if (newSecrets.length > 0) { - await request.post( - `${IntegrationUrls.VERCEL_API_URL}/v10/projects/${integration.app}/env`, - newSecrets, - { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.post(`${IntegrationUrls.VERCEL_API_URL}/v10/projects/${integration.app}/env`, newSecrets, { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ); + }); } for await (const secret of updateSecrets) { if (secret.type !== "sensitive") { const { id, ...updatedSecret } = secret; - await request.patch( - `${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${id}`, - updatedSecret, - { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - } - } - ); - } - } - - for await (const secret of deleteSecrets) { - await request.delete( - `${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, - { + await request.patch(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${id}`, updatedSecret, { params, headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" } + }); + } + } + + for await (const secret of deleteSecrets) { + await request.delete(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" } - ); + }); } }; @@ -866,7 +848,7 @@ const syncSecretsNetlify = async ({ }); const res = ( - await request.get( + await request.get( `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, { params: getParams, @@ -877,11 +859,11 @@ const syncSecretsNetlify = async ({ } ) ).data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), - {} + {} as Record ); const newSecrets: NetlifySecret[] = []; // createEnvVars @@ -905,16 +887,16 @@ const syncSecretsNetlify = async ({ } else { // case: Infisical secret exists in Netlify const contexts = res[key].values.reduce( - (obj: any, value: NetlifyValue) => ({ + (obj, value) => ({ ...obj, [value.context]: value }), - {} + {} as Record ); if ((integration.targetEnvironment as string) in contexts) { // case: Netlify secret value exists in integration context - if (secrets[key] !== contexts[integration.targetEnvironment as string].value) { + if (secrets[key].value !== contexts[integration.targetEnvironment as string].value) { // case: Infisical and Netlify secret values are different // -> update Netlify secret context and value updateSecrets.push({ @@ -994,62 +976,63 @@ const syncSecretsNetlify = async ({ } if (updateSecrets.length > 0) { - updateSecrets.forEach(async (secret: NetlifySecret) => { - await request.patch( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, - { - context: secret.values[0].context, - value: secret.values[0].value - }, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + updateSecrets.map(async (secret: NetlifySecret) => { + await request.patch( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, + { + context: secret.values[0].context, + value: secret.values[0].value + }, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } if (deleteSecrets.length > 0) { - deleteSecrets.forEach(async (key: string) => { - await request.delete( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + deleteSecrets.map(async (key: string) => { + await request.delete( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } if (deleteSecretValues.length > 0) { - deleteSecretValues.forEach(async (secret: NetlifySecret) => { - await request.delete( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + deleteSecretValues.map(async (secret: NetlifySecret) => { + await request.delete( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } }; /** * Sync/push [secrets] to GitHub repo with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for GitHub integration */ const syncSecretsGitHub = async ({ integration, @@ -1096,7 +1079,7 @@ const syncSecretsGitHub = async ({ repo: integration.app as string }) ).data.secrets.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.name]: secret }), @@ -1121,46 +1104,46 @@ const syncSecretsGitHub = async ({ {} ); - Object.keys(encryptedSecrets).map(async (key) => { - if (!(key in secrets)) { - await octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: integration.owner as string, - repo: integration.app as string, - secret_name: key - }); - } - }); + await Promise.all( + Object.keys(encryptedSecrets).map(async (key) => { + if (!(key in secrets)) { + return octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", { + owner: integration.owner as string, + repo: integration.app as string, + secret_name: key + }); + } + }) + ); - Object.keys(secrets).forEach((key) => { - // let encryptedSecret; - sodium.ready.then(async () => { - // convert secret & base64 key to Uint8Array. - const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL); - const binsec = sodium.from_string(secrets[key].value); - - // encrypt secret using libsodium - const encBytes = sodium.crypto_box_seal(binsec, binkey); - - // convert encrypted Uint8Array to base64 - const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL); - - await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: integration.owner as string, - repo: integration.app as string, - secret_name: key, - encrypted_value: encryptedSecret, - key_id: repoPublicKey.key_id + await Promise.all( + Object.keys(secrets).map((key) => { + // let encryptedSecret; + return sodium.ready.then(async () => { + // convert secret & base64 key to Uint8Array. + const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL); + const binsec = sodium.from_string(secrets[key].value); + + // encrypt secret using libsodium + const encBytes = sodium.crypto_box_seal(binsec, binkey); + + // convert encrypted Uint8Array to base64 + const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL); + + await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", { + owner: integration.owner as string, + repo: integration.app as string, + secret_name: key, + encrypted_value: encryptedSecret, + key_id: repoPublicKey.key_id + }); }); - }); - }); + }) + ); }; /** * Sync/push [secrets] to Render service with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Render integration */ const syncSecretsRender = async ({ integration, @@ -1188,10 +1171,6 @@ const syncSecretsRender = async ({ /** * Sync/push [secrets] to Laravel Forge sites with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Laravel Forge integration */ const syncSecretsLaravelForge = async ({ integration, @@ -1204,13 +1183,11 @@ const syncSecretsLaravelForge = async ({ accessId: string | null; accessToken: string; }) => { - function transformObjectToString(obj: any) { + function transformObjectToString(obj: Record) { let result = ""; - for (const key in obj) { - if (obj.hasOwnPropery(key)) { - result += `${key}=${obj[key].value}\n`; - } - } + Object.keys(obj).forEach((key) => { + result += `${key}=${obj[key].value}\n`; + }); return result; } @@ -1231,10 +1208,6 @@ const syncSecretsLaravelForge = async ({ /** * Sync/push [secrets] to Railway project with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Railway integration */ const syncSecretsRailway = async ({ integration, @@ -1279,10 +1252,6 @@ const syncSecretsRailway = async ({ /** * Sync/push [secrets] to Fly.io app - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Render integration */ const syncSecretsFlyio = async ({ integration, @@ -1354,7 +1323,7 @@ const syncSecretsFlyio = async ({ }`; const getSecretsRes = ( - await request.post( + await request.post<{ data: { app: { secrets: FlyioSecret[] } } }>( IntegrationUrls.FLYIO_API_URL, { query: GetSecrets, @@ -1372,9 +1341,7 @@ const syncSecretsFlyio = async ({ ) ).data.data.app.secrets; - const deleteSecretsKeys = getSecretsRes - .filter((secret: FlyioSecret) => !(secret.name in secrets)) - .map((secret: FlyioSecret) => secret.name); + const deleteSecretsKeys = getSecretsRes.filter((secret) => !(secret.name in secrets)).map((secret) => secret.name); // unset (delete) secrets const DeleteSecrets = `mutation($input: UnsetSecretsInput!) { @@ -1460,7 +1427,7 @@ const syncSecretsCircleCI = async ({ // get secrets from CircleCI const getSecretsRes = ( - await request.get( + await request.get<{ items: { name: string }[] }>( `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`, { headers: { @@ -1472,19 +1439,21 @@ const syncSecretsCircleCI = async ({ ).data?.items; // delete secrets from CircleCI - getSecretsRes.forEach(async (sec: any) => { - if (!(sec.name in secrets)) { - await request.delete( - `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`, - { - headers: { - "Circle-Token": accessToken, - "Content-Type": "application/json" + await Promise.all( + getSecretsRes.map(async (sec) => { + if (!(sec.name in secrets)) { + return request.delete( + `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`, + { + headers: { + "Circle-Token": accessToken, + "Content-Type": "application/json" + } } - } - ); - } - }); + ); + } + }) + ); }; /** @@ -1501,21 +1470,20 @@ const syncSecretsTravisCI = async ({ }) => { // get secrets from travis-ci const getSecretsRes = ( - await request.get( - `${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, - { - headers: { - Authorization: `token ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.get<{ + env_vars: { name: string; value: string; repository_id: string; id: string }[]; + }>(`${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, { + headers: { + Authorization: `token ${accessToken}`, + "Accept-Encoding": "application/json" } - ) + }) ).data?.env_vars.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.name]: secret }), - {} + {} as Record ); // add secrets @@ -1598,9 +1566,7 @@ const syncSecretsGitLab = async ({ environment_scope: string; } - const gitLabApiUrl = integrationAuth.url - ? `${integrationAuth.url}/api` - : IntegrationUrls.GITLAB_API_URL; + const gitLabApiUrl = integrationAuth.url ? `${integrationAuth.url}/api` : IntegrationUrls.GITLAB_API_URL; const getAllEnvVariables = async (integrationAppId: string, accToken: string) => { const headers = { @@ -1610,14 +1576,13 @@ const syncSecretsGitLab = async ({ }; let allEnvVariables: GitLabSecret[] = []; - let url: string | null = - `${gitLabApiUrl}/v4/projects/${integrationAppId}/variables?per_page=100`; + let url: string | null = `${gitLabApiUrl}/v4/projects/${integrationAppId}/variables?per_page=100`; while (url) { - const response: any = await request.get(url, { headers }); + const response = await request.get(url, { headers }); allEnvVariables = [...allEnvVariables, ...response.data]; - const linkHeader = response.headers.link; + const linkHeader = response.headers.link as string; const nextLink = linkHeader?.split(",").find((part: string) => part.includes('rel="next"')); if (nextLink) { @@ -1649,7 +1614,7 @@ const syncSecretsGitLab = async ({ }); for await (const key of Object.keys(secrets)) { - const existingSecret = getSecretsRes.find((s: any) => s.key === key); + const existingSecret = getSecretsRes.find((s) => s.key === key); if (!existingSecret) { await request.post( `${gitLabApiUrl}/v4/projects/${integration?.appId}/variables`, @@ -1714,7 +1679,7 @@ const syncSecretsSupabase = async ({ secrets: Record; accessToken: string; }) => { - const { data: getSecretsRes } = await request.get( + const { data: getSecretsRes } = await request.get<{ name: string; value: string }[]>( `${IntegrationUrls.SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, { headers: { @@ -1741,33 +1706,25 @@ const syncSecretsSupabase = async ({ } ); - const secretsToDelete: any = []; - getSecretsRes?.forEach((secretObj: any) => { + const secretsToDelete = getSecretsRes?.flatMap((secretObj) => { if ( !(secretObj.name in secrets) && // supbase reserved secret ref: https://supabase.com/docs/guides/functions/secrets#default-secrets - ![ - "SUPABASE_ANON_KEY", - "SUPABASE_SERVICE_ROLE_KEY", - "SUPABASE_DB_URL", - "SUPABASE_URL" - ].includes(secretObj.name) + !["SUPABASE_ANON_KEY", "SUPABASE_SERVICE_ROLE_KEY", "SUPABASE_DB_URL", "SUPABASE_URL"].includes(secretObj.name) ) { - secretsToDelete.push(secretObj.name); + return secretObj.name; } + return []; }); - await request.delete( - `${IntegrationUrls.SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - "Content-Type": "application/json", - "Accept-Encoding": "application/json" - }, - data: secretsToDelete - } - ); + await request.delete(`${IntegrationUrls.SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, { + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + "Accept-Encoding": "application/json" + }, + data: secretsToDelete + }); }; /** @@ -1788,7 +1745,7 @@ const syncSecretsCheckly = async ({ // sync secrets to checkly group envars let getGroupSecretsRes = ( - await request.get( + await request.get<{ environmentVariables: { key: string; value: string }[] }>( `${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups/${integration.targetServiceId}`, { headers: { @@ -1799,11 +1756,11 @@ const syncSecretsCheckly = async ({ } ) ).data.environmentVariables.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret.value }), - {} + {} as Record ); getGroupSecretsRes = Object.keys(getGroupSecretsRes).reduce( @@ -1846,7 +1803,7 @@ const syncSecretsCheckly = async ({ // sync secrets to checkly global envars let getSecretsRes = ( - await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/variables`, { + await request.get<{ key: string; value: string }[]>(`${IntegrationUrls.CHECKLY_API_URL}/v1/variables`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json", @@ -1854,11 +1811,11 @@ const syncSecretsCheckly = async ({ } }) ).data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret.value }), - {} + {} as Record ); getSecretsRes = Object.keys(getSecretsRes).reduce( @@ -1901,7 +1858,7 @@ const syncSecretsCheckly = async ({ ); // case: secret exists in checkly // -> update/set secret - } else if (secrets[key] !== getSecretsRes[key]) { + } else if (secrets[key].value !== getSecretsRes[key]) { await request.put( `${IntegrationUrls.CHECKLY_API_URL}/v1/variables/${key}`, { @@ -1951,7 +1908,7 @@ const syncSecretsQovery = async ({ accessToken: string; }) => { const getSecretsRes = ( - await request.get( + await request.get<{ results: { id: string; value: string; key: string }[] }>( `${IntegrationUrls.QOVERY_API_URL}/${integration.scope}/${integration.appId}/environmentVariable`, { headers: { @@ -1961,11 +1918,11 @@ const syncSecretsQovery = async ({ } ) ).data.results.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: { id: secret.id, value: secret.value } }), - {} + {} as Record ); // add secrets @@ -2042,7 +1999,7 @@ const syncSecretsTerraformCloud = async ({ }) => { // get secrets from Terraform Cloud const getSecretsRes = ( - await request.get( + await request.get<{ data: { attributes: { key: string; value: string }; id: string }[] }>( `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${integration.appId}/vars`, { headers: { @@ -2052,11 +2009,11 @@ const syncSecretsTerraformCloud = async ({ } ) ).data.data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.attributes.key]: secret }), - {} + {} as Record ); // create or update secrets on Terraform Cloud @@ -2138,7 +2095,7 @@ const syncSecretsTeamCity = async ({ }: { integrationAuth: TIntegrationAuths; integration: TIntegrations; - secrets: any; + secrets: Record; accessToken: string; }) => { interface TeamCitySecret { @@ -2171,13 +2128,16 @@ const syncSecretsTeamCity = async ({ ) ).data.property .filter((parameter) => !parameter.inherited) - .reduce((obj: any, secret: TeamCitySecret) => { - const secretName = secret.name.replace(/^env\./, ""); - return { - ...obj, - [secretName]: secret.value - }; - }, {}); + .reduce( + (obj, secret) => { + const secretName = secret.name.replace(/^env\./, ""); + return { + ...obj, + [secretName]: secret.value + }; + }, + {} as Record + ); for await (const key of Object.keys(secrets)) { if (!(key in res) || (key in res && secrets[key].value !== res[key])) { @@ -2216,7 +2176,7 @@ const syncSecretsTeamCity = async ({ } else { // case: sync to TeamCity project const res = ( - await request.get( + await request.get<{ property: TeamCitySecret[] }>( `${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`, { headers: { @@ -2225,16 +2185,19 @@ const syncSecretsTeamCity = async ({ } } ) - ).data.property.reduce((obj: any, secret: TeamCitySecret) => { - const secretName = secret.name.replace(/^env\./, ""); - return { - ...obj, - [secretName]: secret.value - }; - }, {}); + ).data.property.reduce( + (obj, secret) => { + const secretName = secret.name.replace(/^env\./, ""); + return { + ...obj, + [secretName]: secret.value + }; + }, + {} as Record + ); for await (const key of Object.keys(secrets)) { - if (!(key in res) || (key in res && secrets[key] !== res[key])) { + if (!(key in res) || (key in res && secrets[key].value !== res[key])) { // case: secret does not exist in TeamCity or secret value has changed // -> create/update secret await request.post( @@ -2256,15 +2219,12 @@ const syncSecretsTeamCity = async ({ for await (const key of Object.keys(res)) { if (!(key in secrets)) { // delete secret - await request.delete( - `${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters/env.${key}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" - } + await request.delete(`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters/env.${key}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" } - ); + }); } } } @@ -2347,33 +2307,23 @@ const syncSecretsCloudflarePages = async ({ }) => { // get secrets from cloudflare pages const getSecretsRes = ( - await request.get( - `${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accessId}/pages/projects/${integration.app}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" - } + await request.get<{ + result: { deployment_configs: Record }> }; + }>(`${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accessId}/pages/projects/${integration.app}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" } - ) + }) ).data.result.deployment_configs[integration.targetEnvironment as string].env_vars; // copy the secrets object, so we can set deleted keys to null - const secretsObj: any = getSecretKeyValuePair(secrets); - - for (const [key, val] of Object.entries(secretsObj)) { - secretsObj[key] = { type: "secret_text", value: val }; - } - - if (getSecretsRes) { - for await (const key of Object.keys(getSecretsRes)) { - if (!(key in secrets)) { - // case: secret does not exist in infisical - // -> delete secret from cloudflare pages - secretsObj[key] = null; - } - } - } + const secretsObj = Object.fromEntries( + Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [ + key, + key in Object.keys(getSecretsRes) ? { type: "secret_text", value: val } : null + ]) + ); const data = { deployment_configs: { @@ -2411,7 +2361,7 @@ const syncSecretsCloudflareWorkers = async ({ }) => { // get secrets from cloudflare workers const getSecretsRes = ( - await request.get( + await request.get<{ result: { name: string }[] }>( `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, { headers: { @@ -2422,33 +2372,33 @@ const syncSecretsCloudflareWorkers = async ({ ) ).data.result; - const secretsObj: any = getSecretKeyValuePair(secrets); - - for (const [key, val] of Object.entries(secretsObj)) { - secretsObj[key] = { type: "secret_text", value: val }; - } + const secretsObj = Object.fromEntries( + Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [key, { type: "secret_text", value: val }]) + ); // get deleted secrets list const deletedSecretKeys: string[] = []; if (getSecretsRes) { - getSecretsRes.forEach((secretRes: any) => { + getSecretsRes.forEach((secretRes) => { if (!Object.keys(secrets).includes(secretRes.name)) { deletedSecretKeys.push(secretRes.name); } }); } - deletedSecretKeys.forEach(async (secretKey) => { - await request.delete( - `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" + await Promise.all( + deletedSecretKeys.map(async (secretKey) => { + return request.delete( + `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" + } } - } - ); - }); + ); + }) + ); interface ConvertedSecret { name: string; @@ -2463,35 +2413,30 @@ const syncSecretsCloudflareWorkers = async ({ }; } - const data: ConvertedSecret[] = Object.entries(secretsObj as SecretsObj).map( - ([name, secret]) => ({ - name, - text: secret.value, - type: "secret_text" - }) - ); + const data: ConvertedSecret[] = Object.entries(secretsObj as SecretsObj).map(([name, secret]) => ({ + name, + text: secret.value, + type: "secret_text" + })); - data.forEach(async (secret) => { - await request.put( - `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, - secret, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" + await Promise.all( + data.map(async (secret) => { + return request.put( + `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, + secret, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" + } } - } - ); - }); + ); + }) + ); }; /** * Sync/push [secrets] to BitBucket repo with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for BitBucket integration */ const syncSecretsBitBucket = async ({ integration, @@ -2700,18 +2645,18 @@ const syncSecretsWindmill = async ({ // get secrets stored in windmill workspace const res = ( - await request.get(`${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`, { + await request.get(`${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" } }) ).data.reduce( - (obj: any, secret: WindmillSecret) => ({ + (obj, secret) => ({ ...obj, [secret.path]: secret }), - {} + {} as Record ); // eslint-disable-next-line @@ -2778,11 +2723,6 @@ const syncSecretsWindmill = async ({ /** * Sync/push [secrets] to Cloud66 application with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Cloud66 integration */ const syncSecretsCloud66 = async ({ integration, @@ -2802,12 +2742,12 @@ const syncSecretsCloud66 = async ({ updated_at: string; is_password: boolean; is_generated: boolean; - history: any[]; + history: unknown[]; } // get all current secrets const res = ( - await request.get( + await request.get<{ response: Cloud66Secret[] }>( `${IntegrationUrls.CLOUD_66_API_URL}/3/stacks/${integration.appId}/environments`, { headers: { @@ -2817,9 +2757,9 @@ const syncSecretsCloud66 = async ({ } ) ).data.response - .filter((secret: Cloud66Secret) => !secret.readonly || !secret.is_generated) + .filter((secret) => !secret.readonly || !secret.is_generated) .reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), @@ -2863,15 +2803,12 @@ const syncSecretsCloud66 = async ({ for await (const key of Object.keys(res)) { if (!(key in secrets)) { // delete secret - await request.delete( - `${IntegrationUrls.CLOUD_66_API_URL}/3/stacks/${integration.appId}/environments/${key}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" - } + await request.delete(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks/${integration.appId}/environments/${key}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" } - ); + }); } } }; @@ -2925,8 +2862,7 @@ const syncSecretsHasuraCloud = async ({ const res = await request.post( IntegrationUrls.HASURA_CLOUD_API_URL, { - query: - "query MyQuery($tenantId: uuid!) { getTenantEnv(tenantId: $tenantId) { hash envVars } }", + query: "query MyQuery($tenantId: uuid!) { getTenantEnv(tenantId: $tenantId) { hash envVars } }", variables: { tenantId: integration.appId } diff --git a/backend/src/services/integration-auth/integration-team.ts b/backend/src/services/integration-auth/integration-team.ts index 287e7cc7ae..81ef9b70c5 100644 --- a/backend/src/services/integration-auth/integration-team.ts +++ b/backend/src/services/integration-auth/integration-team.ts @@ -1,7 +1,7 @@ import { request } from "@app/lib/config/request"; import { BadRequestError } from "@app/lib/errors"; -import { Integrations,IntegrationUrls } from "./integration-list"; +import { Integrations, IntegrationUrls } from "./integration-list"; type Team = { name: string; @@ -12,7 +12,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken: let teams: Team[] = []; const res = ( - await request.get(`${gitLabApiUrl}/v4/groups`, { + await request.get<{ name: string; id: string }[]>(`${gitLabApiUrl}/v4/groups`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -20,7 +20,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken: }) ).data; - teams = res.map((t: any) => ({ + teams = res.map((t) => ({ name: t.name, teamId: t.id })); diff --git a/backend/src/services/integration-auth/integration-token.ts b/backend/src/services/integration-auth/integration-token.ts index f67b13a924..0907bd0747 100644 --- a/backend/src/services/integration-auth/integration-token.ts +++ b/backend/src/services/integration-auth/integration-token.ts @@ -80,8 +80,8 @@ const exchangeCodeGCP = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGCPResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.GCP_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -108,8 +108,8 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => { if (!appCfg.CLIENT_ID_AZURE || !appCfg.CLIENT_SECRET_AZURE) { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeAzureResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.AZURE_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -118,7 +118,7 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_AZURE, client_secret: appCfg.CLIENT_SECRET_AZURE, redirect_uri: `${appCfg.SITE_URL}/integrations/azure-key-vault/oauth2/callback` - } as any) + }) ) ).data; @@ -138,8 +138,8 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeHerokuResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.HEROKU_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -160,12 +160,6 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { /** * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel * code-token exchange - * @param {Object} obj1 - * @param {Object} obj1.code - code for code-token exchange - * @returns {Object} obj2 - * @returns {String} obj2.accessToken - access token for Heroku API - * @returns {String} obj2.refreshToken - refresh token for Heroku API - * @returns {Date} obj2.accessExpiresAt - date of expiration for access token */ const exchangeCodeVercel = async ({ code }: { code: string }) => { const appCfg = getConfig(); @@ -173,15 +167,15 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeVercelResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.VERCEL_TOKEN_URL, new URLSearchParams({ code, client_id: appCfg.CLIENT_ID_VERCEL, client_secret: appCfg.CLIENT_SECRET_VERCEL, redirect_uri: `${appCfg.SITE_URL}/integrations/vercel/oauth2/callback` - } as any) + }) ) ).data; @@ -196,12 +190,6 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { /** * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel * code-token exchange - * @param {Object} obj1 - * @param {Object} obj1.code - code for code-token exchange - * @returns {Object} obj2 - * @returns {String} obj2.accessToken - access token for Heroku API - * @returns {String} obj2.refreshToken - refresh token for Heroku API - * @returns {Date} obj2.accessExpiresAt - date of expiration for access token */ const exchangeCodeNetlify = async ({ code }: { code: string }) => { const appCfg = getConfig(); @@ -209,8 +197,8 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeNetlifyResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.NETLIFY_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -218,7 +206,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_NETLIFY, client_secret: appCfg.CLIENT_SECRET_NETLIFY, redirect_uri: `${appCfg.SITE_URL}/integrations/netlify/oauth2/callback` - } as any) + }) ) ).data; @@ -230,7 +218,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { // }); const res3 = ( - await request.get("https://api.netlify.com/api/v1/accounts", { + await request.get>("https://api.netlify.com/api/v1/accounts", { headers: { Authorization: `Bearer ${res.access_token}` } @@ -252,8 +240,8 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGithubResponse = ( - await request.get(IntegrationUrls.GITHUB_TOKEN_URL, { + const res = ( + await request.get(IntegrationUrls.GITHUB_TOKEN_URL, { params: { client_id: appCfg.CLIENT_ID_GITHUB, client_secret: appCfg.CLIENT_SECRET_GITHUB, @@ -285,8 +273,8 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string }) throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGitlabResponse = ( - await request.post( + const res = ( + await request.post( url ? `${url}/oauth/token` : IntegrationUrls.GITLAB_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -294,7 +282,7 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string }) client_id: appCfg.CLIENT_ID_GITLAB, client_secret: appCfg.CLIENT_SECRET_GITLAB, redirect_uri: `${appCfg.SITE_URL}/integrations/gitlab/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -324,8 +312,8 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeBitBucketResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.BITBUCKET_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -333,7 +321,7 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_BITBUCKET, client_secret: appCfg.CLIENT_SECRET_BITBUCKET, redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -530,13 +518,7 @@ const exchangeRefreshHeroku = async ({ refreshToken }: { refreshToken: string }) * @param {String} obj.refreshToken - refresh token to use to get new access token for GitLab * @returns */ -const exchangeRefreshGitLab = async ({ - refreshToken, - url -}: { - url?: string | null; - refreshToken: string; -}) => { +const exchangeRefreshGitLab = async ({ refreshToken, url }: { url?: string | null; refreshToken: string }) => { const accessExpiresAt = new Date(); const appCfg = getConfig(); if (!appCfg.CLIENT_ID_GITLAB || !appCfg.CLIENT_SECRET_GITLAB) { @@ -593,7 +575,7 @@ const exchangeRefreshBitBucket = async ({ refreshToken }: { refreshToken: string client_id: appCfg.CLIENT_ID_BITBUCKET, client_secret: appCfg.CLIENT_SECRET_BITBUCKET, redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -624,7 +606,11 @@ const exchangeRefreshGCPSecretManager = async ({ const accessExpiresAt = new Date(); if (metadata?.authMethod === "serviceAccount") { - const serviceAccount = JSON.parse(refreshToken); + const serviceAccount = JSON.parse(refreshToken) as { + client_email: string; + token_uri: string; + private_key: string; + }; const payload = { iss: serviceAccount.client_email, @@ -636,19 +622,18 @@ const exchangeRefreshGCPSecretManager = async ({ const token = jwt.sign(payload, serviceAccount.private_key, { algorithm: "RS256" }); - const { data }: { data: ServiceAccountAccessTokenGCPSecretManagerResponse } = - await request.post( - IntegrationUrls.GCP_TOKEN_URL, - new URLSearchParams({ - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: token - }).toString(), - { - headers: { - "Content-Type": "application/x-www-form-urlencoded" - } + const { data }: { data: ServiceAccountAccessTokenGCPSecretManagerResponse } = await request.post( + IntegrationUrls.GCP_TOKEN_URL, + new URLSearchParams({ + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: token + }).toString(), + { + headers: { + "Content-Type": "application/x-www-form-urlencoded" } - ); + } + ); accessExpiresAt.setSeconds(accessExpiresAt.getSeconds() + data.expires_in); @@ -663,14 +648,14 @@ const exchangeRefreshGCPSecretManager = async ({ if (!appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER || !appCfg.CLIENT_ID_GCP_SECRET_MANAGER) { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const { data }: { data: RefreshTokenGCPSecretManagerResponse } = await request.post( + const { data } = await request.post( IntegrationUrls.GCP_TOKEN_URL, new URLSearchParams({ client_id: appCfg.CLIENT_ID_GCP_SECRET_MANAGER, client_secret: appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER, refresh_token: refreshToken, grant_type: "refresh_token" - } as any) + }) ); accessExpiresAt.setSeconds(accessExpiresAt.getSeconds() + data.expires_in); diff --git a/backend/src/services/integration/integration-dal.ts b/backend/src/services/integration/integration-dal.ts index 446af0beae..bada253c59 100644 --- a/backend/src/services/integration/integration-dal.ts +++ b/backend/src/services/integration/integration-dal.ts @@ -66,11 +66,7 @@ export const integrationDALFactory = (db: TDbClient) => { try { const integrations = await (tx || db)(TableName.Integration) .where(`${TableName.Environment}.projectId`, projectId) - .join( - TableName.Environment, - `${TableName.Integration}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.Integration}.envId`, `${TableName.Environment}.id`) .select(db.ref("name").withSchema(TableName.Environment).as("envName")) .select(db.ref("slug").withSchema(TableName.Environment).as("envSlug")) .select(db.ref("id").withSchema(TableName.Environment).as("envId")) @@ -99,11 +95,7 @@ export const integrationDALFactory = (db: TDbClient) => { .where("isActive", true) .where(`${TableName.Environment}.slug`, environment) .join(TableName.Environment, `${TableName.Integration}.envId`, `${TableName.Environment}.id`) - .join( - TableName.IntegrationAuth, - `${TableName.IntegrationAuth}.id`, - `${TableName.Integration}.integrationAuthId` - ) + .join(TableName.IntegrationAuth, `${TableName.IntegrationAuth}.id`, `${TableName.Integration}.integrationAuthId`) .select(db.ref("name").withSchema(TableName.Environment).as("envName")) .select(db.ref("slug").withSchema(TableName.Environment).as("envSlug")) .select(db.ref("id").withSchema(TableName.Environment).as("envId")) @@ -119,10 +111,7 @@ export const integrationDALFactory = (db: TDbClient) => { db.ref("refreshCiphertext").withSchema(TableName.IntegrationAuth).as("refreshCiphertextAu"), db.ref("refreshIV").withSchema(TableName.IntegrationAuth).as("refreshIVAu"), db.ref("refreshTag").withSchema(TableName.IntegrationAuth).as("refreshTagAu"), - db - .ref("accessIdCiphertext") - .withSchema(TableName.IntegrationAuth) - .as("accessIdCiphertextAu"), + db.ref("accessIdCiphertext").withSchema(TableName.IntegrationAuth).as("accessIdCiphertextAu"), db.ref("accessIdIV").withSchema(TableName.IntegrationAuth).as("accessIdIVAu"), db.ref("accessIdTag").withSchema(TableName.IntegrationAuth).as("accessIdTagAu"), db.ref("accessIV").withSchema(TableName.IntegrationAuth).as("accessIVAu"), diff --git a/backend/src/services/integration/integration-service.ts b/backend/src/services/integration/integration-service.ts index ba93b37fad..b7f74966ea 100644 --- a/backend/src/services/integration/integration-service.ts +++ b/backend/src/services/integration/integration-service.ts @@ -1,10 +1,7 @@ import { ForbiddenError } from "@casl/ability"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { TProjectPermission } from "@app/lib/types"; @@ -12,11 +9,7 @@ import { TIntegrationAuthDALFactory } from "../integration-auth/integration-auth import { TSecretQueueFactory } from "../secret/secret-queue"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TIntegrationDALFactory } from "./integration-dal"; -import { - TCreateIntegrationDTO, - TDeleteIntegrationDTO, - TUpdateIntegrationDTO -} from "./integration-types"; +import { TCreateIntegrationDTO, TDeleteIntegrationDTO, TUpdateIntegrationDTO } from "./integration-types"; type TIntegrationServiceFactoryDep = { integrationDAL: TIntegrationDALFactory; @@ -57,21 +50,10 @@ export const integrationServiceFactory = ({ const integrationAuth = await integrationAuthDAL.findById(integrationAuthId); if (!integrationAuth) throw new BadRequestError({ message: "Integration auth not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integrationAuth.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Integrations - ); - - const folder = await folderDAL.findBySecretPath( - integrationAuth.projectId, - sourceEnvironment, - secretPath - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); + + const folder = await folderDAL.findBySecretPath(integrationAuth.projectId, sourceEnvironment, secretPath); if (!folder) throw new BadRequestError({ message: "Folder path not found" }); const integration = await integrationDAL.create({ @@ -116,15 +98,8 @@ export const integrationServiceFactory = ({ const integration = await integrationDAL.findById(id); if (!integration) throw new BadRequestError({ message: "Integration auth not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integration.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations); const folder = await folderDAL.findBySecretPath(integration.projectId, environment, secretPath); if (!folder) throw new BadRequestError({ message: "Folder path not found" }); @@ -146,15 +121,8 @@ export const integrationServiceFactory = ({ const integration = await integrationDAL.findById(id); if (!integration) throw new BadRequestError({ message: "Integration auth not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - integration.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); const deletedIntegration = await integrationDAL.deleteById(id); return { ...integration, ...deletedIntegration }; @@ -162,10 +130,7 @@ export const integrationServiceFactory = ({ const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const integrations = await integrationDAL.findByProjectId(projectId); return integrations; diff --git a/backend/src/services/org/incident-contacts-dal.ts b/backend/src/services/org/incident-contacts-dal.ts index c175162410..1979a9c3e5 100644 --- a/backend/src/services/org/incident-contacts-dal.ts +++ b/backend/src/services/org/incident-contacts-dal.ts @@ -7,9 +7,7 @@ export type TIncidentContactsDALFactory = ReturnType { const create = async (orgId: string, email: string) => { try { - const [incidentContact] = await db(TableName.IncidentContact) - .insert({ orgId, email }) - .returning("*"); + const [incidentContact] = await db(TableName.IncidentContact).insert({ orgId, email }).returning("*"); return incidentContact; } catch (error) { throw new DatabaseError({ name: "Incident contact create", error }); @@ -38,10 +36,7 @@ export const incidentContactDALFactory = (db: TDbClient) => { const deleteById = async (id: string, orgId: string) => { try { - const [incidentContact] = await db(TableName.IncidentContact) - .where({ orgId, id }) - .delete() - .returning("*"); + const [incidentContact] = await db(TableName.IncidentContact).where({ orgId, id }).delete().returning("*"); return incidentContact; } catch (error) { throw new DatabaseError({ name: "Incident contact delete", error }); diff --git a/backend/src/services/org/org-dal.ts b/backend/src/services/org/org-dal.ts index 51ab59f689..6629030d20 100644 --- a/backend/src/services/org/org-dal.ts +++ b/backend/src/services/org/org-dal.ts @@ -7,16 +7,11 @@ import { TOrganizationsInsert, TOrgMemberships, TOrgMembershipsInsert, - TOrgMembershipsUpdate + TOrgMembershipsUpdate, + TUserEncryptionKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { - buildFindFilter, - selectAllTableCols, - TFindFilter, - TFindOpt, - withTransaction -} from "@app/lib/knex"; +import { buildFindFilter, selectAllTableCols, TFindFilter, TFindOpt, withTransaction } from "@app/lib/knex"; export type TOrgDALFactory = ReturnType; @@ -35,12 +30,8 @@ export const orgDALFactory = (db: TDbClient) => { try { const org = await db(TableName.OrgMembership) .where({ userId }) - .join( - TableName.Organization, - `${TableName.OrgMembership}.orgId`, - `${TableName.Organization}.id` - ) - .select(`${TableName.Organization}.*`); + .join(TableName.Organization, `${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`) + .select(selectAllTableCols(TableName.Organization)); return org; } catch (error) { throw new DatabaseError({ error, name: "Find all org by user id" }); @@ -50,9 +41,9 @@ export const orgDALFactory = (db: TDbClient) => { const findOrgByProjectId = async (projectId: string): Promise => { try { const [org] = await db(TableName.Project) - .where({ [`${[TableName.Project]}.id`]: projectId }) + .where({ [`${TableName.Project}.id` as "id"]: projectId }) .join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`) - .select(`${TableName.Organization}.*`); + .select(selectAllTableCols(TableName.Organization)); return org; } catch (error) { @@ -66,7 +57,7 @@ export const orgDALFactory = (db: TDbClient) => { const members = await db(TableName.OrgMembership) .where({ orgId }) .join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`) - .leftJoin( + .leftJoin( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` @@ -104,10 +95,7 @@ export const orgDALFactory = (db: TDbClient) => { const deleteById = async (orgId: string, tx?: Knex) => { try { - const [org] = await (tx || db)(TableName.Organization) - .where({ id: orgId }) - .delete() - .returning("*"); + const [org] = await (tx || db)(TableName.Organization).where({ id: orgId }).delete().returning("*"); return org; } catch (error) { throw new DatabaseError({ error, name: "Update organization" }); @@ -141,26 +129,16 @@ export const orgDALFactory = (db: TDbClient) => { const updateMembershipById = async (id: string, data: TOrgMembershipsUpdate, tx?: Knex) => { try { - const [membership] = await (tx || db)(TableName.OrgMembership) - .where({ id }) - .update(data) - .returning("*"); + const [membership] = await (tx || db)(TableName.OrgMembership).where({ id }).update(data).returning("*"); return membership; } catch (error) { throw new DatabaseError({ error, name: "Update org membership" }); } }; - const updateMembership = async ( - filter: Partial, - data: TOrgMembershipsUpdate, - tx?: Knex - ) => { + const updateMembership = async (filter: Partial, data: TOrgMembershipsUpdate, tx?: Knex) => { try { - const membership = await (tx || db)(TableName.OrgMembership) - .where(filter) - .update(data) - .returning("*"); + const membership = await (tx || db)(TableName.OrgMembership).where(filter).update(data).returning("*"); return membership; } catch (error) { throw new DatabaseError({ error, name: "Update org memberships" }); @@ -169,10 +147,7 @@ export const orgDALFactory = (db: TDbClient) => { const deleteMembershipById = async (id: string, orgId: string, tx?: Knex) => { try { - const [membership] = await (tx || db)(TableName.OrgMembership) - .where({ id, orgId }) - .delete() - .returning("*"); + const [membership] = await (tx || db)(TableName.OrgMembership).where({ id, orgId }).delete().returning("*"); return membership; } catch (error) { throw new DatabaseError({ error, name: "Delete org membership" }); @@ -185,18 +160,14 @@ export const orgDALFactory = (db: TDbClient) => { ) => { try { const query = (tx || db)(TableName.OrgMembership) + // eslint-disable-next-line .where(buildFindFilter(filter)) .join(TableName.Users, `${TableName.Users}.id`, `${TableName.OrgMembership}.userId`) - .select( - selectAllTableCols(TableName.OrgMembership), - db.ref("email").withSchema(TableName.Users) - ); - if (limit) query.limit(limit); - if (offset) query.offset(offset); + .select(selectAllTableCols(TableName.OrgMembership), db.ref("email").withSchema(TableName.Users)); + if (limit) void query.limit(limit); + if (offset) void query.offset(offset); if (sort) { - query.orderBy( - sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })) - ); + void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls }))); } const res = await query; return res; diff --git a/backend/src/services/org/org-role-service.ts b/backend/src/services/org/org-role-service.ts index 8dfd0e0af7..c48002d894 100644 --- a/backend/src/services/org/org-role-service.ts +++ b/backend/src/services/org/org-role-service.ts @@ -21,20 +21,10 @@ type TOrgRoleServiceFactoryDep = { export type TOrgRoleServiceFactory = ReturnType; -export const orgRoleServiceFactory = ({ - orgRoleDAL, - permissionService -}: TOrgRoleServiceFactoryDep) => { - const createRole = async ( - userId: string, - orgId: string, - data: Omit - ) => { +export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRoleServiceFactoryDep) => { + const createRole = async (userId: string, orgId: string, data: Omit) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Role - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Role); const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId }); if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" }); const role = await orgRoleDAL.create({ @@ -45,17 +35,9 @@ export const orgRoleServiceFactory = ({ return role; }; - const updateRole = async ( - userId: string, - orgId: string, - roleId: string, - data: Omit - ) => { + const updateRole = async (userId: string, orgId: string, roleId: string, data: Omit) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Role - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Role); if (data?.slug) { const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId }); if (existingRole && existingRole.id !== roleId) @@ -71,10 +53,7 @@ export const orgRoleServiceFactory = ({ const deleteRole = async (userId: string, orgId: string, roleId: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Delete, - OrgPermissionSubjects.Role - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Role); const [deletedRole] = await orgRoleDAL.delete({ id: roleId, orgId }); if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" }); @@ -83,10 +62,7 @@ export const orgRoleServiceFactory = ({ const listRoles = async (userId: string, orgId: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Role - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Role); const customRoles = await orgRoleDAL.find({ orgId }); const roles = [ { diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 69772e8831..a393edcb5b 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -5,10 +5,7 @@ import jwt from "jsonwebtoken"; import { OrgMembershipRole, OrgMembershipStatus } from "@app/db/schemas"; import { TProjects } from "@app/db/schemas/projects"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; -import { - OrgPermissionActions, - OrgPermissionSubjects -} from "@app/ee/services/permission/org-permission"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TSamlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal"; import { getConfig } from "@app/lib/config/env"; @@ -74,8 +71,7 @@ export const orgServiceFactory = ({ const findOrganizationById = async (userId: string, orgId: string) => { await permissionService.getUserOrgPermission(userId, orgId); const org = await orgDAL.findOrgById(orgId); - if (!org) - throw new BadRequestError({ name: "Org not found", message: "Organization not found" }); + if (!org) throw new BadRequestError({ name: "Org not found", message: "Organization not found" }); return org; }; /* @@ -90,10 +86,7 @@ export const orgServiceFactory = ({ * */ const findAllOrgMembers = async (userId: string, orgId: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Member - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member); const members = await orgDAL.findAllOrgMembers(orgId); return members; @@ -101,14 +94,9 @@ export const orgServiceFactory = ({ const findAllWorkspaces = async ({ actor, actorId, orgId }: TFindAllWorkspacesDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.Workspace - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Workspace); - const organizationWorkspaceIds = new Set( - (await projectDAL.find({ orgId })).map((workspace) => workspace.id) - ); + const organizationWorkspaceIds = new Set((await projectDAL.find({ orgId })).map((workspace) => workspace.id)); let workspaces: (TProjects & { organization: string } & { environments: { @@ -134,13 +122,9 @@ export const orgServiceFactory = ({ * */ const updateOrgName = async (userId: string, orgId: string, name: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Settings - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings); const org = await orgDAL.updateById(orgId, { name }); - if (!org) - throw new BadRequestError({ name: "Org not found", message: "Organization not found" }); + if (!org) throw new BadRequestError({ name: "Org not found", message: "Organization not found" }); return org; }; /* @@ -209,7 +193,7 @@ export const orgServiceFactory = ({ * */ const deleteOrganizationById = async (userId: string, orgId: string) => { const { membership } = await permissionService.getUserOrgPermission(userId, orgId); - if (membership.role !== OrgMembershipRole.Admin) + if ((membership.role as OrgMembershipRole) !== OrgMembershipRole.Admin) throw new UnauthorizedError({ name: "Delete org by id", message: "Not an admin" }); const organization = await orgDAL.deleteById(orgId); @@ -222,29 +206,19 @@ export const orgServiceFactory = ({ * Org membership management * Not another service because it has close ties with how an org works doesn't make sense to seperate them * */ - const updateOrgMembership = async ({ - role, - orgId, - userId, - membershipId - }: TUpdateOrgMembershipDTO) => { + const updateOrgMembership = async ({ role, orgId, userId, membershipId }: TUpdateOrgMembershipDTO) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Edit, - OrgPermissionSubjects.Member - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member); const isCustomRole = !Object.values(OrgMembershipRole).includes(role as OrgMembershipRole); if (isCustomRole) { const customRole = await orgRoleDAL.findOne({ slug: role, orgId }); - if (!customRole) - throw new BadRequestError({ name: "Update membership", message: "Role not found" }); + if (!customRole) throw new BadRequestError({ name: "Update membership", message: "Role not found" }); const plan = await licenseService.getPlan(orgId); if (!plan?.rbac) throw new BadRequestError({ - message: - "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member." + message: "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member." }); const [membership] = await orgDAL.updateMembership( @@ -257,10 +231,7 @@ export const orgServiceFactory = ({ return membership; } - const [membership] = await orgDAL.updateMembership( - { id: membershipId, orgId }, - { role, roleId: null } - ); + const [membership] = await orgDAL.updateMembership({ id: membershipId, orgId }, { role, roleId: null }); return membership; }; /* @@ -268,10 +239,7 @@ export const orgServiceFactory = ({ */ const inviteUserToOrganization = async ({ orgId, userId, inviteeEmail }: TInviteUserToOrgDTO) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Member - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member); const samlCfg = await samlConfigDAL.findOne({ orgId }); if (samlCfg && samlCfg.isActive) { @@ -284,8 +252,7 @@ export const orgServiceFactory = ({ // case: limit imposed on number of members allowed // case: number of members used exceeds the number of members allowed throw new BadRequestError({ - message: - "Failed to invite member due to member limit reached. Upgrade plan to invite more members." + message: "Failed to invite member due to member limit reached. Upgrade plan to invite more members." }); } const invitee = await orgDAL.transaction(async (tx) => { @@ -293,10 +260,7 @@ export const orgServiceFactory = ({ if (inviteeUser) { // if user already exist means its already part of infisical // Thus the signup flow is not needed anymore - const [inviteeMembership] = await orgDAL.findMembership( - { orgId, userId: inviteeUser.id }, - { tx } - ); + const [inviteeMembership] = await orgDAL.findMembership({ orgId, userId: inviteeUser.id }, { tx }); if (inviteeMembership && inviteeMembership.status === OrgMembershipStatus.Accepted) { throw new BadRequestError({ message: "Failed to invite an existing member of org", @@ -432,10 +396,7 @@ export const orgServiceFactory = ({ const deleteOrgMembership = async ({ orgId, userId, membershipId }: TDeleteOrgMembershipDTO) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Delete, - OrgPermissionSubjects.Member - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member); const membership = await orgDAL.deleteMembershipById(membershipId, orgId); @@ -448,20 +409,14 @@ export const orgServiceFactory = ({ * */ const findIncidentContacts = async (userId: string, orgId: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Read, - OrgPermissionSubjects.IncidentAccount - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.IncidentAccount); const incidentContacts = await incidentContactDAL.findByOrgId(orgId); return incidentContacts; }; const createIncidentContact = async (userId: string, orgId: string, email: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.IncidentAccount - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.IncidentAccount); const doesIncidentContactExist = await incidentContactDAL.findOne(orgId, { email }); if (doesIncidentContactExist) { throw new BadRequestError({ @@ -476,10 +431,7 @@ export const orgServiceFactory = ({ const deleteIncidentContact = async (userId: string, orgId: string, id: string) => { const { permission } = await permissionService.getUserOrgPermission(userId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Delete, - OrgPermissionSubjects.IncidentAccount - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.IncidentAccount); const incidentContact = await incidentContactDAL.deleteById(id, orgId); return incidentContact; diff --git a/backend/src/services/project-bot/project-bot-dal.ts b/backend/src/services/project-bot/project-bot-dal.ts index 39a8628b85..7f342f0ae4 100644 --- a/backend/src/services/project-bot/project-bot-dal.ts +++ b/backend/src/services/project-bot/project-bot-dal.ts @@ -15,11 +15,7 @@ export const projectBotDALFactory = (db: TDbClient) => { const bot = await (tx || db)(TableName.ProjectBot) .where(filter) .leftJoin(TableName.Users, `${TableName.ProjectBot}.senderId`, `${TableName.Users}.id`) - .leftJoin( - TableName.UserEncryptionKey, - `${TableName.UserEncryptionKey}.userId`, - `${TableName.Users}.id` - ) + .leftJoin(TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id`) .select(selectAllTableCols(TableName.ProjectBot)) .select(db.ref("publicKey").withSchema(TableName.UserEncryptionKey).as("senderPubKey")) .first(); diff --git a/backend/src/services/project-bot/project-bot-service.ts b/backend/src/services/project-bot/project-bot-service.ts index 8a3fd19d90..5478aadfab 100644 --- a/backend/src/services/project-bot/project-bot-service.ts +++ b/backend/src/services/project-bot/project-bot-service.ts @@ -2,10 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; import { decryptAsymmetric, @@ -28,10 +25,7 @@ type TProjectBotServiceFactoryDep = { export type TProjectBotServiceFactory = ReturnType; -export const projectBotServiceFactory = ({ - projectBotDAL, - permissionService -}: TProjectBotServiceFactoryDep) => { +export const projectBotServiceFactory = ({ projectBotDAL, permissionService }: TProjectBotServiceFactoryDep) => { const getBotKey = async (projectId: string) => { const appCfg = getConfig(); const encryptionKey = appCfg.ENCRYPTION_KEY; @@ -43,7 +37,7 @@ export const projectBotServiceFactory = ({ if (!bot.encryptedProjectKeyNonce || !bot.encryptedProjectKey) throw new BadRequestError({ message: "Encryption key missing" }); - if (rootEncryptionKey && bot.keyEncoding === SecretKeyEncoding.BASE64) { + if (rootEncryptionKey && (bot.keyEncoding as SecretKeyEncoding) === SecretKeyEncoding.BASE64) { const privateKeyBot = decryptSymmetric({ iv: bot.iv, tag: bot.tag, @@ -57,7 +51,7 @@ export const projectBotServiceFactory = ({ publicKey: bot.sender.publicKey }); } - if (encryptionKey && bot.keyEncoding === SecretKeyEncoding.UTF8) { + if (encryptionKey && (bot.keyEncoding as SecretKeyEncoding) === SecretKeyEncoding.UTF8) { const privateKeyBot = decryptSymmetric128BitHexKeyUTF8({ iv: bot.iv, tag: bot.tag, @@ -79,10 +73,7 @@ export const projectBotServiceFactory = ({ const findBotByProjectId = async ({ actorId, actor, projectId }: TProjectPermission) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Integrations - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); const appCfg = getConfig(); const bot = await projectBotDAL.transaction(async (tx) => { @@ -108,10 +99,7 @@ export const projectBotServiceFactory = ({ ); } if (appCfg.ENCRYPTION_KEY) { - const { iv, tag, ciphertext } = encryptSymmetric128BitHexKeyUTF8( - privateKey, - appCfg.ENCRYPTION_KEY - ); + const { iv, tag, ciphertext } = encryptSymmetric128BitHexKeyUTF8(privateKey, appCfg.ENCRYPTION_KEY); return projectBotDAL.create( { name: "Infisical Bot", @@ -132,25 +120,12 @@ export const projectBotServiceFactory = ({ return bot; }; - const setBotActiveState = async ({ - actor, - botId, - botKey, - actorId, - isActive - }: TSetActiveStateDTO) => { + const setBotActiveState = async ({ actor, botId, botKey, actorId, isActive }: TSetActiveStateDTO) => { const bot = await projectBotDAL.findById(botId); if (!bot) throw new BadRequestError({ message: "Bot not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - bot.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Integrations - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, bot.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations); if (isActive) { if (!botKey?.nonce || !botKey?.encryptedKey) { diff --git a/backend/src/services/project-env/project-env-dal.ts b/backend/src/services/project-env/project-env-dal.ts index c74e8803c0..42a2342987 100644 --- a/backend/src/services/project-env/project-env-dal.ts +++ b/backend/src/services/project-env/project-env-dal.ts @@ -12,9 +12,7 @@ export const projectEnvDALFactory = (db: TDbClient) => { const findBySlugs = async (projectId: string, env: string[], tx?: Knex) => { try { - const envs = await (tx || db)(TableName.Environment) - .where("projectId", projectId) - .whereIn("slug", env); + const envs = await (tx || db)(TableName.Environment).where("projectId", projectId).whereIn("slug", env); return envs; } catch (error) { throw new DatabaseError({ error, name: "Find by slugs" }); @@ -26,17 +24,12 @@ export const projectEnvDALFactory = (db: TDbClient) => { const findLastEnvPosition = async (projectId: string, tx?: Knex) => { const lastPos = await (tx || db)(TableName.Environment) .where({ projectId }) - .max({ position: "position" }) + .max("position", { as: "position" }) .first(); return lastPos?.position || 0; }; - const updateAllPosition = async ( - projectId: string, - pos: number, - targetPos: number, - tx?: Knex - ) => { + const updateAllPosition = async (projectId: string, pos: number, targetPos: number, tx?: Knex) => { try { if (targetPos === -1) { // this means delete diff --git a/backend/src/services/project-env/project-env-service.ts b/backend/src/services/project-env/project-env-service.ts index d95bb79509..c430548cf9 100644 --- a/backend/src/services/project-env/project-env-service.ts +++ b/backend/src/services/project-env/project-env-service.ts @@ -2,10 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { TProjectDALFactory } from "../project/project-dal"; @@ -32,10 +29,7 @@ export const projectEnvServiceFactory = ({ }: TProjectEnvServiceFactoryDep) => { const createEnvironment = async ({ projectId, actorId, actor, name, slug }: TCreateEnvDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Environments - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Environments); const envs = await projectEnvDAL.find({ projectId }); const existingEnv = envs.find(({ slug: envSlug }) => envSlug === slug); @@ -65,20 +59,9 @@ export const projectEnvServiceFactory = ({ return env; }; - const updateEnvironment = async ({ - projectId, - slug, - actor, - actorId, - name, - id, - position - }: TUpdateEnvDTO) => { + const updateEnvironment = async ({ projectId, slug, actor, actorId, name, id, position }: TUpdateEnvDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Environments - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Environments); const oldEnv = await projectEnvDAL.findOne({ id, projectId }); if (!oldEnv) throw new BadRequestError({ message: "Environment not found" }); @@ -104,10 +87,7 @@ export const projectEnvServiceFactory = ({ const deleteEnvironment = async ({ projectId, actor, actorId, id }: TDeleteEnvDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Environments - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Environments); const env = await projectEnvDAL.transaction(async (tx) => { const [doc] = await projectEnvDAL.delete({ id, projectId }, tx); diff --git a/backend/src/services/project-key/project-key-dal.ts b/backend/src/services/project-key/project-key-dal.ts index b183a933b2..7423a48de7 100644 --- a/backend/src/services/project-key/project-key-dal.ts +++ b/backend/src/services/project-key/project-key-dal.ts @@ -1,7 +1,7 @@ import { TDbClient } from "@app/db"; import { TableName, TProjectKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { ormify } from "@app/lib/knex"; +import { ormify, selectAllTableCols } from "@app/lib/knex"; export type TProjectKeyDALFactory = ReturnType; @@ -11,25 +11,19 @@ export const projectKeyDALFactory = (db: TDbClient) => { const findLatestProjectKey = async ( userId: string, projectId: string - ): Promise => { + ): Promise<(TProjectKeys & { sender: { publicKey: string } }) | undefined> => { try { const projectKey = await db(TableName.ProjectKeys) - .where({ projectId, receiverId: userId }) .join(TableName.Users, `${TableName.ProjectKeys}.senderId`, `${TableName.Users}.id`) - .join( - TableName.UserEncryptionKey, - `${TableName.UserEncryptionKey}.userId`, - `${TableName.Users}.id` - ) + .join(TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id`) + .where({ projectId, receiverId: userId }) .orderBy("createdAt", "desc", "last") - .select(`${TableName.ProjectKeys}.*`, `${TableName.UserEncryptionKey}.publicKey`) + .select(selectAllTableCols(TableName.ProjectKeys)) + .select(db.ref("publicKey").withSchema(TableName.UserEncryptionKey)) .first(); if (projectKey) { - projectKey.sender = { - publicKey: projectKey.publicKey - }; + return { ...projectKey, sender: { publicKey: projectKey.publicKey } }; } - return projectKey; } catch (error) { throw new DatabaseError({ error, name: "Find latest project key" }); } @@ -40,11 +34,7 @@ export const projectKeyDALFactory = (db: TDbClient) => { const pubKeys = await db(TableName.ProjectMembership) .where({ projectId }) .join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`) - .join( - TableName.UserEncryptionKey, - `${TableName.Users}.id`, - `${TableName.UserEncryptionKey}.userId` - ) + .join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`) .select("userId", "publicKey"); return pubKeys; } catch (error) { diff --git a/backend/src/services/project-key/project-key-service.ts b/backend/src/services/project-key/project-key-service.ts index 76694217f1..e7ebc23ee1 100644 --- a/backend/src/services/project-key/project-key-service.ts +++ b/backend/src/services/project-key/project-key-service.ts @@ -1,10 +1,7 @@ import { ForbiddenError } from "@casl/ability"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal"; @@ -33,10 +30,7 @@ export const projectKeyServiceFactory = ({ encryptedKey }: TUploadProjectKeyDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member); const receiverMembership = await projectMembershipDAL.findOne({ userId: receiverId, @@ -59,10 +53,7 @@ export const projectKeyServiceFactory = ({ const getProjectPublicKeys = async ({ actor, actorId, projectId }: TGetLatestProjectKeyDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Member); return projectKeyDAL.findAllProjectUserPubKeys(projectId); }; diff --git a/backend/src/services/project-membership/project-membership-dal.ts b/backend/src/services/project-membership/project-membership-dal.ts index 86cfa55b43..22b9937a95 100644 --- a/backend/src/services/project-membership/project-membership-dal.ts +++ b/backend/src/services/project-membership/project-membership-dal.ts @@ -1,5 +1,5 @@ import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; +import { TableName, TUserEncryptionKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -14,7 +14,7 @@ export const projectMembershipDALFactory = (db: TDbClient) => { const members = await db(TableName.ProjectMembership) .where({ projectId }) .join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`) - .join( + .join( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` @@ -25,10 +25,10 @@ export const projectMembershipDALFactory = (db: TDbClient) => { db.ref("role").withSchema(TableName.ProjectMembership), db.ref("roleId").withSchema(TableName.ProjectMembership), db.ref("email").withSchema(TableName.Users), + db.ref("publicKey").withSchema(TableName.UserEncryptionKey), db.ref("firstName").withSchema(TableName.Users), db.ref("lastName").withSchema(TableName.Users), - db.ref("id").withSchema(TableName.Users).as("userId"), - db.ref("publicKey").withSchema(TableName.UserEncryptionKey) + db.ref("id").withSchema(TableName.Users).as("userId") ); return members.map(({ email, firstName, lastName, publicKey, ...data }) => ({ ...data, diff --git a/backend/src/services/project-membership/project-membership-service.ts b/backend/src/services/project-membership/project-membership-service.ts index d2b4901a09..862c19384a 100644 --- a/backend/src/services/project-membership/project-membership-service.ts +++ b/backend/src/services/project-membership/project-membership-service.ts @@ -3,10 +3,7 @@ import { ForbiddenError } from "@casl/ability"; import { OrgMembershipStatus, ProjectMembershipRole, TableName } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { groupBy } from "@app/lib/fn"; @@ -53,25 +50,14 @@ export const projectMembershipServiceFactory = ({ }: TProjectMembershipServiceFactoryDep) => { const getProjectMemberships = async ({ actorId, actor, projectId }: TGetProjectMembershipDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Member); return projectMembershipDAL.findAllProjectMembers(projectId); }; - const inviteUserToProject = async ({ - actorId, - actor, - projectId, - email - }: TInviteUserToProjectDTO) => { + const inviteUserToProject = async ({ actorId, actor, projectId, email }: TInviteUserToProjectDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Member); const invitee = await userDAL.findOne({ email }); if (!invitee || !invitee.isAccepted) @@ -126,37 +112,25 @@ export const projectMembershipServiceFactory = ({ return { invitee, latestKey }; }; - const addUsersToProject = async ({ - projectId, - actorId, - actor, - members - }: TAddUsersToWorkspaceDTO) => { + const addUsersToProject = async ({ projectId, actorId, actor, members }: TAddUsersToWorkspaceDTO) => { const project = await projectDAL.findById(projectId); if (!project) throw new BadRequestError({ message: "Project not found" }); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Member); const orgMembers = await orgDAL.findMembership({ orgId: project.orgId, $in: { - [`${TableName.OrgMembership}.id` as "id"]: members.map( - ({ orgMembershipId }) => orgMembershipId - ) + [`${TableName.OrgMembership}.id` as "id"]: members.map(({ orgMembershipId }) => orgMembershipId) } }); - if (orgMembers.length !== members.length) - throw new BadRequestError({ message: "Some users are not part of org" }); + if (orgMembers.length !== members.length) throw new BadRequestError({ message: "Some users are not part of org" }); const existingMembers = await projectMembershipDAL.find({ projectId, $in: { userId: orgMembers.map(({ userId }) => userId).filter(Boolean) as string[] } }); - if (existingMembers.length) - throw new BadRequestError({ message: "Some users are already part of project" }); + if (existingMembers.length) throw new BadRequestError({ message: "Some users are already part of project" }); await projectMembershipDAL.transaction(async (tx) => { await projectMembershipDAL.insertMany( @@ -184,7 +158,7 @@ export const projectMembershipServiceFactory = ({ await smtpService.sendMail({ template: SmtpTemplates.WorkspaceInvite, subjectLine: "Infisical workspace invitation", - recipients: orgMembers.map(({ email }) => email).filter(Boolean) as string[], + recipients: orgMembers.map(({ email }) => email).filter(Boolean), substitutions: { inviterFirstName: sender.firstName, inviterEmail: sender.email, @@ -203,24 +177,17 @@ export const projectMembershipServiceFactory = ({ role }: TUpdateProjectMembershipDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member); - const isCustomRole = !Object.values(ProjectMembershipRole).includes( - role as ProjectMembershipRole - ); + const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole); if (isCustomRole) { const customRole = await projectRoleDAL.findOne({ slug: role, projectId }); - if (!customRole) - throw new BadRequestError({ name: "Update project membership", message: "Role not found" }); + if (!customRole) throw new BadRequestError({ name: "Update project membership", message: "Role not found" }); const project = await projectDAL.findById(customRole.projectId); const plan = await licenseService.getPlan(project.orgId); if (!plan?.rbac) throw new BadRequestError({ - message: - "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member." + message: "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member." }); const [membership] = await projectMembershipDAL.update( @@ -233,30 +200,16 @@ export const projectMembershipServiceFactory = ({ return membership; } - const [membership] = await projectMembershipDAL.update( - { id: membershipId, projectId }, - { role, roleId: null } - ); + const [membership] = await projectMembershipDAL.update({ id: membershipId, projectId }, { role, roleId: null }); return membership; }; - const deleteProjectMembership = async ({ - actorId, - actor, - projectId, - membershipId - }: TDeleteProjectMembershipDTO) => { + const deleteProjectMembership = async ({ actorId, actor, projectId, membershipId }: TDeleteProjectMembershipDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Member - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Member); const membership = await projectMembershipDAL.transaction(async (tx) => { - const [deletedMembership] = await projectMembershipDAL.delete( - { projectId, id: membershipId }, - tx - ); + const [deletedMembership] = await projectMembershipDAL.delete({ projectId, id: membershipId }, tx); await projectKeyDAL.delete({ receiverId: deletedMembership.userId, projectId }, tx); return deletedMembership; }); diff --git a/backend/src/services/project-role/project-role-service.ts b/backend/src/services/project-role/project-role-service.ts index 8e86b45fb7..4c06337129 100644 --- a/backend/src/services/project-role/project-role-service.ts +++ b/backend/src/services/project-role/project-role-service.ts @@ -18,18 +18,12 @@ import { TProjectRoleDALFactory } from "./project-role-dal"; type TProjectRoleServiceFactoryDep = { projectRoleDAL: TProjectRoleDALFactory; - permissionService: Pick< - TPermissionServiceFactory, - "getProjectPermission" | "getUserProjectPermission" - >; + permissionService: Pick; }; export type TProjectRoleServiceFactory = ReturnType; -export const projectRoleServiceFactory = ({ - projectRoleDAL, - permissionService -}: TProjectRoleServiceFactoryDep) => { +export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }: TProjectRoleServiceFactoryDep) => { const createRole = async ( actor: ActorType, actorId: string, @@ -37,10 +31,7 @@ export const projectRoleServiceFactory = ({ data: Omit ) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Role - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Role); const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId }); if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" }); const role = await projectRoleDAL.create({ @@ -59,10 +50,7 @@ export const projectRoleServiceFactory = ({ data: Omit ) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Role - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Role); if (data?.slug) { const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId }); if (existingRole && existingRole.id !== roleId) @@ -76,17 +64,9 @@ export const projectRoleServiceFactory = ({ return updatedRole; }; - const deleteRole = async ( - actor: ActorType, - actorId: string, - projectId: string, - roleId: string - ) => { + const deleteRole = async (actor: ActorType, actorId: string, projectId: string, roleId: string) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Role - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Role); const [deletedRole] = await projectRoleDAL.delete({ id: roleId, projectId }); if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" }); @@ -95,10 +75,7 @@ export const projectRoleServiceFactory = ({ const listRoles = async (actor: ActorType, actorId: string, projectId: string) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Role - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role); const customRoles = await projectRoleDAL.find({ projectId }); const roles = [ { @@ -151,10 +128,7 @@ export const projectRoleServiceFactory = ({ }; const getUserPermission = async (userId: string, projectId: string) => { - const { permission, membership } = await permissionService.getUserProjectPermission( - userId, - projectId - ); + const { permission, membership } = await permissionService.getUserProjectPermission(userId, projectId); return { permissions: packRules(permission.rules), membership }; }; diff --git a/backend/src/services/project/project-dal.ts b/backend/src/services/project/project-dal.ts index c286c379fa..b57fdffe1c 100644 --- a/backend/src/services/project/project-dal.ts +++ b/backend/src/services/project/project-dal.ts @@ -12,16 +12,8 @@ export const projectDALFactory = (db: TDbClient) => { try { const workspaces = await db(TableName.ProjectMembership) .where({ userId }) - .join( - TableName.Project, - `${TableName.ProjectMembership}.projectId`, - `${TableName.Project}.id` - ) - .leftJoin( - TableName.Environment, - `${TableName.Environment}.projectId`, - `${TableName.Project}.id` - ) + .join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`) + .leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`) .select( selectAllTableCols(TableName.Project), db.ref("id").withSchema(TableName.Project).as("_id"), @@ -60,16 +52,8 @@ export const projectDALFactory = (db: TDbClient) => { try { const workspaces = await db(TableName.IdentityProjectMembership) .where({ identityId }) - .join( - TableName.Project, - `${TableName.IdentityProjectMembership}.projectId`, - `${TableName.Project}.id` - ) - .leftJoin( - TableName.Environment, - `${TableName.Environment}.projectId`, - `${TableName.Project}.id` - ) + .join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`) + .leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`) .select( selectAllTableCols(TableName.Project), db.ref("id").withSchema(TableName.Project).as("_id"), @@ -110,16 +94,8 @@ export const projectDALFactory = (db: TDbClient) => { try { const workspaces = await db(TableName.ProjectMembership) .where(`${TableName.Project}.id`, id) - .join( - TableName.Project, - `${TableName.ProjectMembership}.projectId`, - `${TableName.Project}.id` - ) - .join( - TableName.Environment, - `${TableName.Environment}.projectId`, - `${TableName.Project}.id` - ) + .join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`) + .join(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`) .select( selectAllTableCols(TableName.Project), db.ref("id").withSchema(TableName.Project).as("_id"), diff --git a/backend/src/services/project/project-service.ts b/backend/src/services/project/project-service.ts index df11685789..08d75b0dda 100644 --- a/backend/src/services/project/project-service.ts +++ b/backend/src/services/project/project-service.ts @@ -3,15 +3,9 @@ import slugify from "@sindresorhus/slugify"; import { ProjectMembershipRole } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; -import { - OrgPermissionActions, - OrgPermissionSubjects -} from "@app/ee/services/permission/org-permission"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; import { createSecretBlindIndex } from "@app/lib/crypto"; import { BadRequestError } from "@app/lib/errors"; @@ -56,10 +50,7 @@ export const projectServiceFactory = ({ * */ const createProject = async ({ orgId, actor, actorId, workspaceName }: TCreateProjectDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); - ForbiddenError.from(permission).throwUnlessCan( - OrgPermissionActions.Create, - OrgPermissionSubjects.Workspace - ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace); const appCfg = getConfig(); const blindIndex = createSecretBlindIndex(appCfg.ROOT_ENCRYPTION_KEY, appCfg.ENCRYPTION_KEY); @@ -69,8 +60,7 @@ export const projectServiceFactory = ({ // case: limit imposed on number of workspaces allowed // case: number of workspaces used exceeds the number of workspaces allowed throw new BadRequestError({ - message: - "Failed to create workspace due to plan limit reached. Upgrade plan to add more workspaces." + message: "Failed to create workspace due to plan limit reached. Upgrade plan to add more workspaces." }); } @@ -118,10 +108,7 @@ export const projectServiceFactory = ({ const deleteProject = async ({ actor, actorId, projectId }: TDeleteProjectDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Project - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Project); const deletedProject = await projectDAL.deleteById(projectId); return deletedProject; @@ -144,26 +131,15 @@ export const projectServiceFactory = ({ autoCapitalization }: TGetProjectDTO & { autoCapitalization: boolean }) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Settings - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings); const updatedProject = await projectDAL.updateById(projectId, { autoCapitalization }); return updatedProject; }; - const updateName = async ({ - projectId, - actor, - actorId, - name - }: TGetProjectDTO & { name: string }) => { + const updateName = async ({ projectId, actor, actorId, name }: TGetProjectDTO & { name: string }) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Settings - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings); const updatedProject = await projectDAL.updateById(projectId, { name }); return updatedProject; diff --git a/backend/src/services/secret-blind-index/secret-blind-index-dal.ts b/backend/src/services/secret-blind-index/secret-blind-index-dal.ts index c508728aff..8fa60cde7c 100644 --- a/backend/src/services/secret-blind-index/secret-blind-index-dal.ts +++ b/backend/src/services/secret-blind-index/secret-blind-index-dal.ts @@ -13,20 +13,12 @@ export const secretBlindIndexDALFactory = (db: TDbClient) => { const countOfSecretsWithNullSecretBlindIndex = async (projectId: string, tx?: Knex) => { try { const doc = await (tx || db)(TableName.Secret) - .leftJoin( - TableName.SecretFolder, - `${TableName.SecretFolder}.id`, - `${TableName.Secret}.folderId` - ) - .leftJoin( - TableName.Environment, - `${TableName.Environment}.id`, - `${TableName.SecretFolder}.envId` - ) + .leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.Secret}.folderId`) + .leftJoin(TableName.Environment, `${TableName.Environment}.id`, `${TableName.SecretFolder}.envId`) .where({ projectId }) .whereNull("secretBlindIndex") - .count(`${TableName.Secret}.id`); - return (doc as any)?.[0]?.count || 0; + .count(`${TableName.Secret}.id` as "id"); + return doc?.[0]?.count || 0; } catch (error) { throw new DatabaseError({ error, name: "CountOfSecretWillNullSecretBlindIndex" }); } @@ -35,16 +27,8 @@ export const secretBlindIndexDALFactory = (db: TDbClient) => { const findAllSecretsByProjectId = async (projectId: string, tx?: Knex) => { try { const docs = await (tx || db)(TableName.Secret) - .leftJoin( - TableName.SecretFolder, - `${TableName.SecretFolder}.id`, - `${TableName.Secret}.folderId` - ) - .leftJoin( - TableName.Environment, - `${TableName.Environment}.id`, - `${TableName.SecretFolder}.envId` - ) + .leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.Secret}.folderId`) + .leftJoin(TableName.Environment, `${TableName.Environment}.id`, `${TableName.SecretFolder}.envId`) .where({ projectId }) .whereNull("secretBlindIndex") .select(selectAllTableCols(TableName.Secret)) @@ -61,16 +45,8 @@ export const secretBlindIndexDALFactory = (db: TDbClient) => { const findSecretsByProjectId = async (projectId: string, secretIds: string[], tx?: Knex) => { try { const docs = await (tx || db)(TableName.Secret) - .leftJoin( - TableName.SecretFolder, - `${TableName.SecretFolder}.id`, - `${TableName.Secret}.folderId` - ) - .leftJoin( - TableName.Environment, - `${TableName.Environment}.id`, - `${TableName.SecretFolder}.envId` - ) + .leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.Secret}.folderId`) + .leftJoin(TableName.Environment, `${TableName.Environment}.id`, `${TableName.SecretFolder}.envId`) .where({ projectId }) .whereIn(`${TableName.Secret}.id`, secretIds) .whereNull("secretBlindIndex") diff --git a/backend/src/services/secret-blind-index/secret-blind-index-service.ts b/backend/src/services/secret-blind-index/secret-blind-index-service.ts index 0c18ddedc1..bb565e295b 100644 --- a/backend/src/services/secret-blind-index/secret-blind-index-service.ts +++ b/backend/src/services/secret-blind-index/secret-blind-index-service.ts @@ -24,11 +24,7 @@ export const secretBlindIndexServiceFactory = ({ permissionService, secretDAL }: TSecretBlindIndexServiceFactoryDep) => { - const getSecretBlindIndexStatus = async ({ - actor, - projectId, - actorId - }: TGetProjectBlindIndexStatusDTO) => { + const getSecretBlindIndexStatus = async ({ actor, projectId, actorId }: TGetProjectBlindIndexStatusDTO) => { await permissionService.getProjectPermission(actor, actorId, projectId); const secretCount = await secretBlindIndexDAL.countOfSecretsWithNullSecretBlindIndex(projectId); @@ -57,15 +53,13 @@ export const secretBlindIndexServiceFactory = ({ } const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); const secrets = await secretBlindIndexDAL.findSecretsByProjectId( projectId, secretsToUpdate.map(({ secretId }) => secretId) ); - if (secrets.length !== secretsToUpdate.length) - throw new BadRequestError({ message: "Secret not found" }); + if (secrets.length !== secretsToUpdate.length) throw new BadRequestError({ message: "Secret not found" }); const operations = await Promise.all( secretsToUpdate.map(async ({ secretName, secretId: id }) => { diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index 3d25217cb5..023d039ca4 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -1,12 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { - TableName, - TProjectEnvironments, - TSecretFolders, - TSecretFoldersUpdate -} from "@app/db/schemas"; +import { TableName, TProjectEnvironments, TSecretFolders, TSecretFoldersUpdate } from "@app/db/schemas"; import { BadRequestError, DatabaseError } from "@app/lib/errors"; import { groupBy, removeTrailingSlash } from "@app/lib/fn"; import { ormify, selectAllTableCols } from "@app/lib/knex"; @@ -16,14 +11,10 @@ export const validateFolderName = (folderName: string) => { return validNameRegex.test(folderName); }; -const sqlFindMultipleFolderByEnvPathQuery = ( - db: Knex, - query: Array<{ envId: string; secretPath: string }> -) => { +const sqlFindMultipleFolderByEnvPathQuery = (db: Knex, query: Array<{ envId: string; secretPath: string }>) => { // this is removing an trailing slash like /folder1/folder2/ -> /folder1/folder2 const formatedQuery = query.map(({ envId, secretPath }) => { - const formatedPath = - secretPath.at(-1) === "/" && secretPath.length > 1 ? secretPath.slice(0, -1) : secretPath; + const formatedPath = secretPath.at(-1) === "/" && secretPath.length > 1 ? secretPath.slice(0, -1) : secretPath; const segments = formatedPath.split("/").filter(Boolean); if (segments.some((segment) => !validateFolderName(segment))) { throw new BadRequestError({ message: "Invalid folder name" }); @@ -42,7 +33,7 @@ const sqlFindMultipleFolderByEnvPathQuery = ( // Thus each node has connection to parent node // for a given path from root we recursively reach to the leaf path or till we get null // the below query is the base case where we select root folder which has parent folder id as null - baseQb + void baseQb .select({ depth: 1, // latestFolderVerId: db.raw("NULL::uuid"), @@ -57,49 +48,44 @@ const sqlFindMultipleFolderByEnvPathQuery = ( formatedQuery.map(({ envId }) => envId) ) .select(selectAllTableCols(TableName.SecretFolder)) - .union((qb) => - // for here on we keep going to next child node. - // we also keep a measure of depth then we check the depth matches the array path segment and folder name - // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 - qb - .select({ - depth: db.raw("parent.depth + 1"), - path: db.raw( - "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" - ) - }) - .select(selectAllTableCols(TableName.SecretFolder)) - .where((wb) => - formatedQuery.map(({ secretPath }) => - wb.orWhereRaw( - `depth = array_position(ARRAY[${secretPath - .map(() => "?") - .join(",")}]::varchar[], ${TableName.SecretFolder}.name,depth)`, - [...secretPath] + .union( + (qb) => + // for here on we keep going to next child node. + // we also keep a measure of depth then we check the depth matches the array path segment and folder name + // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 + void qb + .select({ + depth: db.raw("parent.depth + 1"), + path: db.raw( + "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + ) + }) + .select(selectAllTableCols(TableName.SecretFolder)) + .where((wb) => + formatedQuery.map(({ secretPath }) => + wb.orWhereRaw( + `depth = array_position(ARRAY[${secretPath.map(() => "?").join(",")}]::varchar[], ${ + TableName.SecretFolder + }.name,depth)`, + [...secretPath] + ) ) ) - ) - .from(TableName.SecretFolder) - .join("parent", (bd) => - bd - .on("parent.id", `${TableName.SecretFolder}.parentId`) - .andOn("parent.envId", `${TableName.SecretFolder}.envId`) - ) + .from(TableName.SecretFolder) + .join("parent", (bd) => + bd + .on("parent.id", `${TableName.SecretFolder}.parentId`) + .andOn("parent.envId", `${TableName.SecretFolder}.envId`) + ) ); }) .select("*") .from("parent"); }; -const sqlFindFolderByPathQuery = ( - db: Knex, - projectId: string, - environment: string, - secretPath: string -) => { +const sqlFindFolderByPathQuery = (db: Knex, projectId: string, environment: string, secretPath: string) => { // this is removing an trailing slash like /folder1/folder2/ -> /folder1/folder2 - const formatedPath = - secretPath.at(-1) === "/" && secretPath.length > 1 ? secretPath.slice(0, -1) : secretPath; + const formatedPath = secretPath.at(-1) === "/" && secretPath.length > 1 ? secretPath.slice(0, -1) : secretPath; // next goal to sanitize saw the raw sql query is safe // for this we ensure folder name contains only string and - nothing else const pathSegments = formatedPath.split("/").filter(Boolean); @@ -113,52 +99,45 @@ const sqlFindFolderByPathQuery = ( // Thus each node has connection to parent node // for a given path from root we recursively reach to the leaf path or till we get null // the below query is the base case where we select root folder which has parent folder id as null - baseQb + void baseQb .select({ depth: 1, // latestFolderVerId: db.raw("NULL::uuid"), path: db.raw("'/'") }) .from(TableName.SecretFolder) - .join( - TableName.Environment, - `${TableName.SecretFolder}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .where({ projectId, parentId: null }) .where(`${TableName.Environment}.slug`, environment) .select(selectAllTableCols(TableName.SecretFolder)) - .union((qb) => - // for here on we keep going to next child node. - // we also keep a measure of depth then we check the depth matches the array path segment and folder name - // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 - qb - .select({ - depth: db.raw("parent.depth + 1"), - path: db.raw( - "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + .union( + (qb) => + // for here on we keep going to next child node. + // we also keep a measure of depth then we check the depth matches the array path segment and folder name + // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 + void qb + .select({ + depth: db.raw("parent.depth + 1"), + path: db.raw( + "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + ) + }) + .select(selectAllTableCols(TableName.SecretFolder)) + .whereRaw( + `depth = array_position(ARRAY[${pathSegments + .map(() => "?") + .join(",")}]::varchar[], secret_folders.name,depth)`, + [...pathSegments] ) - }) - .select(selectAllTableCols(TableName.SecretFolder)) - .whereRaw( - `depth = array_position(ARRAY[${pathSegments - .map(() => "?") - .join(",")}]::varchar[], secret_folders.name,depth)`, - [...pathSegments] - ) - .from(TableName.SecretFolder) - .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`) + .from(TableName.SecretFolder) + .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`) ); }) .from("parent") - .leftJoin( - TableName.Environment, - `${TableName.Environment}.id`, - "parent.envId" - ) + .leftJoin(TableName.Environment, `${TableName.Environment}.id`, "parent.envId") .select< TSecretFolders & { depth: number; @@ -183,43 +162,38 @@ const sqlFindSecretPathByFolderId = (db: Knex, projectId: string, folderIds: str // first remember our folders are connected as a link list or known as adjacency list // Thus each node has connection to parent node // we first find the folder given in folder id - baseQb + void baseQb .from(TableName.SecretFolder) .select(selectAllTableCols(TableName.SecretFolder)) .select({ // this is for root condition // if the given folder id is root folder id then intial path is set as / instead of /root // if not root folder the path here will be / - path: db.raw( - `CONCAT('/', (CASE WHEN "parentId" is NULL THEN '' ELSE ${TableName.SecretFolder}.name END))` - ), + path: db.raw(`CONCAT('/', (CASE WHEN "parentId" is NULL THEN '' ELSE ${TableName.SecretFolder}.name END))`), child: db.raw("NULL::uuid") }) - .join( - TableName.Environment, - `${TableName.SecretFolder}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .where({ projectId }) .whereIn(`${TableName.SecretFolder}.id`, folderIds) - .union((qb) => - // then we keep going up - // until parent id is null - qb - .select(selectAllTableCols(TableName.SecretFolder)) - .select({ - // then we join join this folder name behind previous as we are going from child to parent - // the root folder check is used to avoid last / and also root name in folders - path: db.raw( - `CONCAT( CASE + .union( + (qb) => + // then we keep going up + // until parent id is null + void qb + .select(selectAllTableCols(TableName.SecretFolder)) + .select({ + // then we join join this folder name behind previous as we are going from child to parent + // the root folder check is used to avoid last / and also root name in folders + path: db.raw( + `CONCAT( CASE WHEN ${TableName.SecretFolder}."parentId" is NULL THEN '' ELSE CONCAT('/', secret_folders.name) END, parent.path )` - ), - child: db.raw("COALESCE(parent.child, parent.id)") - }) - .from(TableName.SecretFolder) - .join("parent", "parent.parentId", `${TableName.SecretFolder}.id`) + ), + child: db.raw("COALESCE(parent.child, parent.id)") + }) + .from(TableName.SecretFolder) + .join("parent", "parent.parentId", `${TableName.SecretFolder}.id`) ); }) .select("*") @@ -231,19 +205,9 @@ export const ROOT_FOLDER_NAME = "root"; export const secretFolderDALFactory = (db: TDbClient) => { const secretFolderOrm = ormify(db, TableName.SecretFolder); - const findBySecretPath = async ( - projectId: string, - environment: string, - path: string, - tx?: Knex - ) => { + const findBySecretPath = async (projectId: string, environment: string, path: string, tx?: Knex) => { try { - const folder = await sqlFindFolderByPathQuery( - tx || db, - projectId, - environment, - removeTrailingSlash(path) - ) + const folder = await sqlFindFolderByPathQuery(tx || db, projectId, environment, removeTrailingSlash(path)) .orderBy("depth", "desc") .first(); if (folder && folder.path !== removeTrailingSlash(path)) { @@ -260,19 +224,9 @@ export const secretFolderDALFactory = (db: TDbClient) => { // used in folder creation // even if its the original given /path1/path2 // it will stop automatically at /path2 - const findClosestFolder = async ( - projectId: string, - environment: string, - path: string, - tx?: Knex - ) => { + const findClosestFolder = async (projectId: string, environment: string, path: string, tx?: Knex) => { try { - const folder = await sqlFindFolderByPathQuery( - tx || db, - projectId, - environment, - removeTrailingSlash(path) - ) + const folder = await sqlFindFolderByPathQuery(tx || db, projectId, environment, removeTrailingSlash(path)) .orderBy("depth", "desc") .first(); if (!folder) return; @@ -283,10 +237,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { } }; - const findByManySecretPath = async ( - query: Array<{ envId: string; secretPath: string }>, - tx?: Knex - ) => { + const findByManySecretPath = async (query: Array<{ envId: string; secretPath: string }>, tx?: Knex) => { try { const formatedQuery = query.map(({ secretPath, envId }) => ({ envId, @@ -294,10 +245,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { })); const folders = await sqlFindMultipleFolderByEnvPathQuery(tx || db, formatedQuery); return formatedQuery.map(({ envId, secretPath }) => - folders.find( - ({ path: targetPath, envId: targetEnvId }) => - targetPath === secretPath && targetEnvId === envId - ) + folders.find(({ path: targetPath, envId: targetEnvId }) => targetPath === secretPath && targetEnvId === envId) ); } catch (error) { throw new DatabaseError({ error, name: "FindByManySecretPath" }); @@ -336,11 +284,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { try { const folder = await (tx || db)(TableName.SecretFolder) .where({ [`${TableName.SecretFolder}.id` as "id"]: id }) - .join( - TableName.Environment, - `${TableName.SecretFolder}.envId`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .select(selectAllTableCols(TableName.SecretFolder)) .select( db.ref("id").withSchema(TableName.Environment).as("envId"), diff --git a/backend/src/services/secret-folder/secret-folder-service.ts b/backend/src/services/secret-folder/secret-folder-service.ts index a9e7474c8c..0826744851 100644 --- a/backend/src/services/secret-folder/secret-folder-service.ts +++ b/backend/src/services/secret-folder/secret-folder-service.ts @@ -4,21 +4,13 @@ import { v4 as uuidv4 } from "uuid"; import { TSecretFoldersInsert } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service"; import { BadRequestError } from "@app/lib/errors"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TSecretFolderDALFactory } from "./secret-folder-dal"; -import { - TCreateFolderDTO, - TDeleteFolderDTO, - TGetFolderDTO, - TUpdateFolderDTO -} from "./secret-folder-types"; +import { TCreateFolderDTO, TDeleteFolderDTO, TGetFolderDTO, TUpdateFolderDTO } from "./secret-folder-types"; import { TSecretFolderVersionDALFactory } from "./secret-folder-version-dal"; type TSecretFolderServiceFactoryDep = { @@ -38,14 +30,7 @@ export const secretFolderServiceFactory = ({ projectEnvDAL, folderVersionDAL }: TSecretFolderServiceFactoryDep) => { - const createFolder = async ({ - projectId, - actor, - actorId, - name, - environment, - path: secretPath - }: TCreateFolderDTO) => { + const createFolder = async ({ projectId, actor, actorId, name, environment, path: secretPath }: TCreateFolderDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Create, @@ -53,8 +38,7 @@ export const secretFolderServiceFactory = ({ ); const env = await projectEnvDAL.findOne({ projectId, slug: environment }); - if (!env) - throw new BadRequestError({ message: "Environment not found", name: "Create folder" }); + if (!env) throw new BadRequestError({ message: "Environment not found", name: "Create folder" }); const folder = await folderDAL.transaction(async (tx) => { // the logic is simple we need to avoid creating same folder in same path multiple times @@ -62,12 +46,7 @@ export const secretFolderServiceFactory = ({ // so we do a tricky move. we try to find the to be created folder path if that is exactly match return that // else we get some path before that then we will start creating remaining folder const pathWithFolder = path.join(secretPath, name); - const parentFolder = await folderDAL.findClosestFolder( - projectId, - environment, - pathWithFolder, - tx - ); + const parentFolder = await folderDAL.findClosestFolder(projectId, environment, pathWithFolder, tx); // no folder found is not possible root should be their if (!parentFolder) throw new BadRequestError({ message: "Secret path not found" }); // exact folder @@ -78,24 +57,19 @@ export const secretFolderServiceFactory = ({ // this is upsert folder in a path // we are not taking snapshots of this because // snapshot will be removed from automatic for all commits to user click or cron based - const missingSegment = secretPath - .substring(parentFolder.path.length) - .split("/") - .filter(Boolean); + const missingSegment = secretPath.substring(parentFolder.path.length).split("/").filter(Boolean); if (missingSegment.length) { - const newFolders: Array = missingSegment.map( - (segment) => { - const newFolder = { - name: segment, - parentId: parentFolderId, - id: uuidv4(), - envId: env.id, - version: 1 - }; - parentFolderId = newFolder.id; - return newFolder; - } - ); + const newFolders: Array = missingSegment.map((segment) => { + const newFolder = { + name: segment, + parentId: parentFolderId, + id: uuidv4(), + envId: env.id, + version: 1 + }; + parentFolderId = newFolder.id; + return newFolder; + }); parentFolderId = newFolders.at(-1)?.id as string; const docs = await folderDAL.insertMany(newFolders, tx); await folderVersionDAL.insertMany( @@ -110,10 +84,7 @@ export const secretFolderServiceFactory = ({ } } - const doc = await folderDAL.create( - { name, envId: env.id, version: 1, parentId: parentFolderId }, - tx - ); + const doc = await folderDAL.create({ name, envId: env.id, version: 1, parentId: parentFolderId }, tx); await folderVersionDAL.create( { name: doc.name, @@ -149,8 +120,7 @@ export const secretFolderServiceFactory = ({ if (!parentFolder) throw new BadRequestError({ message: "Secret path not found" }); const env = await projectEnvDAL.findOne({ projectId, slug: environment }); - if (!env) - throw new BadRequestError({ message: "Environment not found", name: "Update folder" }); + if (!env) throw new BadRequestError({ message: "Environment not found", name: "Update folder" }); const folder = await folderDAL .findOne({ envId: env.id, id, parentId: parentFolder.id }) // now folder api accepts id based change @@ -160,11 +130,7 @@ export const secretFolderServiceFactory = ({ if (!folder) throw new BadRequestError({ message: "Folder not found" }); const newFolder = await folderDAL.transaction(async (tx) => { - const [doc] = await folderDAL.update( - { envId: env.id, id: folder.id, parentId: parentFolder.id }, - { name }, - tx - ); + const [doc] = await folderDAL.update({ envId: env.id, id: folder.id, parentId: parentFolder.id }, { name }, tx); await folderVersionDAL.create( { name: doc.name, @@ -182,14 +148,7 @@ export const secretFolderServiceFactory = ({ return { folder: newFolder, old: folder }; }; - const deleteFolder = async ({ - projectId, - actor, - actorId, - environment, - path: secretPath, - id - }: TDeleteFolderDTO) => { + const deleteFolder = async ({ projectId, actor, actorId, environment, path: secretPath, id }: TDeleteFolderDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Delete, @@ -197,8 +156,7 @@ export const secretFolderServiceFactory = ({ ); const env = await projectEnvDAL.findOne({ projectId, slug: environment }); - if (!env) - throw new BadRequestError({ message: "Environment not found", name: "Create folder" }); + if (!env) throw new BadRequestError({ message: "Environment not found", name: "Create folder" }); const folder = await folderDAL.transaction(async (tx) => { const parentFolder = await folderDAL.findBySecretPath(projectId, environment, secretPath, tx); @@ -213,13 +171,7 @@ export const secretFolderServiceFactory = ({ return folder; }; - const getFolders = async ({ - projectId, - actor, - actorId, - environment, - path: secretPath - }: TGetFolderDTO) => { + const getFolders = async ({ projectId, actor, actorId, environment, path: secretPath }: TGetFolderDTO) => { // folder list is allowed to be read by anyone // permission to check does user has access await permissionService.getProjectPermission(actor, actorId, projectId); diff --git a/backend/src/services/secret-folder/secret-folder-version-dal.ts b/backend/src/services/secret-folder/secret-folder-version-dal.ts index b610de3595..f133308cf4 100644 --- a/backend/src/services/secret-folder/secret-folder-version-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-version-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretFolderVersions } from "@app/db/schemas"; +import { TableName, TSecretFolderVersions } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols } from "@app/lib/knex"; @@ -14,11 +14,7 @@ export const secretFolderVersionDALFactory = (db: TDbClient) => { const findLatestVersionByFolderId = async (folderId: string, tx?: Knex) => { try { const docs = await (tx || db)(TableName.SecretFolderVersion) - .join( - TableName.SecretFolder, - `${TableName.SecretFolderVersion}.folderId`, - `${TableName.SecretFolder}.id` - ) + .join(TableName.SecretFolder, `${TableName.SecretFolderVersion}.folderId`, `${TableName.SecretFolder}.id`) .where({ parentId: folderId }) .join( (tx || db)(TableName.SecretFolderVersion) @@ -42,9 +38,7 @@ export const secretFolderVersionDALFactory = (db: TDbClient) => { const findLatestFolderVersions = async (folderIds: string[], tx?: Knex) => { try { - const docs: Array = await (tx || db)( - TableName.SecretFolderVersion - ) + const docs: Array = await (tx || db)(TableName.SecretFolderVersion) .whereIn("folderId", folderIds) .join( (tx || db)(TableName.SecretFolderVersion) diff --git a/backend/src/services/secret-import/secret-import-dal.ts b/backend/src/services/secret-import/secret-import-dal.ts index 0acbd74264..f9c6f1be77 100644 --- a/backend/src/services/secret-import/secret-import-dal.ts +++ b/backend/src/services/secret-import/secret-import-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretImports } from "@app/db/schemas"; +import { TableName, TSecretImports } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -15,7 +15,7 @@ export const secretImportDALFactory = (db: TDbClient) => { const findLastImportPosition = async (folderId: string, tx?: Knex) => { const lastPos = await (tx || db)(TableName.SecretImport) .where({ folderId }) - .max({ position: "position" }) + .max("position", { as: "position" }) .first(); return lastPos?.position || 0; }; @@ -53,11 +53,7 @@ export const secretImportDALFactory = (db: TDbClient) => { try { const docs = await (tx || db)(TableName.SecretImport) .where(filter) - .join( - TableName.Environment, - `${TableName.SecretImport}.importEnv`, - `${TableName.Environment}.id` - ) + .join(TableName.Environment, `${TableName.SecretImport}.importEnv`, `${TableName.Environment}.id`) .select( db.ref("*").withSchema(TableName.SecretImport) as unknown as keyof TSecretImports, db.ref("slug").withSchema(TableName.Environment), diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index b4ba45d012..57142424f4 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -1,10 +1,7 @@ import { ForbiddenError, subject } from "@casl/ability"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; @@ -39,14 +36,7 @@ export const secretImportServiceFactory = ({ folderDAL, secretDAL }: TSecretImportServiceFactoryDep) => { - const createImport = async ({ - environment, - data, - actor, - actorId, - projectId, - path - }: TCreateSecretImportDTO) => { + const createImport = async ({ environment, data, actor, actorId, projectId, path }: TCreateSecretImportDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); // check if user has permission to import into destination path @@ -69,8 +59,7 @@ export const secretImportServiceFactory = ({ // TODO(akhilmhdh-pg): updated permission check add here const [importEnv] = await projectEnvDAL.findBySlugs(projectId, [data.environment]); - if (!importEnv) - throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); + if (!importEnv) throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); const secImport = await secretImportDAL.transaction(async (tx) => { const lastPos = await secretImportDAL.findLastImportPosition(folder.id, tx); @@ -88,15 +77,7 @@ export const secretImportServiceFactory = ({ return { ...secImport, importEnv }; }; - const updateImport = async ({ - path, - environment, - projectId, - actor, - actorId, - data, - id - }: TUpdateSecretImportDTO) => { + const updateImport = async ({ path, environment, projectId, actor, actorId, data, id }: TUpdateSecretImportDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Edit, @@ -112,8 +93,7 @@ export const secretImportServiceFactory = ({ const importedEnv = data.environment // this is get env information of new one or old one ? (await projectEnvDAL.findBySlugs(projectId, [data.environment]))?.[0] : await projectEnvDAL.findById(secImpDoc.importEnv); - if (!importedEnv) - throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); + if (!importedEnv) throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); const updatedSecImport = await secretImportDAL.transaction(async (tx) => { const secImp = await secretImportDAL.findOne({ folderId: folder.id, id }); @@ -135,14 +115,7 @@ export const secretImportServiceFactory = ({ return { ...updatedSecImport, importEnv: importedEnv }; }; - const deleteImport = async ({ - path, - environment, - projectId, - actor, - actorId, - id - }: TDeleteSecretImportDTO) => { + const deleteImport = async ({ path, environment, projectId, actor, actorId, id }: TDeleteSecretImportDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Delete, @@ -154,25 +127,17 @@ export const secretImportServiceFactory = ({ const secImport = await secretImportDAL.transaction(async (tx) => { const [doc] = await secretImportDAL.delete({ folderId: folder.id, id }, tx); - if (!doc) - throw new BadRequestError({ name: "Sec imp del", message: "Secret import doc not found" }); + if (!doc) throw new BadRequestError({ name: "Sec imp del", message: "Secret import doc not found" }); await secretImportDAL.updateAllPosition(folder.id, doc.position, -1, tx); const importEnv = await projectEnvDAL.findById(doc.importEnv); - if (!importEnv) - throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); + if (!importEnv) throw new BadRequestError({ error: "Imported env not found", name: "Create import" }); return { ...doc, importEnv }; }); return secImport; }; - const getImports = async ({ - path, - environment, - projectId, - actor, - actorId - }: TGetSecretImportsDTO) => { + const getImports = async ({ path, environment, projectId, actor, actorId }: TGetSecretImportsDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Read, @@ -186,13 +151,7 @@ export const secretImportServiceFactory = ({ return secImports; }; - const getSecretsFromImports = async ({ - path, - environment, - projectId, - actor, - actorId - }: TGetSecretsFromImportDTO) => { + const getSecretsFromImports = async ({ path, environment, projectId, actor, actorId }: TGetSecretsFromImportDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Read, diff --git a/backend/src/services/secret-tag/secret-tag-dal.ts b/backend/src/services/secret-tag/secret-tag-dal.ts index 2e6b38c027..f1ae2424ad 100644 --- a/backend/src/services/secret-tag/secret-tag-dal.ts +++ b/backend/src/services/secret-tag/secret-tag-dal.ts @@ -23,11 +23,7 @@ export const secretTagDALFactory = (db: TDbClient) => { const deleteTagsManySecret = async (projectId: string, secretIds: string[], tx?: Knex) => { try { const tags = await (tx || db)(TableName.JnSecretTag) - .join( - TableName.SecretTag, - `${TableName.JnSecretTag}.${TableName.SecretTag}Id`, - `${TableName.SecretTag}.id` - ) + .join(TableName.SecretTag, `${TableName.JnSecretTag}.${TableName.SecretTag}Id`, `${TableName.SecretTag}.id`) .where("projectId", projectId) .whereIn(`${TableName.Secret}Id`, secretIds) .delete() diff --git a/backend/src/services/secret-tag/secret-tag-service.ts b/backend/src/services/secret-tag/secret-tag-service.ts index 8b097e5955..0605296569 100644 --- a/backend/src/services/secret-tag/secret-tag-service.ts +++ b/backend/src/services/secret-tag/secret-tag-service.ts @@ -1,10 +1,7 @@ import { ForbiddenError } from "@casl/ability"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; import { TSecretTagDALFactory } from "./secret-tag-dal"; @@ -17,16 +14,10 @@ type TSecretTagServiceFactoryDep = { export type TSecretTagServiceFactory = ReturnType; -export const secretTagServiceFactory = ({ - secretTagDAL, - permissionService -}: TSecretTagServiceFactoryDep) => { +export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSecretTagServiceFactoryDep) => { const createTag = async ({ name, slug, actor, color, actorId, projectId }: TCreateTagDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Tags - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Tags); const existingTag = await secretTagDAL.findOne({ slug }); if (existingTag) throw new BadRequestError({ message: "Tag already exist" }); @@ -45,15 +36,8 @@ export const secretTagServiceFactory = ({ const tag = await secretTagDAL.findById(id); if (!tag) throw new BadRequestError({ message: "Tag doesn't exist" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - tag.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Tags - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, tag.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Tags); const deletedTag = await secretTagDAL.deleteById(tag.id); return deletedTag; @@ -61,10 +45,7 @@ export const secretTagServiceFactory = ({ const getProjectTags = async ({ actor, actorId, projectId }: TListProjectTagsDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Tags - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags); const tags = await secretTagDAL.find({ projectId }); return tags; diff --git a/backend/src/services/secret/secret-dal.ts b/backend/src/services/secret/secret-dal.ts index b207f604ad..44b39a9484 100644 --- a/backend/src/services/secret/secret-dal.ts +++ b/backend/src/services/secret/secret-dal.ts @@ -11,17 +11,9 @@ export type TSecretDALFactory = ReturnType; export const secretDALFactory = (db: TDbClient) => { const secretOrm = ormify(db, TableName.Secret); - const update = async ( - filter: Partial, - data: Omit, - tx?: Knex - ) => { + const update = async (filter: Partial, data: Omit, tx?: Knex) => { try { - const sec = await (tx || db)(TableName.Secret) - .where(filter) - .update(data) - .increment("version", 1) - .returning("*"); + const sec = await (tx || db)(TableName.Secret).where(filter).update(data).increment("version", 1).returning("*"); return sec; } catch (error) { throw new DatabaseError({ error, name: "update secret" }); @@ -30,10 +22,7 @@ export const secretDALFactory = (db: TDbClient) => { // the idea is to use postgres specific function // insert with id this will cause a conflict then merge the data - const bulkUpdate = async ( - data: Array<{ filter: Partial; data: TSecretsUpdate }>, - tx?: Knex - ) => { + const bulkUpdate = async (data: Array<{ filter: Partial; data: TSecretsUpdate }>, tx?: Knex) => { try { const secs = await Promise.all( data.map(async ({ filter, data: updateData }) => { @@ -63,7 +52,7 @@ export const secretDALFactory = (db: TDbClient) => { .where({ folderId }) .where((bd) => { data.forEach((el) => { - bd.orWhere({ + void bd.orWhere({ secretBlindIndex: el.blindIndex, type: el.type, ...(el.type === SecretType.Personal ? { userId } : {}) @@ -89,18 +78,10 @@ export const secretDALFactory = (db: TDbClient) => { const secs = await (tx || db)(TableName.Secret) .where({ folderId }) .where((bd) => { - bd.whereNull("userId").orWhere({ userId: userId || null }); + void bd.whereNull("userId").orWhere({ userId: userId || null }); }) - .leftJoin( - TableName.JnSecretTag, - `${TableName.Secret}.id`, - `${TableName.JnSecretTag}.${TableName.Secret}Id` - ) - .leftJoin( - TableName.SecretTag, - `${TableName.JnSecretTag}.${TableName.SecretTag}Id`, - `${TableName.SecretTag}.id` - ) + .leftJoin(TableName.JnSecretTag, `${TableName.Secret}.id`, `${TableName.JnSecretTag}.${TableName.Secret}Id`) + .leftJoin(TableName.SecretTag, `${TableName.JnSecretTag}.${TableName.SecretTag}Id`, `${TableName.SecretTag}.id`) .select(selectAllTableCols(TableName.Secret)) .select(db.ref("id").withSchema(TableName.SecretTag).as("tagId")) .select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor")) @@ -144,7 +125,7 @@ export const secretDALFactory = (db: TDbClient) => { if (el.type === SecretType.Personal && !userId) { throw new BadRequestError({ message: "Missing personal user id" }); } - bd.orWhere({ + void bd.orWhere({ secretBlindIndex: el.blindIndex, type: el.type, userId: el.type === SecretType.Personal ? userId : null diff --git a/backend/src/services/secret/secret-fns.ts b/backend/src/services/secret/secret-fns.ts index 9abaa84246..0f6caa2489 100644 --- a/backend/src/services/secret/secret-fns.ts +++ b/backend/src/services/secret/secret-fns.ts @@ -8,10 +8,7 @@ import { buildSecretBlindIndexFromName, decryptSymmetric128BitHexKeyUTF8 } from import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretDALFactory } from "./secret-dal"; -export const generateSecretBlindIndexBySalt = async ( - secretName: string, - secretBlindIndexDoc: TSecretBlindIndexes -) => { +export const generateSecretBlindIndexBySalt = async (secretName: string, secretBlindIndexDoc: TSecretBlindIndexes) => { const appCfg = getConfig(); const secretBlindIndex = await buildSecretBlindIndexFromName({ secretName, @@ -32,12 +29,7 @@ type TInterpolateSecretArg = { folderDAL: Pick; }; -export const interpolateSecrets = ({ - projectId, - secretEncKey, - secretDAL, - folderDAL -}: TInterpolateSecretArg) => { +export const interpolateSecrets = ({ projectId, secretEncKey, secretDAL, folderDAL }: TInterpolateSecretArg) => { const fetchSecretsCrossEnv = () => { const fetchCache: Record> = {}; @@ -197,10 +189,7 @@ export const interpolateSecrets = ({ return expandSecrets; }; -export const decryptSecretRaw = ( - secret: TSecrets & { workspace: string; environment: string }, - key: string -) => { +export const decryptSecretRaw = (secret: TSecrets & { workspace: string; environment: string }, key: string) => { const secretKey = decryptSymmetric128BitHexKeyUTF8({ ciphertext: secret.secretKeyCiphertext, iv: secret.secretKeyIV, diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index 71b2444aed..b797b7caf6 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -23,11 +23,7 @@ import { TWebhookDALFactory } from "../webhook/webhook-dal"; import { fnTriggerWebhook } from "../webhook/webhook-fns"; import { TSecretDALFactory } from "./secret-dal"; import { interpolateSecrets } from "./secret-fns"; -import { - TCreateSecretReminderDTO, - THandleReminderDTO, - TRemoveSecretReminderDTO -} from "./secret-types"; +import { TCreateSecretReminderDTO, THandleReminderDTO, TRemoveSecretReminderDTO } from "./secret-types"; export type TSecretQueueFactory = ReturnType; @@ -105,20 +101,13 @@ export const secretQueueFactory = ({ QueueJobs.SecretReminder, { // on prod it this will be in days, in development this will be second - every: - appCfg.NODE_ENV === "development" - ? secondsToMillis(dto.repeatDays) - : daysToMillisecond(dto.repeatDays) + every: appCfg.NODE_ENV === "development" ? secondsToMillis(dto.repeatDays) : daysToMillisecond(dto.repeatDays) }, `reminder-${dto.secretId}` ); }; - const addSecretReminder = async ({ - oldSecret, - newSecret, - projectId - }: TCreateSecretReminderDTO) => { + const addSecretReminder = async ({ oldSecret, newSecret, projectId }: TCreateSecretReminderDTO) => { try { const appCfg = getConfig(); @@ -179,8 +168,7 @@ export const secretQueueFactory = ({ if (newSecret.type !== "personal" && secretReminderRepeatDays !== undefined) { if ( - (secretReminderRepeatDays && - oldSecret.secretReminderRepeatDays !== secretReminderRepeatDays) || + (secretReminderRepeatDays && oldSecret.secretReminderRepeatDays !== secretReminderRepeatDays) || (secretReminderNote && oldSecret.secretReminderNote !== secretReminderNote) ) { await addSecretReminder({ @@ -212,10 +200,7 @@ export const secretQueueFactory = ({ secretDAL, folderDAL }); - const content: Record< - string, - { value: string; comment?: string; skipMultilineEncoding?: boolean } - > = {}; + const content: Record = {}; importedSecrets.forEach(({ secrets: secs }) => { secs.forEach((secret) => { @@ -294,8 +279,7 @@ export const secretQueueFactory = ({ const integrations = await integrationDAL.findByProjectIdV2(projectId, environment); const toBeSyncedIntegrations = integrations.filter( - ({ secretPath: integrationSecPath, isActive }) => - isActive && isSamePath(secretPath, integrationSecPath) + ({ secretPath: integrationSecPath, isActive }) => isActive && isSamePath(secretPath, integrationSecPath) ); if (!integrations.length) return; @@ -309,16 +293,10 @@ export const secretQueueFactory = ({ }; const botKey = await projectBotService.getBotKey(projectId); - const { accessToken, accessId } = await integrationAuthService.getIntegrationAccessToken( - integrationAuth, - botKey - ); - const secrets = await getIntegrationSecrets( - { environment, projectId, secretPath, folderId: folder.id }, - botKey - ); + const { accessToken, accessId } = await integrationAuthService.getIntegrationAccessToken(integrationAuth, botKey); + const secrets = await getIntegrationSecrets({ environment, projectId, secretPath, folderId: folder.id }, botKey); const suffixedSecrets: typeof secrets = {}; - const metadata = integration.metadata as Record; + const metadata = integration.metadata as Record; if (metadata) { Object.keys(secrets).forEach((key) => { const prefix = metadata?.secretPrefix || ""; @@ -353,25 +331,19 @@ export const secretQueueFactory = ({ const project = await projectDAL.findById(projectId); if (!organization) { - logger.info( - `secretReminderQueue.process: [secretDocument=${data.secretId}] no organization found` - ); + logger.info(`secretReminderQueue.process: [secretDocument=${data.secretId}] no organization found`); return; } if (!project) { - logger.info( - `secretReminderQueue.process: [secretDocument=${data.secretId}] no project found` - ); + logger.info(`secretReminderQueue.process: [secretDocument=${data.secretId}] no project found`); return; } const projectMembers = await projectMembershipDAL.findAllProjectMembers(projectId); if (!projectMembers || !projectMembers.length) { - logger.info( - `secretReminderQueue.process: [secretDocument=${data.secretId}] no project members found` - ); + logger.info(`secretReminderQueue.process: [secretDocument=${data.secretId}] no project members found`); return; } diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index f210a72a2b..71086446fd 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -1,17 +1,8 @@ import { ForbiddenError, subject } from "@casl/ability"; -import { - SecretEncryptionAlgo, - SecretKeyEncoding, - SecretsSchema, - SecretType, - TableName -} from "@app/db/schemas"; +import { SecretEncryptionAlgo, SecretKeyEncoding, SecretsSchema, SecretType, TableName } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service"; import { getConfig } from "@app/lib/config/env"; import { buildSecretBlindIndexFromName, encryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto"; @@ -58,17 +49,11 @@ type TSecretServiceFactoryDep = { secretDAL: TSecretDALFactory; secretTagDAL: TSecretTagDALFactory; secretVersionDAL: TSecretVersionDALFactory; - folderDAL: Pick< - TSecretFolderDALFactory, - "findBySecretPath" | "updateById" | "findById" | "findByManySecretPath" - >; + folderDAL: Pick; secretBlindIndexDAL: TSecretBlindIndexDALFactory; permissionService: Pick; snapshotService: Pick; - secretQueueService: Pick< - TSecretQueueFactory, - "syncSecrets" | "handleSecretReminder" | "removeSecretReminder" - >; + secretQueueService: Pick; projectBotService: Pick; secretImportDAL: Pick; secretVersionTagDAL: Pick; @@ -93,8 +78,7 @@ export const secretServiceFactory = ({ const appCfg = getConfig(); const secretBlindIndexDoc = await secretBlindIndexDAL.findOne({ projectId }); - if (!secretBlindIndexDoc) - throw new BadRequestError({ message: "Blind index not found", name: "Create secret" }); + if (!secretBlindIndexDoc) throw new BadRequestError({ message: "Blind index not found", name: "Create secret" }); const secretBlindIndex = await buildSecretBlindIndexFromName({ secretName, @@ -116,15 +100,11 @@ export const secretServiceFactory = ({ inputSecrets.map(({ tags, ...el }) => ({ ...el, folderId })), tx ); - const newSecretGroupByBlindIndex = groupBy( - newSecrets, - (item) => item.secretBlindIndex as string - ); + const newSecretGroupByBlindIndex = groupBy(newSecrets, (item) => item.secretBlindIndex as string); const newSecretTags = inputSecrets.flatMap(({ tags: secretTags = [], secretBlindIndex }) => secretTags.map((tag) => ({ [`${TableName.SecretTag}Id` as const]: tag, - [`${TableName.Secret}Id` as const]: - newSecretGroupByBlindIndex[secretBlindIndex as string][0].id + [`${TableName.Secret}Id` as const]: newSecretGroupByBlindIndex[secretBlindIndex as string][0].id })) ); const secretVersions = await secretVersionDAL.insertMany( @@ -148,12 +128,7 @@ export const secretServiceFactory = ({ return newSecrets.map((secret) => ({ ...secret, _id: secret.id })); }; - const fnSecretBulkUpdate = async ({ - tx, - inputSecrets, - folderId, - projectId - }: TFnSecretBulkUpdate) => { + const fnSecretBulkUpdate = async ({ tx, inputSecrets, folderId, projectId }: TFnSecretBulkUpdate) => { const newSecrets = await secretDAL.bulkUpdate( inputSecrets.map(({ filter, data: { tags, ...data } }) => ({ filter: { ...filter, folderId }, @@ -197,12 +172,7 @@ export const secretServiceFactory = ({ return newSecrets.map((secret) => ({ ...secret, _id: secret.id })); }; - const fnSecretBulkDelete = async ({ - folderId, - inputSecrets, - tx, - actorId - }: TFnSecretBulkDelete) => { + const fnSecretBulkDelete = async ({ folderId, inputSecrets, tx, actorId }: TFnSecretBulkDelete) => { const deletedSecrets = await secretDAL.deleteMany( inputSecrets.map(({ type, secretBlindIndex }) => ({ blindIndex: secretBlindIndex, @@ -245,9 +215,7 @@ export const secretServiceFactory = ({ }: TFnSecretBlindIndexCheck) => { const blindIndex2KeyName: Record = {}; // used at audit log point const keyName2BlindIndex = await Promise.all( - inputSecrets.map(({ secretName }) => - generateSecretBlindIndexBySalt(secretName, blindIndexCfg) - ) + inputSecrets.map(({ secretName }) => generateSecretBlindIndexBySalt(secretName, blindIndexCfg)) ).then((blindIndexes) => blindIndexes.reduce>((prev, curr, i) => { // eslint-disable-next-line @@ -282,11 +250,7 @@ export const secretServiceFactory = ({ // this is used when secret blind index already exist // mainly for secret approval - const fnSecretBlindIndexCheckV2 = async ({ - inputSecrets, - folderId, - userId - }: TFnSecretBlindIndexCheckV2) => { + const fnSecretBlindIndexCheckV2 = async ({ inputSecrets, folderId, userId }: TFnSecretBlindIndexCheckV2) => { if (inputSecrets.some(({ type }) => type === SecretType.Personal) && !userId) { throw new BadRequestError({ message: "Missing user id for personal secret" }); } @@ -303,14 +267,7 @@ export const secretServiceFactory = ({ return { secsGroupedByBlindIndex, secrets }; }; - const createSecret = async ({ - path, - actor, - actorId, - environment, - projectId, - ...inputSecret - }: TCreateSecretDTO) => { + const createSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TCreateSecretDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Create, @@ -322,8 +279,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); if (ActorType.USER !== actor && inputSecret.type === SecretType.Personal) { throw new BadRequestError({ message: "Must be user to create personal secret" }); @@ -352,11 +308,8 @@ export const secretServiceFactory = ({ // validate tags // fetch all tags and if not same count throw error meaning one was invalid tags - const tags = inputSecret.tags - ? await secretTagDAL.findManyTagsById(projectId, inputSecret.tags) - : []; - if ((inputSecret.tags || []).length !== tags.length) - throw new BadRequestError({ message: "Tag not found" }); + const tags = inputSecret.tags ? await secretTagDAL.findManyTagsById(projectId, inputSecret.tags) : []; + if ((inputSecret.tags || []).length !== tags.length) throw new BadRequestError({ message: "Tag not found" }); const { secretName, type, ...el } = inputSecret; const secret = await secretDAL.transaction((tx) => @@ -384,14 +337,7 @@ export const secretServiceFactory = ({ return { ...secret[0], environment, workspace: projectId, tags }; }; - const updateSecret = async ({ - path, - actor, - actorId, - environment, - projectId, - ...inputSecret - }: TUpdateSecretDTO) => { + const updateSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TUpdateSecretDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Edit, @@ -403,8 +349,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); if (ActorType.USER !== actor && inputSecret.type === SecretType.Personal) { throw new BadRequestError({ message: "Must be user to create personal secret" }); @@ -441,11 +386,8 @@ export const secretServiceFactory = ({ projectId }); - const tags = inputSecret.tags - ? await secretTagDAL.findManyTagsById(projectId, inputSecret.tags) - : []; - if ((inputSecret.tags || []).length !== tags.length) - throw new BadRequestError({ message: "Tag not found" }); + const tags = inputSecret.tags ? await secretTagDAL.findManyTagsById(projectId, inputSecret.tags) : []; + if ((inputSecret.tags || []).length !== tags.length) throw new BadRequestError({ message: "Tag not found" }); const { secretName, ...el } = inputSecret; const updatedSecret = await secretDAL.transaction(async (tx) => @@ -487,14 +429,7 @@ export const secretServiceFactory = ({ return { ...updatedSecret[0], workspace: projectId, environment }; }; - const deleteSecret = async ({ - path, - actor, - actorId, - environment, - projectId, - ...inputSecret - }: TDeleteSecretDTO) => { + const deleteSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TDeleteSecretDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Delete, @@ -506,8 +441,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "CreateSecret" }); if (ActorType.USER !== actor && inputSecret.type === SecretType.Personal) { throw new BadRequestError({ message: "Must be user to create personal secret" }); @@ -542,14 +476,7 @@ export const secretServiceFactory = ({ return { ...deletedSecret[0], _id: deletedSecret[0].id, workspace: projectId, environment }; }; - const getSecrets = async ({ - actorId, - path, - environment, - projectId, - actor, - includeImports - }: TGetSecretsDTO) => { + const getSecrets = async ({ actorId, path, environment, projectId, actor, includeImports }: TGetSecretsDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionActions.Read, @@ -683,8 +610,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); const { keyName2BlindIndex } = await fnSecretBlindIndexCheck({ inputSecrets, @@ -738,8 +664,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); const { keyName2BlindIndex } = await fnSecretBlindIndexCheck({ inputSecrets, @@ -809,8 +734,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); - if (!blindIndexCfg) - throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); const { keyName2BlindIndex } = await fnSecretBlindIndexCheck({ inputSecrets, @@ -838,46 +762,22 @@ export const secretServiceFactory = ({ return secretsDeleted; }; - const listSecretVersionsBySecretId = async ({ - actorId, - actor, - limit, - offset, - secretId - }: TListSecretVersionDTO) => { + const listSecretVersionsBySecretId = async ({ actorId, actor, limit, offset, secretId }: TListSecretVersionDTO) => { const secret = await secretDAL.findById(secretId); if (!secret) throw new BadRequestError({ message: "Failed to find secret" }); const folder = await folderDAL.findById(secret.folderId); if (!folder) throw new BadRequestError({ message: "Folder not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - folder.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRollback - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, folder.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); - const secretVersions = await secretVersionDAL.find( - { secretId }, - { limit, offset, sort: [["createdAt", "desc"]] } - ); + const secretVersions = await secretVersionDAL.find({ secretId }, { limit, offset, sort: [["createdAt", "desc"]] }); return secretVersions; }; - const getSecretsRaw = async ({ - projectId, - path, - actor, - actorId, - environment, - includeImports - }: TGetSecretsRawDTO) => { + const getSecretsRaw = async ({ projectId, path, actor, actorId, environment, includeImports }: TGetSecretsRawDTO) => { const botKey = await projectBotService.getBotKey(projectId); - if (!botKey) - throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); + if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); const { secrets, imports } = await getSecrets({ actorId, @@ -911,8 +811,7 @@ export const secretServiceFactory = ({ version }: TGetASecretRawDTO) => { const botKey = await projectBotService.getBotKey(projectId); - if (!botKey) - throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); + if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); const secret = await getSecretByName({ actorId, @@ -941,8 +840,7 @@ export const secretServiceFactory = ({ skipMultilineEncoding }: TCreateSecretRawDTO) => { const botKey = await projectBotService.getBotKey(projectId); - if (!botKey) - throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); + if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretName, botKey); const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey); @@ -986,8 +884,7 @@ export const secretServiceFactory = ({ skipMultilineEncoding }: TUpdateSecretRawDTO) => { const botKey = await projectBotService.getBotKey(projectId); - if (!botKey) - throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); + if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey); @@ -1021,8 +918,7 @@ export const secretServiceFactory = ({ secretPath }: TDeleteSecretRawDTO) => { const botKey = await projectBotService.getBotKey(projectId); - if (!botKey) - throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); + if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); const secret = await deleteSecret({ secretName, @@ -1040,33 +936,17 @@ export const secretServiceFactory = ({ return decryptSecretRaw(secret, botKey); }; - const getSecretVersions = async ({ - actorId, - actor, - limit = 20, - offset = 0, - secretId - }: TGetSecretVersionsDTO) => { + const getSecretVersions = async ({ actorId, actor, limit = 20, offset = 0, secretId }: TGetSecretVersionsDTO) => { const secret = await secretDAL.findById(secretId); if (!secret) throw new BadRequestError({ message: "Failed to find secret" }); const folder = await folderDAL.findById(secret.folderId); if (!folder) throw new BadRequestError({ message: "Failed to find secret" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - folder.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.SecretRollback - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, folder.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); - const secretVersions = await secretVersionDAL.find( - { secretId }, - { offset, limit, sort: [["createdAt", "desc"]] } - ); + const secretVersions = await secretVersionDAL.find({ secretId }, { offset, limit, sort: [["createdAt", "desc"]] }); return secretVersions; }; diff --git a/backend/src/services/secret/secret-types.ts b/backend/src/services/secret/secret-types.ts index f5fdf32a20..89e16d77ba 100644 --- a/backend/src/services/secret/secret-types.ts +++ b/backend/src/services/secret/secret-types.ts @@ -1,20 +1,11 @@ import { Knex } from "knex"; -import { - SecretType, - TSecretBlindIndexes, - TSecrets, - TSecretsInsert, - TSecretsUpdate -} from "@app/db/schemas"; +import { SecretType, TSecretBlindIndexes, TSecrets, TSecretsInsert, TSecretsUpdate } from "@app/db/schemas"; import { TProjectPermission } from "@app/lib/types"; type TPartialSecret = Pick; -type TPartialInputSecret = Pick< - TSecrets, - "type" | "secretReminderNote" | "secretReminderRepeatDays" | "id" ->; +type TPartialInputSecret = Pick; export type TCreateSecretDTO = { secretName: string; diff --git a/backend/src/services/secret/secret-version-dal.ts b/backend/src/services/secret/secret-version-dal.ts index 339b8346bf..7a6695e187 100644 --- a/backend/src/services/secret/secret-version-dal.ts +++ b/backend/src/services/secret/secret-version-dal.ts @@ -38,17 +38,11 @@ export const secretVersionDALFactory = (db: TDbClient) => { const findLatestVersionMany = async (folderId: string, secretIds: string[], tx?: Knex) => { try { - const docs: Array = await (tx || db)( - TableName.SecretVersion - ) + const docs: Array = await (tx || db)(TableName.SecretVersion) .where("folderId", folderId) .whereIn(`${TableName.SecretVersion}.secretId`, secretIds) .join( - (tx || db)(TableName.SecretVersion) - .groupBy("secretId") - .max("version") - .select("secretId") - .as("latestVersion"), + (tx || db)(TableName.SecretVersion).groupBy("secretId").max("version").select("secretId").as("latestVersion"), (bd) => { bd.on(`${TableName.SecretVersion}.secretId`, "latestVersion.secretId").andOn( `${TableName.SecretVersion}.version`, diff --git a/backend/src/services/service-token/service-token-service.ts b/backend/src/services/service-token/service-token-service.ts index 63d5f6aace..3813d6c05b 100644 --- a/backend/src/services/service-token/service-token-service.ts +++ b/backend/src/services/service-token/service-token-service.ts @@ -4,10 +4,7 @@ import { ForbiddenError, subject } from "@casl/ability"; import bcrypt from "bcrypt"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; @@ -50,10 +47,7 @@ export const serviceTokenServiceFactory = ({ encryptedKey }: TCreateServiceTokenDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.ServiceTokens - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.ServiceTokens); scopes.forEach(({ environment, secretPath }) => { ForbiddenError.from(permission).throwUnlessCan( @@ -67,8 +61,7 @@ export const serviceTokenServiceFactory = ({ // validates env const scopeEnvs = [...new Set(scopes.map(({ environment }) => environment))]; const inputEnvs = await projectEnvDAL.findBySlugs(projectId, scopeEnvs); - if (inputEnvs.length !== scopeEnvs.length) - throw new BadRequestError({ message: "Environment not found" }); + if (inputEnvs.length !== scopeEnvs.length) throw new BadRequestError({ message: "Environment not found" }); const secret = crypto.randomBytes(16).toString("hex"); const secretHash = await bcrypt.hash(secret, appCfg.SALT_ROUNDS); @@ -101,23 +94,15 @@ export const serviceTokenServiceFactory = ({ const serviceToken = await serviceTokenDAL.findById(id); if (!serviceToken) throw new BadRequestError({ message: "Token not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - serviceToken.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.ServiceTokens - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, serviceToken.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.ServiceTokens); const deletedServiceToken = await serviceTokenDAL.deleteById(id); return deletedServiceToken; }; const getServiceToken = async ({ actor, actorId }: TGetServiceTokenInfoDTO) => { - if (actor !== ActorType.SERVICE) - throw new BadRequestError({ message: "Service token not found" }); + if (actor !== ActorType.SERVICE) throw new BadRequestError({ message: "Service token not found" }); const serviceToken = await serviceTokenDAL.findById(actorId); if (!serviceToken) throw new BadRequestError({ message: "Token not found" }); @@ -128,16 +113,9 @@ export const serviceTokenServiceFactory = ({ return { serviceToken, user: serviceTokenUser }; }; - const getProjectServiceTokens = async ({ - actorId, - actor, - projectId - }: TProjectServiceTokensDTO) => { + const getProjectServiceTokens = async ({ actorId, actor, projectId }: TProjectServiceTokensDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.ServiceTokens - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens); const tokens = await serviceTokenDAL.find({ projectId }); return tokens; diff --git a/backend/src/services/smtp/smtp-service.ts b/backend/src/services/smtp/smtp-service.ts index 37c5a98a94..142993ceb9 100644 --- a/backend/src/services/smtp/smtp-service.ts +++ b/backend/src/services/smtp/smtp-service.ts @@ -41,8 +41,8 @@ export const getTlsOption = (host?: SmtpHost | string, secure?: boolean) => { if (!secure) return { secure: false }; if (!host) return { secure: true }; - if (host === SmtpHost.Sendgrid) { - return { secure: true, port: 465}; // more details here https://nodemailer.com/smtp/ + if ((host as SmtpHost) === SmtpHost.Sendgrid) { + return { secure: true, port: 465 }; // more details here https://nodemailer.com/smtp/ } if (host.includes("amazonaws.com")) { return { tls: { ciphers: "TLSv1.2" } }; diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts index a549cfac5c..c31d55d465 100644 --- a/backend/src/services/super-admin/super-admin-service.ts +++ b/backend/src/services/super-admin/super-admin-service.ts @@ -19,8 +19,7 @@ export type TSuperAdminServiceFactory = ReturnType; export const getServerCfg = () => { - if (!serverCfg) - throw new BadRequestError({ name: "Get server cfg", message: "Server cfg not initialized" }); + if (!serverCfg) throw new BadRequestError({ name: "Get server cfg", message: "Server cfg not initialized" }); return serverCfg; }; @@ -64,8 +63,7 @@ export const superAdminServiceFactory = ({ userAgent }: TAdminSignUpDTO) => { const existingUser = await userDAL.findOne({ email }); - if (existingUser) - throw new BadRequestError({ name: "Admin sign up", message: "User already exist" }); + if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exist" }); const userInfo = await userDAL.transaction(async (tx) => { const newUser = await userDAL.create( diff --git a/backend/src/services/telemetry/telemetry-service.ts b/backend/src/services/telemetry/telemetry-service.ts index 82e912deb2..c386abd955 100644 --- a/backend/src/services/telemetry/telemetry-service.ts +++ b/backend/src/services/telemetry/telemetry-service.ts @@ -51,7 +51,7 @@ To opt into telemetry, you can set "TELEMETRY_ENABLED=true" within the environme } }; - const sendPostHogEvents = async (event: TPostHogEvent) => { + const sendPostHogEvents = (event: TPostHogEvent) => { if (postHog) { postHog.capture({ event: event.event, diff --git a/backend/src/services/user/user-dal.ts b/backend/src/services/user/user-dal.ts index 8051cee289..0de4903991 100644 --- a/backend/src/services/user/user-dal.ts +++ b/backend/src/services/user/user-dal.ts @@ -24,11 +24,7 @@ export const userDALFactory = (db: TDbClient) => { try { return await db(TableName.Users) .where({ email }) - .join( - TableName.UserEncryptionKey, - `${TableName.Users}.id`, - `${TableName.UserEncryptionKey}.userId` - ) + .join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`) .first(); } catch (error) { throw new DatabaseError({ error, name: "Find user enc by email" }); @@ -39,11 +35,7 @@ export const userDALFactory = (db: TDbClient) => { try { const user = await db(TableName.Users) .where(`${TableName.Users}.id`, userId) - .join( - TableName.UserEncryptionKey, - `${TableName.Users}.id`, - `${TableName.UserEncryptionKey}.userId` - ) + .join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`) .first(); if (user?.id) { // change to user id @@ -64,11 +56,7 @@ export const userDALFactory = (db: TDbClient) => { } }; - const updateUserEncryptionByUserId = async ( - userId: string, - data: TUserEncryptionKeysUpdate, - tx?: Knex - ) => { + const updateUserEncryptionByUserId = async (userId: string, data: TUserEncryptionKeysUpdate, tx?: Knex) => { try { const [userEnc] = await (tx || db)(TableName.UserEncryptionKey) .where({ userId }) @@ -86,10 +74,7 @@ export const userDALFactory = (db: TDbClient) => { tx?: Knex ) => { try { - const [userEnc] = await (tx - ? tx(TableName.UserEncryptionKey) - : db(TableName.UserEncryptionKey) - ) + const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey)) // if user insert make sure to pass all required data .insert({ userId, ...data } as TUserEncryptionKeys) .onConflict("userId") diff --git a/backend/src/services/user/user-service.ts b/backend/src/services/user/user-service.ts index 81c7ea9d2b..b700869c2d 100644 --- a/backend/src/services/user/user-service.ts +++ b/backend/src/services/user/user-service.ts @@ -31,9 +31,7 @@ export const userServiceFactory = ({ userDAL }: TUserServiceFactoryDep) => { if (!user) throw new BadRequestError({ name: "Update auth methods" }); const hasSamlEnabled = user?.authMethods?.some((method) => - [AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes( - method as AuthMethod - ) + [AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(method as AuthMethod) ); if (hasSamlEnabled) throw new BadRequestError({ diff --git a/backend/src/services/webhook/webhook-dal.ts b/backend/src/services/webhook/webhook-dal.ts index 14abcac5a4..d1bd2e80a5 100644 --- a/backend/src/services/webhook/webhook-dal.ts +++ b/backend/src/services/webhook/webhook-dal.ts @@ -63,21 +63,16 @@ export const webhookDALFactory = (db: TDbClient) => { } }; - const findAllWebhooks = async ( - projectId: string, - environment?: string, - secretPath?: string, - tx?: Knex - ) => { + const findAllWebhooks = async (projectId: string, environment?: string, secretPath?: string, tx?: Knex) => { try { const webhooks = await (tx || db)(TableName.Webhook) .where(`${TableName.Environment}.projectId`, projectId) .where((qb) => { if (environment) { - qb.where("slug", environment); + void qb.where("slug", environment); } if (secretPath) { - qb.where("secretPath", secretPath); + void qb.where("secretPath", secretPath); } }) .join(TableName.Environment, `${TableName.Webhook}.envId`, `${TableName.Environment}.id`) @@ -103,9 +98,7 @@ export const webhookDALFactory = (db: TDbClient) => { const bulkUpdate = async (data: Array, tx?: Knex) => { try { - const queries = data.map(({ id, ...el }) => - (tx || db)(TableName.Webhook).where({ id }).update(el) - ); + const queries = data.map(({ id, ...el }) => (tx || db)(TableName.Webhook).where({ id }).update(el)); const docs = await Promise.all(queries); return docs; } catch (error) { diff --git a/backend/src/services/webhook/webhook-fns.ts b/backend/src/services/webhook/webhook-fns.ts index a43d1c9691..35d2ba7fcf 100644 --- a/backend/src/services/webhook/webhook-fns.ts +++ b/backend/src/services/webhook/webhook-fns.ts @@ -1,5 +1,6 @@ import crypto from "node:crypto"; +import { AxiosError } from "axios"; import picomatch from "picomatch"; import { SecretKeyEncoding, TWebhooks } from "@app/db/schemas"; @@ -43,10 +44,7 @@ export const triggerWebhookRequest = async ( }); } if (secretKey) { - const webhookSign = crypto - .createHmac("sha256", secretKey) - .update(JSON.stringify(payload)) - .digest("hex"); + const webhookSign = crypto.createHmac("sha256", secretKey).update(JSON.stringify(payload)).digest("hex"); headers["x-infisical-signature"] = `t=${payload.timestamp};${webhookSign}`; } } @@ -97,10 +95,7 @@ export const fnTriggerWebhook = async ({ logger.info("Secret webhook job started", { environment, secretPath, projectId }); const webhooksTriggered = await Promise.allSettled( toBeTriggeredHooks.map((hook) => - triggerWebhookRequest( - hook, - getWebhookPayload("secrets.modified", projectId, environment, secretPath) - ) + triggerWebhookRequest(hook, getWebhookPayload("secrets.modified", projectId, environment, secretPath)) ) ); // filter hooks by status @@ -111,7 +106,7 @@ export const fnTriggerWebhook = async ({ .filter(({ status }) => status === "rejected") .map((data, i) => ({ id: toBeTriggeredHooks[i].id, - error: data.status === "rejected" && data.reason.message + error: data.status === "rejected" ? (data.reason as AxiosError).message : "" })); await webhookDAL.transaction(async (tx) => { diff --git a/backend/src/services/webhook/webhook-service.ts b/backend/src/services/webhook/webhook-service.ts index e176cc8655..c208ba472f 100644 --- a/backend/src/services/webhook/webhook-service.ts +++ b/backend/src/services/webhook/webhook-service.ts @@ -2,10 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import { SecretEncryptionAlgo, SecretKeyEncoding, TWebhooksInsert } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { - ProjectPermissionActions, - ProjectPermissionSub -} from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { getConfig } from "@app/lib/config/env"; import { encryptSymmetric, encryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto"; import { BadRequestError } from "@app/lib/errors"; @@ -29,11 +26,7 @@ type TWebhookServiceFactoryDep = { export type TWebhookServiceFactory = ReturnType; -export const webhookServiceFactory = ({ - webhookDAL, - projectEnvDAL, - permissionService -}: TWebhookServiceFactoryDep) => { +export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionService }: TWebhookServiceFactoryDep) => { const createWebhook = async ({ actor, actorId, @@ -44,10 +37,7 @@ export const webhookServiceFactory = ({ webhookSecretKey }: TCreateWebhookDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, - ProjectPermissionSub.Webhooks - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Webhooks); const env = await projectEnvDAL.findOne({ projectId, slug: environment }); if (!env) throw new BadRequestError({ message: "Env not found" }); @@ -69,10 +59,7 @@ export const webhookServiceFactory = ({ insertDoc.algorithm = SecretEncryptionAlgo.AES_256_GCM; insertDoc.keyEncoding = SecretKeyEncoding.BASE64; } else if (encryptionKey) { - const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8( - webhookSecretKey, - encryptionKey - ); + const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8(webhookSecretKey, encryptionKey); insertDoc.encryptedSecretKey = ciphertext; insertDoc.iv = iv; insertDoc.tag = tag; @@ -89,15 +76,8 @@ export const webhookServiceFactory = ({ const webhook = await webhookDAL.findById(id); if (!webhook) throw new BadRequestError({ message: "Webhook not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - webhook.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Webhooks - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Webhooks); const updatedWebhook = await webhookDAL.updateById(id, { isDisabled }); return { ...webhook, ...updatedWebhook }; @@ -107,15 +87,8 @@ export const webhookServiceFactory = ({ const webhook = await webhookDAL.findById(id); if (!webhook) throw new BadRequestError({ message: "Webhook not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - webhook.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, - ProjectPermissionSub.Webhooks - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Webhooks); const deletedWebhook = await webhookDAL.deleteById(id); return { ...webhook, ...deletedWebhook }; @@ -125,15 +98,8 @@ export const webhookServiceFactory = ({ const webhook = await webhookDAL.findById(id); if (!webhook) throw new BadRequestError({ message: "Webhook not found" }); - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - webhook.projectId - ); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Webhooks - ); + const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks); let webhookError: string | undefined; try { @@ -152,18 +118,9 @@ export const webhookServiceFactory = ({ return { ...webhook, ...updatedWebhook }; }; - const listWebhooks = async ({ - actorId, - actor, - projectId, - secretPath, - environment - }: TListWebhookDTO) => { + const listWebhooks = async ({ actorId, actor, projectId, secretPath, environment }: TListWebhookDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.Webhooks - ); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks); return webhookDAL.findAllWebhooks(projectId, environment, secretPath); };