mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 13:27:46 +00:00
feat: added auto bot creator when bot is missing by taking the user old server encrypted private key
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TProjectBots } from "@app/db/schemas";
|
import { TableName, TProjectBots, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -41,5 +41,43 @@ export const projectBotDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...projectBotOrm, findOne, findProjectByBotId };
|
const findProjectUserWorkspaceKey = async (projectId: string) => {
|
||||||
|
try {
|
||||||
|
const doc = await db
|
||||||
|
.replicaNode()(TableName.ProjectMembership)
|
||||||
|
.where(`${TableName.ProjectMembership}.projectId` as "projectId", projectId)
|
||||||
|
.where(`${TableName.Users}.isGhost` as "isGhost", false)
|
||||||
|
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
||||||
|
.join(TableName.ProjectKeys, `${TableName.ProjectMembership}.userId`, `${TableName.ProjectKeys}.receiverId`)
|
||||||
|
.join<TUserEncryptionKeys>(
|
||||||
|
TableName.UserEncryptionKey,
|
||||||
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
|
`${TableName.Users}.id`
|
||||||
|
)
|
||||||
|
.join<TUserEncryptionKeys>(
|
||||||
|
db(TableName.UserEncryptionKey).as("senderUserEncryption"),
|
||||||
|
`${TableName.ProjectKeys}.senderId`,
|
||||||
|
`senderUserEncryption.userId`
|
||||||
|
)
|
||||||
|
.whereNotNull(`${TableName.UserEncryptionKey}.serverEncryptedPrivateKey`)
|
||||||
|
.whereNotNull(`${TableName.UserEncryptionKey}.serverEncryptedPrivateKeyIV`)
|
||||||
|
.whereNotNull(`${TableName.UserEncryptionKey}.serverEncryptedPrivateKeyTag`)
|
||||||
|
.select(
|
||||||
|
db.ref("serverEncryptedPrivateKey").withSchema(TableName.UserEncryptionKey),
|
||||||
|
db.ref("serverEncryptedPrivateKeyTag").withSchema(TableName.UserEncryptionKey),
|
||||||
|
db.ref("serverEncryptedPrivateKeyIV").withSchema(TableName.UserEncryptionKey),
|
||||||
|
db.ref("serverEncryptedPrivateKeyEncoding").withSchema(TableName.UserEncryptionKey),
|
||||||
|
db.ref("encryptedKey").withSchema(TableName.ProjectKeys).as("projectEncryptedKey"),
|
||||||
|
db.ref("nonce").withSchema(TableName.ProjectKeys).as("projectKeyNonce"),
|
||||||
|
db.ref("publicKey").withSchema("senderUserEncryption").as("senderPublicKey"),
|
||||||
|
db.ref("id").withSchema(TableName.Users).as("userId")
|
||||||
|
)
|
||||||
|
.first();
|
||||||
|
return doc;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Find all project members" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...projectBotOrm, findOne, findProjectByBotId, findProjectUserWorkspaceKey };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
import { SecretKeyEncoding } from "@app/db/schemas";
|
||||||
import { decryptAsymmetric, infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
|
import {
|
||||||
|
decryptAsymmetric,
|
||||||
|
encryptAsymmetric,
|
||||||
|
generateAsymmetricKeyPair,
|
||||||
|
infisicalSymmetricDecrypt,
|
||||||
|
infisicalSymmetricEncypt
|
||||||
|
} from "@app/lib/crypto/encryption";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
|
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
|
||||||
|
|
||||||
@@ -27,11 +33,61 @@ export const getBotKeyFnFactory = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bot = await projectBotDAL.findOne({ projectId: project.id });
|
const bot = await projectBotDAL.findOne({ projectId: project.id });
|
||||||
|
if (!bot || !bot.isActive || !bot.encryptedProjectKey || !bot.encryptedProjectKeyNonce) {
|
||||||
|
// trying to set bot automatically
|
||||||
|
const projectV1Keys = await projectBotDAL.findProjectUserWorkspaceKey(projectId);
|
||||||
|
if (!projectV1Keys)
|
||||||
|
throw new BadRequestError({ message: "Bot not found. [no-private-key]. Please ask admin user to login" });
|
||||||
|
|
||||||
if (!bot) throw new BadRequestError({ message: "Failed to find bot key", name: "bot_not_found_error" });
|
let userPrivateKey = "";
|
||||||
if (!bot.isActive) throw new BadRequestError({ message: "Bot is not active", name: "bot_not_found_error" });
|
if (
|
||||||
if (!bot.encryptedProjectKeyNonce || !bot.encryptedProjectKey)
|
projectV1Keys?.serverEncryptedPrivateKey &&
|
||||||
throw new BadRequestError({ message: "Encryption key missing", name: "bot_not_found_error" });
|
projectV1Keys.serverEncryptedPrivateKeyIV &&
|
||||||
|
projectV1Keys.serverEncryptedPrivateKeyTag &&
|
||||||
|
projectV1Keys.serverEncryptedPrivateKeyEncoding
|
||||||
|
) {
|
||||||
|
userPrivateKey = infisicalSymmetricDecrypt({
|
||||||
|
iv: projectV1Keys.serverEncryptedPrivateKeyIV,
|
||||||
|
tag: projectV1Keys.serverEncryptedPrivateKeyTag,
|
||||||
|
ciphertext: projectV1Keys.serverEncryptedPrivateKey,
|
||||||
|
keyEncoding: projectV1Keys.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const workspaceKey = decryptAsymmetric({
|
||||||
|
ciphertext: projectV1Keys.projectEncryptedKey,
|
||||||
|
nonce: projectV1Keys.projectKeyNonce,
|
||||||
|
publicKey: projectV1Keys.senderPublicKey,
|
||||||
|
privateKey: userPrivateKey
|
||||||
|
});
|
||||||
|
const botKey = generateAsymmetricKeyPair();
|
||||||
|
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(botKey.privateKey);
|
||||||
|
const encryptedWorkspaceKey = encryptAsymmetric(workspaceKey, botKey.publicKey, userPrivateKey);
|
||||||
|
|
||||||
|
if (!bot) {
|
||||||
|
await projectBotDAL.create({
|
||||||
|
name: "Infisical Bot (Ghost)",
|
||||||
|
projectId,
|
||||||
|
tag,
|
||||||
|
iv,
|
||||||
|
encryptedPrivateKey: ciphertext,
|
||||||
|
isActive: true,
|
||||||
|
publicKey: botKey.publicKey,
|
||||||
|
algorithm,
|
||||||
|
keyEncoding: encoding,
|
||||||
|
encryptedProjectKey: encryptedWorkspaceKey.ciphertext,
|
||||||
|
encryptedProjectKeyNonce: encryptedWorkspaceKey.nonce,
|
||||||
|
senderId: projectV1Keys.userId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await projectBotDAL.updateById(bot.id, {
|
||||||
|
isActive: true,
|
||||||
|
encryptedProjectKey: encryptedWorkspaceKey.ciphertext,
|
||||||
|
encryptedProjectKeyNonce: encryptedWorkspaceKey.nonce,
|
||||||
|
senderId: projectV1Keys.userId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { botKey: workspaceKey, project, shouldUseSecretV2Bridge: false };
|
||||||
|
}
|
||||||
|
|
||||||
const botPrivateKey = getBotPrivateKey({ bot });
|
const botPrivateKey = getBotPrivateKey({ bot });
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export const projectBotServiceFactory = ({
|
|||||||
|
|
||||||
const project = await projectDAL.findById(projectId, tx);
|
const project = await projectDAL.findById(projectId, tx);
|
||||||
|
|
||||||
if (project.version === ProjectVersion.V2) {
|
if (project.version === ProjectVersion.V2 || project.version === ProjectVersion.V3) {
|
||||||
throw new BadRequestError({ message: "Failed to create bot, project is upgraded." });
|
throw new BadRequestError({ message: "Failed to create bot, project is upgraded." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user