Files
zpan/server/platform/libsql.ts
T
Jasper VanandClaude Opus 4.8 e6e67c5fe4 feat(licensing): harden cloud pairing — env keys, clear errors, confirm handshake (#424)
Three related robustness fixes for the cloud pairing flow:

1. Trusted license public keys are env-configurable (ZPAN_LICENSE_PUBLIC_KEYS)
   instead of hardcoding dev keys in source — a leaked dev key is rotated via
   config and never baked into production builds. Registered in all platform
   factories.
2. Certificate verification surfaces a specific rejection reason
   (signature/issuer/instance/expired/host), and the pairing modal distinguishes
   a cert-verification failure from a genuine timeout instead of showing both as
   "expired". On failure the poll handler rolls back the orphaned cloud binding.
3. After verifying + storing the certificate, the instance confirms the binding
   to the cloud (zpan-cloud-sdk 2.1.0's POST /licenses/:id/confirm) so the cloud
   pairing page resolves to success only once the instance actually accepted it.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:43:46 -04:00

39 lines
1.1 KiB
TypeScript

import { createClient } from '@libsql/client'
import { drizzle } from 'drizzle-orm/libsql'
import { migrate } from 'drizzle-orm/libsql/migrator'
import * as authSchema from '../db/auth-schema'
import * as schema from '../db/schema'
import { registerEnvPublicKeys } from '../licensing/public-keys'
import type { Platform } from './interface'
interface LibsqlEnv {
TURSO_DATABASE_URL: string
TURSO_AUTH_TOKEN?: string
}
export async function createLibsqlPlatform(env: LibsqlEnv): Promise<Platform> {
const migrationsFolder = process.env.MIGRATIONS_DIR || './migrations'
const envRecord: Record<string, string | undefined> = { ...env }
const client = createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
})
const db = drizzle(client, { schema: { ...schema, ...authSchema } })
await migrate(db, { migrationsFolder })
registerEnvPublicKeys(envRecord.ZPAN_LICENSE_PUBLIC_KEYS ?? process.env.ZPAN_LICENSE_PUBLIC_KEYS)
return {
db,
getEnv(key: string) {
return envRecord[key] ?? process.env[key]
},
getBinding<T = unknown>(_key: string): T | undefined {
return undefined
},
}
}