feat(infisical-pg): added single scope service token auto filling for get secret by name raw and version option for both get secret by name

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:23 +05:30
parent 6c2803da93
commit e8fd693da3
3 changed files with 62 additions and 24 deletions
@@ -71,7 +71,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
environment, environment,
projectId: workspaceId as string, projectId: workspaceId,
path: secretPath, path: secretPath,
includeImports: req.query.include_imports includeImports: req.query.include_imports
}); });
@@ -100,9 +100,10 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secretName: z.string().trim() secretName: z.string().trim()
}), }),
querystring: z.object({ querystring: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim().optional(),
environment: z.string().trim(), environment: z.string().trim().optional(),
secretPath: z.string().trim().default("/"), secretPath: z.string().trim().default("/"),
version: z.coerce.number().optional(),
type: z.nativeEnum(SecretType).default(SecretType.Shared), type: z.nativeEnum(SecretType).default(SecretType.Shared),
include_imports: z include_imports: z
.enum(["true", "false"]) .enum(["true", "false"])
@@ -122,15 +123,30 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
AuthMode.IDENTITY_ACCESS_TOKEN AuthMode.IDENTITY_ACCESS_TOKEN
]), ]),
handler: async (req) => { handler: async (req) => {
const secret = await server.services.secret.getASecretRaw({ let { secretPath, environment, workspaceId } = req.query;
if (req.auth.actor === ActorType.SERVICE) {
const scope = ServiceTokenScopes.parse(req.auth.serviceToken.scopes);
const isSingleScope = scope.length === 1;
if (isSingleScope && !picomatch.scan(scope[0].secretPath).isGlob) {
secretPath = scope[0].secretPath;
environment = scope[0].environment;
workspaceId = req.auth.serviceToken.projectId;
}
}
if (!workspaceId || !environment)
throw new BadRequestError({ message: "Missing workspace id or environment" });
const secret = await server.services.secret.getSecretByNameRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
environment: req.query.environment, environment,
projectId: req.query.workspaceId, projectId: workspaceId,
path: req.query.secretPath, path: secretPath,
secretName: req.params.secretName, secretName: req.params.secretName,
type: req.query.type, type: req.query.type,
includeImports: req.query.include_imports includeImports: req.query.include_imports,
version: req.query.version
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -411,6 +427,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
environment: z.string().trim(), environment: z.string().trim(),
secretPath: z.string().trim().default("/"), secretPath: z.string().trim().default("/"),
type: z.nativeEnum(SecretType).default(SecretType.Shared), type: z.nativeEnum(SecretType).default(SecretType.Shared),
version: z.coerce.number().optional(),
include_imports: z include_imports: z
.enum(["true", "false"]) .enum(["true", "false"])
.default("false") .default("false")
@@ -429,7 +446,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
AuthMode.IDENTITY_ACCESS_TOKEN AuthMode.IDENTITY_ACCESS_TOKEN
]), ]),
handler: async (req) => { handler: async (req) => {
const secret = await server.services.secret.getASecret({ const secret = await server.services.secret.getSecretByName({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
environment: req.query.environment, environment: req.query.environment,
@@ -437,7 +454,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
path: req.query.secretPath, path: req.query.secretPath,
secretName: req.params.secretName, secretName: req.params.secretName,
type: req.query.type, type: req.query.type,
includeImports: req.query.include_imports includeImports: req.query.include_imports,
version: req.query.version
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -1,6 +1,12 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { SecretEncryptionAlgo, SecretKeyEncoding, 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 { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -530,7 +536,7 @@ export const secretServiceFactory = ({
return { secrets: secrets.map((el) => ({ ...el, workspace: projectId, environment })) }; return { secrets: secrets.map((el) => ({ ...el, workspace: projectId, environment })) };
}; };
const getASecret = async ({ const getSecretByName = async ({
actorId, actorId,
actor, actor,
projectId, projectId,
@@ -538,6 +544,7 @@ export const secretServiceFactory = ({
path, path,
type, type,
secretName, secretName,
version,
includeImports includeImports
}: TGetASecretDTO) => { }: TGetASecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
@@ -551,12 +558,21 @@ export const secretServiceFactory = ({
const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName); const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName);
const secret = await secretDal.findOne({ const secret = await (typeof version !== undefined
folderId, ? secretDal.findOne({
type, folderId,
userId: type === SecretType.Personal ? actorId : null, type,
secretBlindIndex userId: type === SecretType.Personal ? actorId : null,
}); secretBlindIndex
})
: secretVersionDal
.findOne({
folderId,
type,
userId: type === SecretType.Personal ? actorId : null,
secretBlindIndex
})
.then((el) => SecretsSchema.parse({ ...el, id: el.secretId })));
// now if secret is not found // now if secret is not found
// then search for imported secrets // then search for imported secrets
// here we consider the import order also thus starting from bottom // here we consider the import order also thus starting from bottom
@@ -831,7 +847,7 @@ export const secretServiceFactory = ({
}; };
}; };
const getASecretRaw = async ({ const getSecretByNameRaw = async ({
type, type,
path, path,
actor, actor,
@@ -839,13 +855,14 @@ export const secretServiceFactory = ({
projectId, projectId,
actorId, actorId,
secretName, secretName,
includeImports includeImports,
version
}: TGetASecretRawDTO) => { }: TGetASecretRawDTO) => {
const botKey = await projectBotService.getBotKey(projectId); const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) if (!botKey)
throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
const secret = await getASecret({ const secret = await getSecretByName({
actorId, actorId,
projectId, projectId,
environment, environment,
@@ -853,7 +870,8 @@ export const secretServiceFactory = ({
path, path,
secretName, secretName,
type, type,
includeImports includeImports,
version
}); });
return decryptSecretRaw(secret, botKey); return decryptSecretRaw(secret, botKey);
}; };
@@ -1007,10 +1025,10 @@ export const secretServiceFactory = ({
createManySecret, createManySecret,
updateManySecret, updateManySecret,
deleteManySecret, deleteManySecret,
getASecret, getSecretByName,
getSecrets, getSecrets,
getSecretsRaw, getSecretsRaw,
getASecretRaw, getSecretByNameRaw,
createSecretRaw, createSecretRaw,
updateSecretRaw, updateSecretRaw,
deleteSecretRaw, deleteSecretRaw,
@@ -76,6 +76,7 @@ export type TGetASecretDTO = {
environment: string; environment: string;
type: "shared" | "personal"; type: "shared" | "personal";
includeImports?: boolean; includeImports?: boolean;
version?: number;
} & TProjectPermission; } & TProjectPermission;
export type TCreateBulkSecretDTO = { export type TCreateBulkSecretDTO = {
@@ -145,6 +146,7 @@ export type TGetASecretRawDTO = {
environment: string; environment: string;
type: "shared" | "personal"; type: "shared" | "personal";
includeImports?: boolean; includeImports?: boolean;
version?: number;
} & TProjectPermission; } & TProjectPermission;
export type TCreateSecretRawDTO = TProjectPermission & { export type TCreateSecretRawDTO = TProjectPermission & {