diff --git a/src/backend/ssh/docker.ts b/src/backend/ssh/docker.ts index c995a824..d8b6fc16 100644 --- a/src/backend/ssh/docker.ts +++ b/src/backend/ssh/docker.ts @@ -142,7 +142,7 @@ async function resolveJumpHost( getDb() .select() .from(hosts) - .where(and(eq(hosts.id, hostId), eq(hosts.userId, userId))), + .where(eq(hosts.id, hostId)), "ssh_data", userId, ); @@ -152,8 +152,35 @@ async function resolveJumpHost( } const host = hostResults[0]; + const ownerId = (host.userId || userId) as string; if (host.credentialId) { + if (userId !== ownerId) { + try { + const { SharedCredentialManager } = + await import("../utils/shared-credential-manager.js"); + const sharedCredManager = SharedCredentialManager.getInstance(); + const sharedCred = + await sharedCredManager.getSharedCredentialForUser(hostId, userId); + if (sharedCred) { + return { + ...host, + password: sharedCred.password, + key: sharedCred.key, + keyPassword: sharedCred.keyPassword, + keyType: sharedCred.keyType, + authType: sharedCred.key + ? "key" + : sharedCred.password + ? "password" + : "none", + } as JumpHostConfig; + } + } catch { + // fall through to owner credential lookup + } + } + const credentials = await SimpleDBOps.select( getDb() .select() @@ -161,11 +188,11 @@ async function resolveJumpHost( .where( and( eq(sshCredentials.id, host.credentialId as number), - eq(sshCredentials.userId, userId), + eq(sshCredentials.userId, ownerId), ), ), "ssh_credentials", - userId, + ownerId, ); if (credentials.length > 0) { diff --git a/src/backend/ssh/file-manager.ts b/src/backend/ssh/file-manager.ts index 4bed2271..404518a0 100644 --- a/src/backend/ssh/file-manager.ts +++ b/src/backend/ssh/file-manager.ts @@ -154,7 +154,7 @@ async function resolveJumpHost( getDb() .select() .from(hosts) - .where(and(eq(hosts.id, hostId), eq(hosts.userId, userId))), + .where(eq(hosts.id, hostId)), "ssh_data", userId, ); @@ -164,8 +164,35 @@ async function resolveJumpHost( } const host = hostResults[0]; + const ownerId = (host.userId || userId) as string; if (host.credentialId) { + if (userId !== ownerId) { + try { + const { SharedCredentialManager } = + await import("../utils/shared-credential-manager.js"); + const sharedCredManager = SharedCredentialManager.getInstance(); + const sharedCred = + await sharedCredManager.getSharedCredentialForUser(hostId, userId); + if (sharedCred) { + return { + ...host, + password: sharedCred.password, + key: sharedCred.key, + keyPassword: sharedCred.keyPassword, + keyType: sharedCred.keyType, + authType: sharedCred.key + ? "key" + : sharedCred.password + ? "password" + : "none", + } as JumpHostConfig; + } + } catch { + // fall through to owner credential lookup + } + } + const credentials = await SimpleDBOps.select( getDb() .select() @@ -173,11 +200,11 @@ async function resolveJumpHost( .where( and( eq(sshCredentials.id, host.credentialId as number), - eq(sshCredentials.userId, userId), + eq(sshCredentials.userId, ownerId), ), ), "ssh_credentials", - userId, + ownerId, ); if (credentials.length > 0) { diff --git a/src/backend/ssh/server-stats.ts b/src/backend/ssh/server-stats.ts index 8700f476..ef7e3538 100644 --- a/src/backend/ssh/server-stats.ts +++ b/src/backend/ssh/server-stats.ts @@ -78,7 +78,7 @@ async function resolveJumpHost( getDb() .select() .from(hosts) - .where(and(eq(hosts.id, hostId), eq(hosts.userId, userId))), + .where(eq(hosts.id, hostId)), "ssh_data", userId, ); @@ -88,8 +88,35 @@ async function resolveJumpHost( } const host = hostResults[0]; + const ownerId = (host.userId || userId) as string; if (host.credentialId) { + if (userId !== ownerId) { + try { + const { SharedCredentialManager } = + await import("../utils/shared-credential-manager.js"); + const sharedCredManager = SharedCredentialManager.getInstance(); + const sharedCred = + await sharedCredManager.getSharedCredentialForUser(hostId, userId); + if (sharedCred) { + return { + ...host, + password: sharedCred.password, + key: sharedCred.key, + keyPassword: sharedCred.keyPassword, + keyType: sharedCred.keyType, + authType: sharedCred.key + ? "key" + : sharedCred.password + ? "password" + : "none", + } as JumpHostConfig; + } + } catch { + // fall through to owner credential lookup + } + } + const credentials = await SimpleDBOps.select( getDb() .select() @@ -97,11 +124,11 @@ async function resolveJumpHost( .where( and( eq(sshCredentials.id, host.credentialId as number), - eq(sshCredentials.userId, userId), + eq(sshCredentials.userId, ownerId), ), ), "ssh_credentials", - userId, + ownerId, ); if (credentials.length > 0) { diff --git a/src/backend/ssh/terminal.ts b/src/backend/ssh/terminal.ts index fb775493..da34dd88 100644 --- a/src/backend/ssh/terminal.ts +++ b/src/backend/ssh/terminal.ts @@ -148,7 +148,7 @@ async function resolveJumpHost( getDb() .select() .from(hosts) - .where(and(eq(hosts.id, hostId), eq(hosts.userId, userId))), + .where(eq(hosts.id, hostId)), "ssh_data", userId, ); @@ -158,8 +158,35 @@ async function resolveJumpHost( } const host = hostResults[0]; + const ownerId = (host.userId || userId) as string; if (host.credentialId) { + if (userId !== ownerId) { + try { + const { SharedCredentialManager } = + await import("../utils/shared-credential-manager.js"); + const sharedCredManager = SharedCredentialManager.getInstance(); + const sharedCred = + await sharedCredManager.getSharedCredentialForUser(hostId, userId); + if (sharedCred) { + return { + ...host, + password: sharedCred.password, + key: sharedCred.key, + keyPassword: sharedCred.keyPassword, + keyType: sharedCred.keyType, + authType: sharedCred.key + ? "key" + : sharedCred.password + ? "password" + : "none", + } as JumpHostConfig; + } + } catch { + // fall through to owner credential lookup + } + } + const credentials = await SimpleDBOps.select( getDb() .select() @@ -167,11 +194,11 @@ async function resolveJumpHost( .where( and( eq(sshCredentials.id, host.credentialId as number), - eq(sshCredentials.userId, userId), + eq(sshCredentials.userId, ownerId), ), ), "ssh_credentials", - userId, + ownerId, ); if (credentials.length > 0) {