clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

fix/175-template-quality-pass
lofi / package / access / access_operations_test.ts
access_operations_test.ts 3.5K
1import { schema as s } from "jazz-tools";2import {3 AccessError,4 createSharingOperations,5 decodeSharingIdentity,6 decodeSharingIdentityDetails,7 encodeSharingIdentity,8 sharedGrantTable,9} from "./mod.ts";10import { assert } from "../runtime/test-assert.ts";1112const app = s.defineApp({13 docs: s.table({ title: s.string() }),14 grants: sharedGrantTable("docs"),15});1617Deno.test("sharing identities round-trip only inside the configured app", () => {18 const identity = encodeSharingIdentity("stable-jazz-principal");19 assert(20 decodeSharingIdentity(identity) === "stable-jazz-principal",21 "identity did not round-trip",22 );23 let code = "";24 try {25 decodeSharingIdentity("lofi1:different-app:principal");26 } catch (error) {27 code = error instanceof AccessError ? error.code : "unexpected";28 }29 assert(code === "invalid-identity", "cross-app identity was accepted");30});3132Deno.test("sharing identities tolerate copy/paste padding but never inner whitespace", () => {33 const identity = encodeSharingIdentity("stable-jazz-principal");34 assert(35 decodeSharingIdentity(` ${identity}\n`) === "stable-jazz-principal",36 "surrounding whitespace from copy/paste must not change the decoded principal",37 );38 // A grant recorded for a whitespace-bearing principal looks active to the39 // owner but never matches the recipient's account — reject at both ends.40 let decoded = "";41 try {42 decodeSharingIdentity(identity.replace("principal", "prin cipal"));43 } catch (error) {44 decoded = error instanceof AccessError ? error.code : "unexpected";45 }46 assert(decoded === "invalid-identity", "inner whitespace in the principal was accepted");47 let encoded = "";48 try {49 encodeSharingIdentity("principal with spaces");50 } catch (error) {51 encoded = error instanceof AccessError ? error.code : "unexpected";52 }53 assert(encoded === "invalid-identity", "a whitespace-bearing principal must not encode");54});5556Deno.test("shared operations reject managed-sync work before touching a local-only runtime", async () => {57 const operations = createSharingOperations({ resource: app.docs, grants: app.grants });58 let code = "";59 try {60 await operations.share("resource", encodeSharingIdentity("recipient"), "read");61 } catch (error) {62 code = error instanceof AccessError ? error.code : "unexpected";63 }64 assert(code === "sync-required", "local-only sharing did not report its sync precondition");65});6667Deno.test("fingerprint-bearing identities round-trip and coexist with plain ones", () => {68 const plain = encodeSharingIdentity("stable-jazz-principal");69 assert(plain.startsWith("lofi1:"), "a fingerprintless identity stays v1");70 const pinned = encodeSharingIdentity("stable-jazz-principal", "fp-abc123");71 assert(pinned.startsWith("lofi2:"), "a fingerprint upgrades the identity to v2");72 const details = decodeSharingIdentityDetails(pinned);73 assert(74 details.userId === "stable-jazz-principal" && details.fingerprint === "fp-abc123",75 "v2 identity did not round-trip its parts",76 );77 assert(78 decodeSharingIdentity(pinned) === "stable-jazz-principal",79 "the principal-only decoder must accept v2",80 );81 assert(82 decodeSharingIdentityDetails(plain).fingerprint === undefined,83 "a v1 identity carries no fingerprint",84 );85 let code = "";86 try {87 decodeSharingIdentityDetails(`${plain}:unexpected-extra`);88 } catch (error) {89 code = error instanceof AccessError ? error.code : "unexpected";90 }91 assert(code === "invalid-identity", "a v1 identity with a trailing segment was accepted");92});