From 3011de6abb70c9cfd9ec27f93aac262c0d07a481 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Fri, 22 May 2026 17:16:39 -0500 Subject: [PATCH] fix: guacd hosts not migarting password --- src/backend/database/db/index.ts | 23 +++++++++++----------- src/backend/utils/lazy-field-encryption.ts | 21 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/backend/database/db/index.ts b/src/backend/database/db/index.ts index 862d8a1f..19bb0ea4 100644 --- a/src/backend/database/db/index.ts +++ b/src/backend/database/db/index.ts @@ -1092,9 +1092,9 @@ const migrateSchema = () => { } } - // One-time migration: copy old generic credentials into protocol-specific fields - // for hosts that were created before the multi-protocol schema was introduced. - const credentialBackfills = [ + // Copy unencrypted username/domain into protocol-specific columns for old guac hosts. + // Passwords are handled via the legacy field name fallback in lazy-field-encryption.ts. + const usernameDomainBackfills = [ { protocol: "rdp", sql: "UPDATE ssh_data SET rdp_user = username, rdp_password = password, rdp_domain = domain WHERE connection_type = 'rdp' AND rdp_user IS NULL AND rdp_password IS NULL", @@ -1108,21 +1108,20 @@ const migrateSchema = () => { sql: "UPDATE ssh_data SET telnet_user = username, telnet_password = password WHERE connection_type = 'telnet' AND telnet_user IS NULL AND telnet_password IS NULL", }, ]; - - for (const backfill of credentialBackfills) { + for (const backfill of usernameDomainBackfills) { try { const result = sqlite.prepare(backfill.sql).run(); if (result.changes > 0) { databaseLogger.info( - `Backfilled credentials for ${result.changes} ${backfill.protocol} host(s)`, - { operation: "credential_backfill" }, + `Backfilled ${result.changes} ${backfill.protocol} host credential(s)`, + { operation: "guac_credential_backfill" }, ); } - } catch (backfillError) { - databaseLogger.warn( - `Failed to backfill ${backfill.protocol} credentials`, - { operation: "credential_backfill", error: backfillError }, - ); + } catch (e) { + databaseLogger.warn(`Failed to backfill ${backfill.protocol} host credentials`, { + operation: "guac_credential_backfill", + error: e, + }); } } diff --git a/src/backend/utils/lazy-field-encryption.ts b/src/backend/utils/lazy-field-encryption.ts index 3103ad79..e831ea9f 100644 --- a/src/backend/utils/lazy-field-encryption.ts +++ b/src/backend/utils/lazy-field-encryption.ts @@ -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",