This commit is contained in:
LukeGus
2026-05-28 22:29:20 -05:00
parent 33dcde0827
commit 5777351145
238 changed files with 62303 additions and 98955 deletions
@@ -1,5 +1,5 @@
import { db } from "../database/db/index.js";
import { sshCredentials } from "../database/db/schema.js";
import { sshCredentials, sharedCredentials } from "../database/db/schema.js";
import { eq, and, or, isNull } from "drizzle-orm";
import { DataCrypto } from "./data-crypto.js";
import { SystemCrypto } from "./system-crypto.js";
@@ -64,7 +64,7 @@ export class CredentialSystemEncryptionMigration {
cred.keyPassword,
userDEK,
cred.id.toString(),
"key_password",
"keyPassword",
)
: null;
@@ -105,6 +105,11 @@ export class CredentialSystemEncryptionMigration {
})
.where(eq(sshCredentials.id, cred.id));
await db
.update(sharedCredentials)
.set({ needsReEncryption: true })
.where(eq(sharedCredentials.originalCredentialId, cred.id));
migrated++;
} catch (error) {
databaseLogger.warn(
@@ -103,6 +103,27 @@ export class LazyFieldEncryption {
}
}
// Guac hosts migrated from single-protocol: rdpPassword/vncPassword/telnetPassword
// columns were populated by copying the encrypted `password` blob. Try decrypting
// under the original field name before giving up.
if (
fieldName === "rdpPassword" ||
fieldName === "vncPassword" ||
fieldName === "telnetPassword"
) {
try {
const decrypted = FieldCrypto.decryptField(
fieldValue,
userKEK,
recordId,
"password",
);
return decrypted;
} catch {
// not encrypted as "password" either
}
}
const sensitiveFields = [
"totpSecret",
"totpBackupCodes",
+24 -3
View File
@@ -1,7 +1,9 @@
import crypto from "crypto";
import type { ConnectConfig, CipherAlgorithm } from "ssh2";
// Maps SSH cipher names to their OpenSSL equivalents (as used by ssh2 internally)
const availableCiphers = new Set(crypto.getCiphers());
// Maps SSH cipher names to their OpenSSL equivalents
const SSH_CIPHER_SSL_NAME: Partial<Record<CipherAlgorithm, string>> = {
"chacha20-poly1305@openssh.com": "chacha20",
"aes256-gcm@openssh.com": "aes-256-gcm",
@@ -15,12 +17,31 @@ const SSH_CIPHER_SSL_NAME: Partial<Record<CipherAlgorithm, string>> = {
"3des-cbc": "des-ede3-cbc",
};
const availableCiphers = new Set(crypto.getCiphers());
// Check if ssh2's native crypto binding is available (needed for chacha20-poly1305)
let ssh2BindingAvailable = false;
try {
require("ssh2/lib/protocol/crypto/build/Release/sshcrypto.node");
ssh2BindingAvailable = true;
} catch {
try {
// ESM fallback: check if chacha20 works via OpenSSL createCipheriv
crypto.createCipheriv("chacha20", Buffer.alloc(32), Buffer.alloc(16));
ssh2BindingAvailable = true;
} catch {
ssh2BindingAvailable = false;
}
}
function filterCiphers(list: CipherAlgorithm[]): CipherAlgorithm[] {
return list.filter((name) => {
const sslName = SSH_CIPHER_SSL_NAME[name];
return !sslName || availableCiphers.has(sslName);
if (!sslName) return true;
if (!availableCiphers.has(sslName)) return false;
// chacha20-poly1305 requires either native binding or working OpenSSL chacha20
if (name === "chacha20-poly1305@openssh.com" && !ssh2BindingAvailable) {
return false;
}
return true;
});
}
+21
View File
@@ -103,6 +103,27 @@ function detectKeyTypeFromContent(keyContent: string): string {
function detectPublicKeyTypeFromContent(publicKeyContent: string): string {
const content = publicKeyContent.trim();
// OpenSSH certificate types (must be checked before plain key types)
if (content.startsWith("ssh-ed25519-cert-v01@openssh.com ")) {
return "ssh-ed25519-cert-v01@openssh.com";
}
if (content.startsWith("ssh-rsa-cert-v01@openssh.com ")) {
return "ssh-rsa-cert-v01@openssh.com";
}
if (content.startsWith("ecdsa-sha2-nistp256-cert-v01@openssh.com ")) {
return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
}
if (content.startsWith("ecdsa-sha2-nistp384-cert-v01@openssh.com ")) {
return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
}
if (content.startsWith("ecdsa-sha2-nistp521-cert-v01@openssh.com ")) {
return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
}
if (content.startsWith("sk-ssh-ed25519-cert-v01@openssh.com ")) {
return "sk-ssh-ed25519-cert-v01@openssh.com";
}
// Plain public keys
if (content.startsWith("ssh-rsa ")) {
return "ssh-rsa";
}