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.
This commit is contained in:
Moheeb Zara
2026-05-19 02:10:20 -07:00
parent b90debbd37
commit c2ba9586fa
+14 -9
View File
@@ -239,7 +239,7 @@ export async function testDoorConnection(input: unknown) {
const { data: conn } = await supabase const { data: conn } = await supabase
.from('door_connections') .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('id', v.data.connectionId)
.eq('space_id', member.space_id) .eq('space_id', member.space_id)
.maybeSingle() .maybeSingle()
@@ -260,15 +260,17 @@ export async function testDoorConnection(input: unknown) {
query = applyTemplate(tmpl, { pw: password ?? '' }) query = applyTemplate(tmpl, { pw: password ?? '' })
} }
const authParam = (conn.auth_param as string | null) ?? null
const result = await callDoor({ const result = await callDoor({
url: (conn.base_url as string) + query, url: (conn.base_url as string) + query,
pinnedHost: conn.pinned_host as string, pinnedHost: conn.pinned_host as string,
password, password,
authParam,
}) })
const detail = result.ok const detail = result.ok
? redactDoorSecrets(`status ${result.status}: ${result.snippet}`.slice(0, 1000), password) ? redactDoorSecrets(`status ${result.status}: ${result.snippet}`.slice(0, 1000), password, authParam)
: redactDoorSecrets(`failed: ${result.reason}`.slice(0, 1000), password) : redactDoorSecrets(`failed: ${result.reason}`.slice(0, 1000), password, authParam)
await admin.from('door_access_log').insert({ await admin.from('door_access_log').insert({
space_id: member.space_id, space_id: member.space_id,
@@ -344,6 +346,7 @@ type ConnRow = {
adapter: string adapter: string
base_url: string base_url: string
pinned_host: string pinned_host: string
auth_param: string | null
secret_ref: string | null secret_ref: string | null
verbs: Record<string, string> | null verbs: Record<string, string> | null
is_enabled: boolean is_enabled: boolean
@@ -356,7 +359,7 @@ async function loadEnabledConnection(
): Promise<{ ok: true; conn: ConnRow } | { ok: false; error: string }> { ): Promise<{ ok: true; conn: ConnRow } | { ok: false; error: string }> {
const { data } = await admin const { data } = await admin
.from('door_connections') .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('id', connectionId)
.eq('space_id', spaceId) .eq('space_id', spaceId)
.maybeSingle() .maybeSingle()
@@ -376,6 +379,7 @@ async function auditDoor(
success: boolean success: boolean
detail: string detail: string
password?: string | null password?: string | null
authParam?: string | null
}, },
) { ) {
await admin.from('door_access_log').insert({ await admin.from('door_access_log').insert({
@@ -385,7 +389,7 @@ async function auditDoor(
target_member_id: row.targetMemberId ?? null, target_member_id: row.targetMemberId ?? null,
action: row.action, action: row.action,
success: row.success, 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) { if (!result.ok) {
// Roll back the reservation so slots do not leak on a failed write. // 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 ?? '' }) 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) { if (!result.ok) {
// Keep the slot row so the app's map stays in sync with the device's // 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 ?? '' }) 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, { await auditDoor(admin, {
spaceId: member.space_id, connectionId, actorMemberId: member.id, spaceId: member.space_id, connectionId, actorMemberId: member.id,
@@ -748,7 +752,7 @@ export async function selfEntry(input: unknown) {
const { data: conn } = await admin const { data: conn } = await admin
.from('door_connections') .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('id', v.data.connectionId)
.eq('space_id', member.space_id) .eq('space_id', member.space_id)
.maybeSingle() .maybeSingle()
@@ -789,6 +793,7 @@ export async function selfEntry(input: unknown) {
url: (conn.base_url as string) + query, url: (conn.base_url as string) + query,
pinnedHost: conn.pinned_host as string, pinnedHost: conn.pinned_host as string,
password, password,
authParam: (conn.auth_param as string | null) ?? null,
}) })
await auditDoor(admin, { await auditDoor(admin, {