fix: resolved secret version empty

This commit is contained in:
akhilmhdh
2023-06-28 20:32:12 +05:30
parent 0e9c71ae9f
commit f1d609cf40
3 changed files with 175 additions and 169 deletions
@@ -54,23 +54,20 @@ export const getSecretVersions = async (req: Request, res: Response) => {
} }
} }
*/ */
const { secretId, workspaceId, environment, folderId } = req.params; const { secretId } = req.params;
const offset: number = parseInt(req.query.offset as string); const offset: number = parseInt(req.query.offset as string);
const limit: number = parseInt(req.query.limit as string); const limit: number = parseInt(req.query.limit as string);
const secretVersions = await SecretVersion.find({ const secretVersions = await SecretVersion.find({
secret: secretId, secret: secretId
workspace: workspaceId,
environment,
folder: folderId,
}) })
.sort({ createdAt: -1 }) .sort({ createdAt: -1 })
.skip(offset) .skip(offset)
.limit(limit); .limit(limit);
return res.status(200).send({ return res.status(200).send({
secretVersions, secretVersions
}); });
}; };
@@ -135,7 +132,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
// validate secret version // validate secret version
const oldSecretVersion = await SecretVersion.findOne({ const oldSecretVersion = await SecretVersion.findOne({
secret: secretId, secret: secretId,
version, version
}).select("+secretBlindIndex"); }).select("+secretBlindIndex");
if (!oldSecretVersion) throw new Error("Failed to find secret version"); if (!oldSecretVersion) throw new Error("Failed to find secret version");
@@ -154,7 +151,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
secretValueTag, secretValueTag,
algorithm, algorithm,
folder, folder,
keyEncoding, keyEncoding
} = oldSecretVersion; } = oldSecretVersion;
// update secret // update secret
@@ -162,7 +159,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
secretId, secretId,
{ {
$inc: { $inc: {
version: 1, version: 1
}, },
workspace, workspace,
type, type,
@@ -177,10 +174,10 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
secretValueTag, secretValueTag,
folderId: folder, folderId: folder,
algorithm, algorithm,
keyEncoding, keyEncoding
}, },
{ {
new: true, new: true
} }
); );
@@ -204,17 +201,17 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
secretValueTag, secretValueTag,
folder, folder,
algorithm, algorithm,
keyEncoding, keyEncoding
}).save(); }).save();
// take secret snapshot // take secret snapshot
await EESecretService.takeSecretSnapshot({ await EESecretService.takeSecretSnapshot({
workspaceId: secret.workspace, workspaceId: secret.workspace,
environment, environment,
folderId: folder, folderId: folder
}); });
return res.status(200).send({ return res.status(200).send({
secret, secret
}); });
}; };
+162 -153
View File
@@ -81,76 +81,79 @@ export const useGetProjectSecrets = ({
enabled: Boolean(decryptFileKey && workspaceId && env) && !isPaused, enabled: Boolean(decryptFileKey && workspaceId && env) && !isPaused,
queryKey: secretKeys.getProjectSecret(workspaceId, env, folderId), queryKey: secretKeys.getProjectSecret(workspaceId, env, folderId),
queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId), queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId),
select: useCallback((data: EncryptedSecret[]) => { select: useCallback(
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; (data: EncryptedSecret[]) => {
const latestKey = decryptFileKey; const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
const key = decryptAssymmetric({ const latestKey = decryptFileKey;
ciphertext: latestKey.encryptedKey, const key = decryptAssymmetric({
nonce: latestKey.nonce, ciphertext: latestKey.encryptedKey,
publicKey: latestKey.sender.publicKey, nonce: latestKey.nonce,
privateKey: PRIVATE_KEY publicKey: latestKey.sender.publicKey,
}); privateKey: PRIVATE_KEY
const sharedSecrets: DecryptedSecret[] = [];
const personalSecrets: Record<string, { id: string; value: string }> = {};
// this used for add-only mode in dashboard
// type won't be there thus only one key is shown
const duplicateSecretKey: Record<string, boolean> = {};
data.forEach((encSecret: EncryptedSecret) => {
const secretKey = decryptSymmetric({
ciphertext: encSecret.secretKeyCiphertext,
iv: encSecret.secretKeyIV,
tag: encSecret.secretKeyTag,
key
}); });
const secretValue = decryptSymmetric({ const sharedSecrets: DecryptedSecret[] = [];
ciphertext: encSecret.secretValueCiphertext, const personalSecrets: Record<string, { id: string; value: string }> = {};
iv: encSecret.secretValueIV, // this used for add-only mode in dashboard
tag: encSecret.secretValueTag, // type won't be there thus only one key is shown
key const duplicateSecretKey: Record<string, boolean> = {};
}); data.forEach((encSecret: EncryptedSecret) => {
const secretKey = decryptSymmetric({
ciphertext: encSecret.secretKeyCiphertext,
iv: encSecret.secretKeyIV,
tag: encSecret.secretKeyTag,
key
});
const secretComment = decryptSymmetric({ const secretValue = decryptSymmetric({
ciphertext: encSecret.secretCommentCiphertext, ciphertext: encSecret.secretValueCiphertext,
iv: encSecret.secretCommentIV, iv: encSecret.secretValueIV,
tag: encSecret.secretCommentTag, tag: encSecret.secretValueTag,
key key
}); });
const decryptedSecret = { const secretComment = decryptSymmetric({
_id: encSecret._id, ciphertext: encSecret.secretCommentCiphertext,
env: encSecret.environment, iv: encSecret.secretCommentIV,
key: secretKey, tag: encSecret.secretCommentTag,
value: secretValue, key
tags: encSecret.tags, });
comment: secretComment,
createdAt: encSecret.createdAt,
updatedAt: encSecret.updatedAt
};
if (encSecret.type === "personal") { const decryptedSecret = {
personalSecrets[`${decryptedSecret.key}-${decryptedSecret.env}`] = { _id: encSecret._id,
id: encSecret._id, env: encSecret.environment,
value: secretValue key: secretKey,
value: secretValue,
tags: encSecret.tags,
comment: secretComment,
createdAt: encSecret.createdAt,
updatedAt: encSecret.updatedAt
}; };
} else {
if (!duplicateSecretKey?.[`${decryptedSecret.key}-${decryptedSecret.env}`]) { if (encSecret.type === "personal") {
sharedSecrets.push(decryptedSecret); personalSecrets[`${decryptedSecret.key}-${decryptedSecret.env}`] = {
id: encSecret._id,
value: secretValue
};
} else {
if (!duplicateSecretKey?.[`${decryptedSecret.key}-${decryptedSecret.env}`]) {
sharedSecrets.push(decryptedSecret);
}
duplicateSecretKey[`${decryptedSecret.key}-${decryptedSecret.env}`] = true;
} }
duplicateSecretKey[`${decryptedSecret.key}-${decryptedSecret.env}`] = true; });
} sharedSecrets.forEach((val) => {
}); const dupKey = `${val.key}-${val.env}`;
sharedSecrets.forEach((val) => { if (personalSecrets?.[dupKey]) {
const dupKey = `${val.key}-${val.env}`; val.idOverride = personalSecrets[dupKey].id;
if (personalSecrets?.[dupKey]) { val.valueOverride = personalSecrets[dupKey].value;
val.idOverride = personalSecrets[dupKey].id; val.overrideAction = "modified";
val.valueOverride = personalSecrets[dupKey].value; }
val.overrideAction = "modified"; });
} return { secrets: sharedSecrets };
}); },
return { secrets: sharedSecrets }; [decryptFileKey]
}, [decryptFileKey]) )
}); });
export const useGetProjectSecretsByKey = ({ export const useGetProjectSecretsByKey = ({
@@ -167,82 +170,85 @@ export const useGetProjectSecretsByKey = ({
// right now secretpath is passed as folderid as only this is used in overview // right now secretpath is passed as folderid as only this is used in overview
queryKey: secretKeys.getProjectSecret(workspaceId, env, secretPath), queryKey: secretKeys.getProjectSecret(workspaceId, env, secretPath),
queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId, secretPath), queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId, secretPath),
select: useCallback((data: EncryptedSecret[]) => { select: useCallback(
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; (data: EncryptedSecret[]) => {
const latestKey = decryptFileKey; const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
const key = decryptAssymmetric({ const latestKey = decryptFileKey;
ciphertext: latestKey.encryptedKey, const key = decryptAssymmetric({
nonce: latestKey.nonce, ciphertext: latestKey.encryptedKey,
publicKey: latestKey.sender.publicKey, nonce: latestKey.nonce,
privateKey: PRIVATE_KEY publicKey: latestKey.sender.publicKey,
}); privateKey: PRIVATE_KEY
const sharedSecrets: Record<string, DecryptedSecret[]> = {};
const personalSecrets: Record<string, { id: string; value: string }> = {};
// this used for add-only mode in dashboard
// type won't be there thus only one key is shown
const duplicateSecretKey: Record<string, boolean> = {};
const uniqSecKeys: Record<string, boolean> = {};
data.forEach((encSecret: EncryptedSecret) => {
const secretKey = decryptSymmetric({
ciphertext: encSecret.secretKeyCiphertext,
iv: encSecret.secretKeyIV,
tag: encSecret.secretKeyTag,
key
});
if (!uniqSecKeys?.[secretKey]) uniqSecKeys[secretKey] = true;
const secretValue = decryptSymmetric({
ciphertext: encSecret.secretValueCiphertext,
iv: encSecret.secretValueIV,
tag: encSecret.secretValueTag,
key
}); });
const secretComment = decryptSymmetric({ const sharedSecrets: Record<string, DecryptedSecret[]> = {};
ciphertext: encSecret.secretCommentCiphertext, const personalSecrets: Record<string, { id: string; value: string }> = {};
iv: encSecret.secretCommentIV, // this used for add-only mode in dashboard
tag: encSecret.secretCommentTag, // type won't be there thus only one key is shown
key const duplicateSecretKey: Record<string, boolean> = {};
}); const uniqSecKeys: Record<string, boolean> = {};
data.forEach((encSecret: EncryptedSecret) => {
const secretKey = decryptSymmetric({
ciphertext: encSecret.secretKeyCiphertext,
iv: encSecret.secretKeyIV,
tag: encSecret.secretKeyTag,
key
});
if (!uniqSecKeys?.[secretKey]) uniqSecKeys[secretKey] = true;
const decryptedSecret = { const secretValue = decryptSymmetric({
_id: encSecret._id, ciphertext: encSecret.secretValueCiphertext,
env: encSecret.environment, iv: encSecret.secretValueIV,
key: secretKey, tag: encSecret.secretValueTag,
value: secretValue, key
tags: encSecret.tags, });
comment: secretComment,
createdAt: encSecret.createdAt,
updatedAt: encSecret.updatedAt
};
if (encSecret.type === "personal") { const secretComment = decryptSymmetric({
personalSecrets[`${decryptedSecret.key}-${decryptedSecret.env}`] = { ciphertext: encSecret.secretCommentCiphertext,
id: encSecret._id, iv: encSecret.secretCommentIV,
value: secretValue tag: encSecret.secretCommentTag,
key
});
const decryptedSecret = {
_id: encSecret._id,
env: encSecret.environment,
key: secretKey,
value: secretValue,
tags: encSecret.tags,
comment: secretComment,
createdAt: encSecret.createdAt,
updatedAt: encSecret.updatedAt
}; };
} else {
if (!duplicateSecretKey?.[`${decryptedSecret.key}-${decryptedSecret.env}`]) { if (encSecret.type === "personal") {
if (!sharedSecrets?.[secretKey]) sharedSecrets[secretKey] = []; personalSecrets[`${decryptedSecret.key}-${decryptedSecret.env}`] = {
sharedSecrets[secretKey].push(decryptedSecret); id: encSecret._id,
} value: secretValue
duplicateSecretKey[`${decryptedSecret.key}-${decryptedSecret.env}`] = true; };
} } else {
}); if (!duplicateSecretKey?.[`${decryptedSecret.key}-${decryptedSecret.env}`]) {
Object.keys(sharedSecrets).forEach((secName) => { if (!sharedSecrets?.[secretKey]) sharedSecrets[secretKey] = [];
sharedSecrets[secName].forEach((val) => { sharedSecrets[secretKey].push(decryptedSecret);
const dupKey = `${val.key}-${val.env}`; }
if (personalSecrets?.[dupKey]) { duplicateSecretKey[`${decryptedSecret.key}-${decryptedSecret.env}`] = true;
val.idOverride = personalSecrets[dupKey].id;
val.valueOverride = personalSecrets[dupKey].value;
val.overrideAction = "modified";
} }
}); });
}); Object.keys(sharedSecrets).forEach((secName) => {
sharedSecrets[secName].forEach((val) => {
const dupKey = `${val.key}-${val.env}`;
if (personalSecrets?.[dupKey]) {
val.idOverride = personalSecrets[dupKey].id;
val.valueOverride = personalSecrets[dupKey].value;
val.overrideAction = "modified";
}
});
});
return { secrets: sharedSecrets, uniqueSecCount: Object.keys(uniqSecKeys).length }; return { secrets: sharedSecrets, uniqueSecCount: Object.keys(uniqSecKeys).length };
}, [decryptFileKey]) },
[decryptFileKey]
)
}); });
const fetchEncryptedSecretVersion = async (secretId: string, offset: number, limit: number) => { const fetchEncryptedSecretVersion = async (secretId: string, offset: number, limit: number) => {
@@ -263,29 +269,32 @@ export const useGetSecretVersion = (dto: GetSecretVersionsDTO) =>
enabled: Boolean(dto.secretId && dto.decryptFileKey), enabled: Boolean(dto.secretId && dto.decryptFileKey),
queryKey: secretKeys.getSecretVersion(dto.secretId), queryKey: secretKeys.getSecretVersion(dto.secretId),
queryFn: () => fetchEncryptedSecretVersion(dto.secretId, dto.offset, dto.limit), queryFn: () => fetchEncryptedSecretVersion(dto.secretId, dto.offset, dto.limit),
select: useCallback((data: EncryptedSecretVersion[]) => { select: useCallback(
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; (data: EncryptedSecretVersion[]) => {
const latestKey = dto.decryptFileKey; const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
const key = decryptAssymmetric({ const latestKey = dto.decryptFileKey;
ciphertext: latestKey.encryptedKey, const key = decryptAssymmetric({
nonce: latestKey.nonce, ciphertext: latestKey.encryptedKey,
publicKey: latestKey.sender.publicKey, nonce: latestKey.nonce,
privateKey: PRIVATE_KEY publicKey: latestKey.sender.publicKey,
}); privateKey: PRIVATE_KEY
});
return data return data
.map((el) => ({ .map((el) => ({
createdAt: el.createdAt, createdAt: el.createdAt,
id: el._id, id: el._id,
value: decryptSymmetric({ value: decryptSymmetric({
ciphertext: el.secretValueCiphertext, ciphertext: el.secretValueCiphertext,
iv: el.secretValueIV, iv: el.secretValueIV,
tag: el.secretValueTag, tag: el.secretValueTag,
key key
}) })
})) }))
.sort((a, b) => b.createdAt.localeCompare(a.createdAt)); .sort((a, b) => b.createdAt.localeCompare(a.createdAt));
}, []) },
[dto.decryptFileKey]
)
}); });
export const useBatchSecretsOp = () => { export const useBatchSecretsOp = () => {
@@ -193,8 +193,8 @@ export const SecretDetailDrawer = ({
</div> </div>
</div> </div>
<div className="ml-1.5 flex items-center space-x-2 border-l border-bunker-300 pl-4"> <div className="ml-1.5 flex items-center space-x-2 border-l border-bunker-300 pl-4">
<div className="rounded-sm bg-primary-500/30 px-1">Value:</div> <div className="self-start rounded-sm bg-primary-500/30 px-1">Value:</div>
<div className="font-mono">{value}</div> <div className="break-all font-mono">{value}</div>
</div> </div>
</div> </div>
))} ))}