From c2ba9586fa6d1764dca28a9de966e48ba28878aa Mon Sep 17 00:00:00 2001 From: Moheeb Zara Date: Tue, 19 May 2026 02:10:20 -0700 Subject: [PATCH] fix(door): thread conn.auth_param into call + audit redaction (E1, completes D10) D10 closed the client-facing leak; this completes the defense-in-depth so a generic-adapter connection's custom auth-param value is also scrubbed from the operator-readable door_access_log / callDoor reason regardless of param name. auth_param added to ConnRow + loadEnabledConnection + the test/selfEntry selects; threaded into every callDoor (which already redacts reason/snippet by it) and auditDoor gained an optional authParam. Native HeatSync (e=) was already covered; this hardens custom generic adapters. 532 tests. --- lib/actions/door.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/actions/door.ts b/lib/actions/door.ts index d558392..f06cbc2 100644 --- a/lib/actions/door.ts +++ b/lib/actions/door.ts @@ -239,7 +239,7 @@ export async function testDoorConnection(input: unknown) { const { data: conn } = await supabase .from('door_connections') - .select('id, space_id, adapter, base_url, pinned_host, secret_ref, verbs, is_enabled') + .select('id, space_id, adapter, base_url, pinned_host, auth_param, secret_ref, verbs, is_enabled') .eq('id', v.data.connectionId) .eq('space_id', member.space_id) .maybeSingle() @@ -260,15 +260,17 @@ export async function testDoorConnection(input: unknown) { query = applyTemplate(tmpl, { pw: password ?? '' }) } + const authParam = (conn.auth_param as string | null) ?? null const result = await callDoor({ url: (conn.base_url as string) + query, pinnedHost: conn.pinned_host as string, password, + authParam, }) const detail = result.ok - ? redactDoorSecrets(`status ${result.status}: ${result.snippet}`.slice(0, 1000), password) - : redactDoorSecrets(`failed: ${result.reason}`.slice(0, 1000), password) + ? redactDoorSecrets(`status ${result.status}: ${result.snippet}`.slice(0, 1000), password, authParam) + : redactDoorSecrets(`failed: ${result.reason}`.slice(0, 1000), password, authParam) await admin.from('door_access_log').insert({ space_id: member.space_id, @@ -344,6 +346,7 @@ type ConnRow = { adapter: string base_url: string pinned_host: string + auth_param: string | null secret_ref: string | null verbs: Record | null is_enabled: boolean @@ -356,7 +359,7 @@ async function loadEnabledConnection( ): Promise<{ ok: true; conn: ConnRow } | { ok: false; error: string }> { const { data } = await admin .from('door_connections') - .select('id, adapter, base_url, pinned_host, secret_ref, verbs, is_enabled') + .select('id, adapter, base_url, pinned_host, auth_param, secret_ref, verbs, is_enabled') .eq('id', connectionId) .eq('space_id', spaceId) .maybeSingle() @@ -376,6 +379,7 @@ async function auditDoor( success: boolean detail: string password?: string | null + authParam?: string | null }, ) { await admin.from('door_access_log').insert({ @@ -385,7 +389,7 @@ async function auditDoor( target_member_id: row.targetMemberId ?? null, action: row.action, success: row.success, - detail: redactDoorSecrets(row.detail.slice(0, 1000), row.password), + detail: redactDoorSecrets(row.detail.slice(0, 1000), row.password, row.authParam), }) } @@ -499,7 +503,7 @@ export async function grantCard(input: unknown) { }) } - const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password }) + const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password, authParam: conn.auth_param }) if (!result.ok) { // Roll back the reservation so slots do not leak on a failed write. @@ -580,7 +584,7 @@ export async function revokeCard(input: unknown) { query = applyTemplate(tmpl, { slot, pw: password ?? '' }) } - const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password }) + const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password, authParam: conn.auth_param }) if (!result.ok) { // Keep the slot row so the app's map stays in sync with the device's @@ -678,7 +682,7 @@ export async function doorControl(input: unknown) { query = applyTemplate(tmpl, { pw: password ?? '' }) } - const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password }) + const result = await callDoor({ url: conn.base_url + query, pinnedHost: conn.pinned_host, password, authParam: conn.auth_param }) await auditDoor(admin, { spaceId: member.space_id, connectionId, actorMemberId: member.id, @@ -748,7 +752,7 @@ export async function selfEntry(input: unknown) { const { data: conn } = await admin .from('door_connections') - .select('id, adapter, base_url, pinned_host, secret_ref, verbs, is_enabled, allow_member_self_entry') + .select('id, adapter, base_url, pinned_host, auth_param, secret_ref, verbs, is_enabled, allow_member_self_entry') .eq('id', v.data.connectionId) .eq('space_id', member.space_id) .maybeSingle() @@ -789,6 +793,7 @@ export async function selfEntry(input: unknown) { url: (conn.base_url as string) + query, pinnedHost: conn.pinned_host as string, password, + authParam: (conn.auth_param as string | null) ?? null, }) await auditDoor(admin, {