mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 13:28:27 +00:00
fix: move permissions
This commit is contained in:
@@ -2114,16 +2114,26 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
[`${TableName.SecretV2}.id` as "id"]: secretIds
|
[`${TableName.SecretV2}.id` as "id"]: secretIds
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sourceActions = [
|
||||||
|
ProjectPermissionSecretActions.Delete,
|
||||||
|
ProjectPermissionSecretActions.ReadValue,
|
||||||
|
ProjectPermissionSecretActions.DescribeSecret
|
||||||
|
] as const;
|
||||||
|
const destinationActions = [ProjectPermissionSecretActions.Create, ProjectPermissionSecretActions.Edit] as const;
|
||||||
|
|
||||||
sourceSecrets.forEach((secret) => {
|
sourceSecrets.forEach((secret) => {
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
for (const sourceAction of sourceActions) {
|
||||||
ProjectPermissionSecretActions.Delete,
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
sourceAction,
|
||||||
environment: sourceEnvironment,
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
secretPath: sourceSecretPath,
|
environment: sourceEnvironment,
|
||||||
secretName: secret.key,
|
secretPath: sourceSecretPath,
|
||||||
secretTags: secret.tags.map((el) => el.slug)
|
secretName: secret.key,
|
||||||
})
|
secretTags: secret.tags.map((el) => el.slug)
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sourceSecrets.length !== secretIds.length) {
|
if (sourceSecrets.length !== secretIds.length) {
|
||||||
@@ -2198,27 +2208,17 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
// permission check whether can create or edit the ones in the destination folder
|
// permission check whether can create or edit the ones in the destination folder
|
||||||
locallyCreatedSecrets.forEach((secret) => {
|
locallyCreatedSecrets.forEach((secret) => {
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
for (const destinationAction of destinationActions) {
|
||||||
ProjectPermissionSecretActions.Create,
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
destinationAction,
|
||||||
environment: destinationEnvironment,
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
secretPath: destinationEnvironment,
|
environment: destinationEnvironment,
|
||||||
secretName: secret.key,
|
secretPath: destinationFolder.path,
|
||||||
secretTags: secret.tags.map((el) => el.slug)
|
secretName: secret.key,
|
||||||
})
|
secretTags: secret.tags.map((el) => el.slug)
|
||||||
);
|
})
|
||||||
});
|
);
|
||||||
|
}
|
||||||
locallyUpdatedSecrets.forEach((secret) => {
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionSecretActions.Edit,
|
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
|
||||||
environment: destinationEnvironment,
|
|
||||||
secretPath: destinationEnvironment,
|
|
||||||
secretName: secret.key,
|
|
||||||
secretTags: secret.tags.map((el) => el.slug)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const destinationFolderPolicy = await secretApprovalPolicyService.getSecretApprovalPolicy(
|
const destinationFolderPolicy = await secretApprovalPolicyService.getSecretApprovalPolicy(
|
||||||
|
|||||||
@@ -169,6 +169,48 @@ export const secretDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findManySecretsWithTags = async (
|
||||||
|
filter: {
|
||||||
|
secretIds: string[];
|
||||||
|
type: SecretType;
|
||||||
|
},
|
||||||
|
tx?: Knex
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const secrets = await (tx || db.replicaNode())(TableName.Secret)
|
||||||
|
.whereIn(`${TableName.Secret}.id` as "id", filter.secretIds)
|
||||||
|
.where("type", filter.type)
|
||||||
|
.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"))
|
||||||
|
.select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug"));
|
||||||
|
|
||||||
|
const data = sqlNestRelationships({
|
||||||
|
data: secrets,
|
||||||
|
key: "id",
|
||||||
|
parentMapper: (el) => ({ _id: el.id, ...SecretsSchema.parse(el) }),
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
key: "tagId",
|
||||||
|
label: "tags" as const,
|
||||||
|
mapper: ({ tagId: id, tagColor: color, tagSlug: slug }) => ({
|
||||||
|
id,
|
||||||
|
color,
|
||||||
|
slug,
|
||||||
|
name: slug
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "get many secrets with tags" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const findByFolderIds = async (folderIds: string[], userId?: string, tx?: Knex) => {
|
const findByFolderIds = async (folderIds: string[], userId?: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
// check if not uui then userId id is null (corner case because service token's ID is not UUI in effort to keep backwards compatibility from mongo)
|
// check if not uui then userId id is null (corner case because service token's ID is not UUI in effort to keep backwards compatibility from mongo)
|
||||||
@@ -443,6 +485,7 @@ export const secretDALFactory = (db: TDbClient) => {
|
|||||||
upsertSecretReferences,
|
upsertSecretReferences,
|
||||||
findReferencedSecretReferences,
|
findReferencedSecretReferences,
|
||||||
findAllProjectSecretValues,
|
findAllProjectSecretValues,
|
||||||
pruneSecretReminders
|
pruneSecretReminders,
|
||||||
|
findManySecretsWithTags
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ActionProjectType,
|
ActionProjectType,
|
||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
ProjectUpgradeStatus,
|
ProjectUpgradeStatus,
|
||||||
|
ProjectVersion,
|
||||||
SecretEncryptionAlgo,
|
SecretEncryptionAlgo,
|
||||||
SecretKeyEncoding,
|
SecretKeyEncoding,
|
||||||
SecretsSchema,
|
SecretsSchema,
|
||||||
@@ -2730,7 +2731,7 @@ export const secretServiceFactory = ({
|
|||||||
message: `Project with slug '${projectSlug}' not found`
|
message: `Project with slug '${projectSlug}' not found`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (project.version === 3) {
|
if (project.version === ProjectVersion.V3) {
|
||||||
return secretV2BridgeService.moveSecrets({
|
return secretV2BridgeService.moveSecrets({
|
||||||
sourceEnvironment,
|
sourceEnvironment,
|
||||||
sourceSecretPath,
|
sourceSecretPath,
|
||||||
@@ -2755,34 +2756,6 @@ export const secretServiceFactory = ({
|
|||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
|
|
||||||
const permissionChecks = [
|
|
||||||
{
|
|
||||||
action: ProjectPermissionSecretActions.Delete,
|
|
||||||
subject: {
|
|
||||||
environment: sourceEnvironment,
|
|
||||||
secretPath: sourceSecretPath
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: ProjectPermissionSecretActions.Create,
|
|
||||||
subject: {
|
|
||||||
environment: destinationEnvironment,
|
|
||||||
secretPath: destinationSecretPath
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: ProjectPermissionSecretActions.Edit,
|
|
||||||
subject: {
|
|
||||||
environment: destinationEnvironment,
|
|
||||||
secretPath: destinationSecretPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
for (const { action, subject: permissionSubject } of permissionChecks) {
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(action, subject(ProjectPermissionSub.Secrets, permissionSubject));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { botKey } = await projectBotService.getBotKey(project.id);
|
const { botKey } = await projectBotService.getBotKey(project.id);
|
||||||
if (!botKey) {
|
if (!botKey) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -2810,11 +2783,9 @@ export const secretServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceSecrets = await secretDAL.find({
|
const sourceSecrets = await secretDAL.findManySecretsWithTags({
|
||||||
type: SecretType.Shared,
|
type: SecretType.Shared,
|
||||||
$in: {
|
secretIds
|
||||||
id: secretIds
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sourceSecrets.length !== secretIds.length) {
|
if (sourceSecrets.length !== secretIds.length) {
|
||||||
@@ -2823,21 +2794,60 @@ export const secretServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const decryptedSourceSecrets = sourceSecrets.map((secret) => ({
|
const sourceActions = [
|
||||||
...secret,
|
ProjectPermissionSecretActions.Delete,
|
||||||
secretKey: decryptSymmetric128BitHexKeyUTF8({
|
ProjectPermissionSecretActions.DescribeSecret,
|
||||||
|
ProjectPermissionSecretActions.ReadValue
|
||||||
|
] as const;
|
||||||
|
const destinationActions = [ProjectPermissionSecretActions.Create, ProjectPermissionSecretActions.Edit] as const;
|
||||||
|
|
||||||
|
const decryptedSourceSecrets = sourceSecrets.map((secret) => {
|
||||||
|
const secretKey = decryptSymmetric128BitHexKeyUTF8({
|
||||||
ciphertext: secret.secretKeyCiphertext,
|
ciphertext: secret.secretKeyCiphertext,
|
||||||
iv: secret.secretKeyIV,
|
iv: secret.secretKeyIV,
|
||||||
tag: secret.secretKeyTag,
|
tag: secret.secretKeyTag,
|
||||||
key: botKey
|
key: botKey
|
||||||
}),
|
});
|
||||||
secretValue: decryptSymmetric128BitHexKeyUTF8({
|
|
||||||
ciphertext: secret.secretValueCiphertext,
|
for (const destinationAction of destinationActions) {
|
||||||
iv: secret.secretValueIV,
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
tag: secret.secretValueTag,
|
destinationAction,
|
||||||
key: botKey
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
})
|
environment: destinationEnvironment,
|
||||||
}));
|
secretPath: destinationSecretPath,
|
||||||
|
secretName: secretKey,
|
||||||
|
...(secret.tags.length && {
|
||||||
|
secretTags: secret.tags.map((t) => t.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const sourceAction of sourceActions) {
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
sourceAction,
|
||||||
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
|
environment: sourceEnvironment,
|
||||||
|
secretPath: sourceSecretPath,
|
||||||
|
secretName: secretKey,
|
||||||
|
...(secret.tags.length && {
|
||||||
|
secretTags: secret.tags.map((t) => t.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...secret,
|
||||||
|
secretKey,
|
||||||
|
secretValue: decryptSymmetric128BitHexKeyUTF8({
|
||||||
|
ciphertext: secret.secretValueCiphertext,
|
||||||
|
iv: secret.secretValueIV,
|
||||||
|
tag: secret.secretValueTag,
|
||||||
|
key: botKey
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
let isSourceUpdated = false;
|
let isSourceUpdated = false;
|
||||||
let isDestinationUpdated = false;
|
let isDestinationUpdated = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user