Merge branch 'dev-1.8.0' into feature-engineering-improvements

This commit is contained in:
Karmaa
2025-10-07 20:05:51 -05:00
committed by GitHub
139 changed files with 3076 additions and 269 deletions

View File

@@ -17,13 +17,9 @@ class FieldCrypto {
private static readonly ENCRYPTED_FIELDS = {
users: new Set([
"password_hash",
"passwordHash",
"client_secret",
"clientSecret",
"totp_secret",
"totpSecret",
"totp_backup_codes",
"totpBackupCodes",
"oidc_identifier",
"oidcIdentifier",
]),
@@ -31,12 +27,9 @@ class FieldCrypto {
ssh_credentials: new Set([
"password",
"private_key",
"privateKey",
"key_password",
"keyPassword",
"key",
"public_key",
"publicKey",
]),
};

View File

@@ -6,10 +6,20 @@ export class LazyFieldEncryption {
key_password: "keyPassword",
private_key: "privateKey",
public_key: "publicKey",
// Reverse mappings for Drizzle ORM (camelCase -> snake_case)
password_hash: "passwordHash",
client_secret: "clientSecret",
totp_secret: "totpSecret",
totp_backup_codes: "totpBackupCodes",
oidc_identifier: "oidcIdentifier",
keyPassword: "key_password",
privateKey: "private_key",
publicKey: "public_key",
passwordHash: "password_hash",
clientSecret: "client_secret",
totpSecret: "totp_secret",
totpBackupCodes: "totp_backup_codes",
oidcIdentifier: "oidc_identifier",
};
static isPlaintextField(value: string): boolean {

View File

@@ -70,7 +70,36 @@ class UserCrypto {
}
async setupOIDCUserEncryption(userId: string): Promise<void> {
const DEK = crypto.randomBytes(UserCrypto.DEK_LENGTH);
const existingEncryptedDEK = await this.getEncryptedDEK(userId);
let DEK: Buffer;
if (existingEncryptedDEK) {
const systemKey = this.deriveOIDCSystemKey(userId);
DEK = this.decryptDEK(existingEncryptedDEK, systemKey);
systemKey.fill(0);
} else {
DEK = crypto.randomBytes(UserCrypto.DEK_LENGTH);
const systemKey = this.deriveOIDCSystemKey(userId);
try {
const encryptedDEK = this.encryptDEK(DEK, systemKey);
await this.storeEncryptedDEK(userId, encryptedDEK);
const storedEncryptedDEK = await this.getEncryptedDEK(userId);
if (
storedEncryptedDEK &&
storedEncryptedDEK.data !== encryptedDEK.data
) {
DEK.fill(0);
DEK = this.decryptDEK(storedEncryptedDEK, systemKey);
} else if (!storedEncryptedDEK) {
throw new Error("Failed to store and retrieve user encryption key.");
}
} finally {
systemKey.fill(0);
}
}
const now = Date.now();
this.userSessions.set(userId, {
@@ -134,20 +163,14 @@ class UserCrypto {
async authenticateOIDCUser(userId: string): Promise<boolean> {
try {
const kekSalt = await this.getKEKSalt(userId);
if (!kekSalt) {
const encryptedDEK = await this.getEncryptedDEK(userId);
if (!encryptedDEK) {
await this.setupOIDCUserEncryption(userId);
return true;
}
const systemKey = this.deriveOIDCSystemKey(userId);
const encryptedDEK = await this.getEncryptedDEK(userId);
if (!encryptedDEK) {
systemKey.fill(0);
await this.setupOIDCUserEncryption(userId);
return true;
}
const DEK = this.decryptDEK(encryptedDEK, systemKey);
systemKey.fill(0);