feat(door): P2 connections + SSRF-safe executor + native adapter + audit
Migration 035 adds door_connections (per-space controller integration: secret_ref -> AES-256-GCM secrets vault, never a plaintext password; pinned_host SSRF pin; native_heatsync|generic_http adapter; allow_member_self_entry opt-in for phase 3) and door_access_log (append-only, secrets redacted, service-client-only writes; immutable). RLS additive/default-deny: connections CRUD = door.manage; log SELECT = door.manage/operate. Safety core is pure and heavily unit-tested (door-logic, suite 409): validateDoorTarget (request host must equal the pinned host; metadata/link-local always blocked; http(s) only), the firmware-verified HeatSync encoders with fixed-width zero-padding (slot 3 / perm 3 / tag 8 / 4-char password), generic template substitution, and redactDoorSecrets. lib/door/executor.ts is the single hardened egress: re-validates the pin, refuses redirects, caps time and body, redacts before any audit write. The door password is read from the secrets vault and decrypted server-side only, never returned or logged. /door/manage (door.manage) configures connections, picks a vault secret, and runs a safe status-only test. Sidebar Admin link added; "Learn" moved before "People" per request. Docs updated.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
|
||||
// Server-component guard for the /door/manage surface. Mirrors the other
|
||||
// module guards: resolve the member, check door.manage via the same RPC the
|
||||
// RLS uses, redirect non-managers before any data is fetched. The RLS
|
||||
// independently enforces this.
|
||||
export async function requireDoorManagerPage() {
|
||||
const supabase = await createClient()
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
if (!user) redirect('/login')
|
||||
|
||||
const { data: member } = await supabase
|
||||
.from('space_members')
|
||||
.select('id, space_id, role, user_id, display_name')
|
||||
.eq('user_id', user.id)
|
||||
.in('status', ['current', 'unverified', 'late'])
|
||||
.single()
|
||||
if (!member) redirect('/login')
|
||||
|
||||
const { data: allowed } = await supabase.rpc('user_has_permission', {
|
||||
uid: user.id,
|
||||
sid: member.space_id,
|
||||
perm: 'door.manage',
|
||||
})
|
||||
if (!allowed) redirect('/dashboard')
|
||||
|
||||
return { supabase, member }
|
||||
}
|
||||
Reference in New Issue
Block a user