diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index cd2d3248e..4399b4be0 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -3,12 +3,15 @@ import { Types } from "mongoose"; import { EventService, SecretService } from "../../services"; import { eventPushSecrets } from "../../events"; import { BotService } from "../../services"; -import { repackageSecretToRaw } from "../../helpers/secrets"; +import { containsGlobPatterns, repackageSecretToRaw } from "../../helpers/secrets"; import { encryptSymmetric128BitHexKeyUTF8 } from "../../utils/crypto"; import { getAllImportedSecrets } from "../../services/SecretImportService"; import Folder from "../../models/folder"; import { getFolderByPath } from "../../services/FolderService"; import { BadRequestError } from "../../utils/errors"; +import { IServiceTokenData } from "../../models"; +import { requireWorkspaceAuth } from "../../middleware"; +import { ADMIN, MEMBER, PERMISSION_READ_SECRETS } from "../../variables"; /** * Return secrets for workspace with id [workspaceId] and environment @@ -17,11 +20,31 @@ import { BadRequestError } from "../../utils/errors"; * @param res */ export const getSecretsRaw = async (req: Request, res: Response) => { - const workspaceId = req.query.workspaceId as string; - const environment = req.query.environment as string; - const secretPath = req.query.secretPath as string; + let workspaceId = req.query.workspaceId as string; + let environment = req.query.environment as string; + let secretPath = req.query.secretPath as string; const includeImports = req.query.include_imports as string; + // if the service token has single scope, it will get all secrets for that scope by default + const serviceTokenDetails: IServiceTokenData = req?.serviceTokenData + if (serviceTokenDetails) { + if (serviceTokenDetails.scopes.length == 1 && !containsGlobPatterns(serviceTokenDetails.scopes[0].secretPath)) { + const scope = serviceTokenDetails.scopes[0] + secretPath = scope.secretPath + environment = scope.environment + workspaceId = serviceTokenDetails.workspace.toString() + } else { + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + locationWorkspaceId: "query", + locationEnvironment: "query", + requiredPermissions: [PERMISSION_READ_SECRETS], + requireBlindIndicesEnabled: true, + requireE2EEOff: true + }) + } + } + const secrets = await SecretService.getSecrets({ workspaceId: new Types.ObjectId(workspaceId), environment, diff --git a/backend/src/helpers/secrets.ts b/backend/src/helpers/secrets.ts index 1a68930bc..c770e78fb 100644 --- a/backend/src/helpers/secrets.ts +++ b/backend/src/helpers/secrets.ts @@ -44,6 +44,7 @@ import { EELogService, EESecretService } from "../ee/services"; import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/auth"; import { getFolderIdFromServiceToken } from "../services/FolderService"; import picomatch from "picomatch"; +import path from "path"; export const isValidScope = ( authPayload: IServiceTokenData, @@ -60,6 +61,13 @@ export const isValidScope = ( return Boolean(validScope); }; +export function containsGlobPatterns(secretPath: string) { + const globChars = ["*", "?", "[", "]", "{", "}", "**"]; + const normalizedPath = path.normalize(secretPath); + return globChars.some(char => normalizedPath.includes(char)); +} + + /** * Returns an object containing secret [secret] but with its value, key, comment decrypted. * diff --git a/backend/src/routes/v3/secrets.ts b/backend/src/routes/v3/secrets.ts index 69ba938e6..cea90a6ca 100644 --- a/backend/src/routes/v3/secrets.ts +++ b/backend/src/routes/v3/secrets.ts @@ -18,8 +18,8 @@ import { router.get( "/raw", - query("workspaceId").exists().isString().trim(), - query("environment").exists().isString().trim(), + query("workspaceId").optional().isString().trim(), + query("environment").optional().isString().trim(), query("secretPath").default("/").isString().trim(), query("include_imports").optional().isBoolean().default(false), validateRequest, @@ -31,14 +31,6 @@ router.get( AUTH_MODE_SERVICE_ACCOUNT ] }), - requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - locationWorkspaceId: "query", - locationEnvironment: "query", - requiredPermissions: [PERMISSION_READ_SECRETS], - requireBlindIndicesEnabled: true, - requireE2EEOff: true - }), secretsController.getSecretsRaw ); diff --git a/docs/api-reference/overview/examples/e2ee-disabled.mdx b/docs/api-reference/overview/examples/e2ee-disabled.mdx index 9864a1ff5..1a9e57552 100644 --- a/docs/api-reference/overview/examples/e2ee-disabled.mdx +++ b/docs/api-reference/overview/examples/e2ee-disabled.mdx @@ -7,8 +7,7 @@ in plaintext. Effectively, this means each such secret operation only requires 1 - Retrieve all secrets for an Infisical project and environment. - + Retrieve all secrets for an Infisical project and environment. ```bash @@ -18,7 +17,12 @@ in plaintext. Effectively, this means each such secret operation only requires 1 ``` - + #### + + When using a [service token](../../../documentation/platform/token) with access to a single environment and path, you don't need to provide request parameters because the server will automatically scope the request to the defined environment/secrets path of the service token used. + For all other cases, request parameters are required. + + #### The ID of the workspace