Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
// The page model of one inspection: every value the inspector shows, built
|
|
|
|
|
// from the library's Inspection with no DOM and no clock, so that it can be
|
|
|
|
|
// tested without a browser.
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
canonicalJSON,
|
|
|
|
|
chainHashHex,
|
|
|
|
|
compactDateKey,
|
|
|
|
|
DKC_PRELUDE_SIZE,
|
|
|
|
|
type ErrorCode,
|
|
|
|
|
type Extension,
|
|
|
|
|
type ExtensionRegistry,
|
Read capsule format 2 of spec v0.9
Syncs testdata with datekeys-go at spec-v0.9 (7e2d83c) and moves the
reader to the DateKeys Protocol Specification v0.9. Both capsule formats
are read; a format 1 capsule keeps the verdict v0.8.2 gave it.
- framing: the VERSION of the prelude is the capsule format, 1 or 2
(Prelude.format, FORMAT_1, FORMAT_2, isFormat).
- control: decodeControl and encodeControl take the format; schema
version 2 adds payload_length (8 bytes, at most L_MAX) and padding
(1 or 2).
- padding.ts: the rules bloque256 and reforzado of spec §29.1, exact up
to L_MAX with BigInt bit lengths and ceil roundings, and the length of
PAYLOAD_AGE.
- open: exactly 16 stanzas in INNER_ACCESS_AGE of format 2 (step 12), P
at step 16, and at step 17 a plaintext of exactly P bytes whose
padding is zero; only the first L bytes are delivered, never the
padding. Step 17 is recorded when it passes, and step 18 gives the
bytes of content, as the reference does. Opened reports the format, L
and, in format 2, the rule and P.
- inspect: the JSON view carries format, as datekeys inspect -json.
- The page shows the format, warns about format 1, and gives the
padding rule and P once a format 2 capsule opens.
Tests: the twelve fixtures, the 125 mutation cases through open from
memory and from a Blob, the 4380 differential cases, padding.json, the
format 2 CBOR vectors, and padding.test.ts against a BigInt statement of
§29.1. The error texts of the 125 corpus cases were compared with
capsule.Open at spec-v0.9. ibe-vectors.json gains the seven format 2
fixtures from scripts/ibe-go-vectors.go; its frozen values are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
type Format,
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
formatRFC3339,
|
|
|
|
|
type Inspection,
|
|
|
|
|
inspectView,
|
|
|
|
|
type InspectView,
|
|
|
|
|
policyName,
|
|
|
|
|
STANZA_TLOCK,
|
|
|
|
|
type StanzaInfo,
|
|
|
|
|
toHex,
|
Phase 2, step 8: the open action of /inspect
After steps 1 to 8, a valid capsule whose date has passed on the device
clock can be opened in the page: steps 9 to 18 of spec section 63 with
open, loaded on demand with a dynamic import (opener.ts), so noble and
age-encryption stay out of the first load of every page.
- The release is supplied directly by the person (spec 63, step 10):
drand's JSON answer or the bare signature, pasted after opening the
drand URL the page links to, or the release in the record of an
official fixture. The page never fetches it and reads only its round
and signature (spec 11, 13). The CSP is unchanged.
- time_and_key credentials: a .dkk (readAccessKey reads at most
12 bytes + 16 MiB + 1) or age identities, one per line.
- The plaintext of the person's own file goes to a temporary OPFS file
(tempfile.ts), committed only after step 18 (spec 56), offered for
download and deleted on request, with another capsule, on pagehide
and, if left over, on the next visit. One directory and one Web Lock
per tab keep other tabs' clean-up away from files in use. Without
OPFS, or when the browser refuses it, capsules up to 64 MiB open in
memory. An opening in progress stops when another capsule is loaded.
- opening.ts builds the page model of steps 9 to 18 as the reference
records them; fixtures show their plaintext and compare its SHA-256
with their record.
- licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts),
the license of every package in the client bundle, Vite's and
rolldown's runtime code, and the site's own license. check-build now
fails if a notice is missing, or if a page loads noble, @scure/base
or age-encryption with its first load.
- The home page no longer says that the page never asks for keys.
Checked in the browser on the production build: the time_only,
time_and_key_portable (with its .dkk) and time_and_key_recipients (with
a pasted identity) fixtures open with the SHA-256 of their records; a
tampered signature fails at step 10 and a tampered STREAM chunk at step
17, with no download and no file left; an own file opens to OPFS,
downloads without a CSP violation and is deleted with its lock; a left
over directory goes on the next visit; no request leaves the origin.
An adversarial review (four dimensions, each finding checked by a
refuter) confirmed 15 findings, all fixed here.
2611 tests; coverage 100 % of the new modules, now a threshold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
type Unusable,
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
} from '../dkc/index.ts';
|
|
|
|
|
import { cborView, type Diagnostic } from './diagnostic.ts';
|
|
|
|
|
import { cliJSON, displayText, instantToEpochMs, INSPECT_STEPS, printableText, stepGloss, stepName } from './format.ts';
|
|
|
|
|
|
|
|
|
|
export type StepState = 'ok' | 'failed' | 'not-run';
|
|
|
|
|
|
|
|
|
|
/** One of the eight steps, as the CLI reports it, or not run. */
|
|
|
|
|
export interface StepRow {
|
|
|
|
|
readonly step: number;
|
|
|
|
|
/** The CLI name, for example "header validation". */
|
|
|
|
|
readonly name: string;
|
|
|
|
|
/** What the step checks, in Spanish. */
|
|
|
|
|
readonly gloss: string;
|
|
|
|
|
readonly state: StepState;
|
|
|
|
|
/** The pass detail or the error message; undefined when not run. */
|
|
|
|
|
readonly detail?: string;
|
|
|
|
|
/** The normative code of a failed step. */
|
|
|
|
|
readonly code?: ErrorCode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** A value read from the capsule next to the one the pinned profile expects. */
|
|
|
|
|
export interface Comparison {
|
|
|
|
|
readonly label: string;
|
|
|
|
|
readonly found: string | undefined;
|
|
|
|
|
readonly expected: string;
|
|
|
|
|
readonly match: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** One PUBLIC_HEADER extension, with every view of its data. */
|
|
|
|
|
export interface ExtensionRow {
|
|
|
|
|
readonly critical: boolean;
|
|
|
|
|
/** extension_id as shown: as it is, or quoted and escaped. */
|
|
|
|
|
readonly id: string;
|
|
|
|
|
/** The identifier holds non-printable characters and is shown escaped. */
|
|
|
|
|
readonly idEscaped: boolean;
|
|
|
|
|
readonly version: number;
|
|
|
|
|
/** Whether this reader implements the extension. */
|
|
|
|
|
readonly known: boolean;
|
|
|
|
|
/** The data error of a known noncritical extension the reader cannot use. */
|
|
|
|
|
readonly unusable?: string;
|
|
|
|
|
/** Data length in bytes; 0 when the extension carries no data. */
|
|
|
|
|
readonly length: number;
|
|
|
|
|
/** Data in lowercase hexadecimal. */
|
|
|
|
|
readonly hex: string;
|
|
|
|
|
/** The data as text when it is valid printable UTF-8. */
|
|
|
|
|
readonly text?: string;
|
|
|
|
|
/** Informative diagnostic notation when the data is CBOR of the §58 profile. */
|
|
|
|
|
readonly cbor?: Diagnostic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CapsuleFacts {
|
|
|
|
|
readonly capsuleId: string;
|
|
|
|
|
readonly accessPolicy: string;
|
|
|
|
|
/** The compact dk1_ DateKey. */
|
|
|
|
|
readonly dateKey: string;
|
|
|
|
|
/** Its decoded payload, the canonical JSON of spec §18. */
|
|
|
|
|
readonly dateKeyJSON: string;
|
|
|
|
|
/** The network field of the DateKey: the profile_id. */
|
|
|
|
|
readonly network: string;
|
|
|
|
|
readonly round: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProfileFacts {
|
|
|
|
|
readonly id: string;
|
|
|
|
|
readonly provider: string;
|
|
|
|
|
readonly network: string;
|
|
|
|
|
readonly chainHash: string;
|
|
|
|
|
readonly period: number;
|
|
|
|
|
readonly genesis: string;
|
|
|
|
|
readonly scheme: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PreludeFacts {
|
|
|
|
|
/** The 16 prelude bytes in hexadecimal. */
|
|
|
|
|
readonly hex: string;
|
|
|
|
|
readonly magic: string;
|
Read capsule format 2 of spec v0.9
Syncs testdata with datekeys-go at spec-v0.9 (7e2d83c) and moves the
reader to the DateKeys Protocol Specification v0.9. Both capsule formats
are read; a format 1 capsule keeps the verdict v0.8.2 gave it.
- framing: the VERSION of the prelude is the capsule format, 1 or 2
(Prelude.format, FORMAT_1, FORMAT_2, isFormat).
- control: decodeControl and encodeControl take the format; schema
version 2 adds payload_length (8 bytes, at most L_MAX) and padding
(1 or 2).
- padding.ts: the rules bloque256 and reforzado of spec §29.1, exact up
to L_MAX with BigInt bit lengths and ceil roundings, and the length of
PAYLOAD_AGE.
- open: exactly 16 stanzas in INNER_ACCESS_AGE of format 2 (step 12), P
at step 16, and at step 17 a plaintext of exactly P bytes whose
padding is zero; only the first L bytes are delivered, never the
padding. Step 17 is recorded when it passes, and step 18 gives the
bytes of content, as the reference does. Opened reports the format, L
and, in format 2, the rule and P.
- inspect: the JSON view carries format, as datekeys inspect -json.
- The page shows the format, warns about format 1, and gives the
padding rule and P once a format 2 capsule opens.
Tests: the twelve fixtures, the 125 mutation cases through open from
memory and from a Blob, the 4380 differential cases, padding.json, the
format 2 CBOR vectors, and padding.test.ts against a BigInt statement of
§29.1. The error texts of the 125 corpus cases were compared with
capsule.Open at spec-v0.9. ibe-vectors.json gains the seven format 2
fixtures from scripts/ibe-go-vectors.go; its frozen values are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
/**
|
|
|
|
|
* VERSION, the capsule format (spec §22): format 1 does not hide the
|
|
|
|
|
* number of credentials nor the exact length of the content (§55.2, §70).
|
|
|
|
|
*/
|
|
|
|
|
readonly format: Format;
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
readonly flags: string;
|
|
|
|
|
readonly reserved: string;
|
|
|
|
|
readonly publicHeaderLen: number;
|
|
|
|
|
readonly sealedControlLen: number;
|
|
|
|
|
/** Where PAYLOAD_AGE starts. */
|
|
|
|
|
readonly payloadOffset: number;
|
|
|
|
|
/** Bytes of PAYLOAD_AGE, when the file reaches its start. */
|
|
|
|
|
readonly payloadLength?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface Report {
|
|
|
|
|
readonly fileName: string;
|
|
|
|
|
/** Size of the whole file. */
|
|
|
|
|
readonly size: number;
|
|
|
|
|
/** Bytes read for the inspection (see inspectedLength). */
|
|
|
|
|
readonly readLength: number;
|
|
|
|
|
readonly valid: boolean;
|
|
|
|
|
readonly failure?: { readonly step: number; readonly code: ErrorCode; readonly message: string };
|
|
|
|
|
/** Always the eight steps, in order. */
|
|
|
|
|
readonly steps: readonly StepRow[];
|
|
|
|
|
/** The view of `datekeys inspect -json`. */
|
|
|
|
|
readonly view: InspectView;
|
|
|
|
|
/** Its exact JSON text. */
|
|
|
|
|
readonly json: string;
|
|
|
|
|
readonly capsule?: CapsuleFacts;
|
|
|
|
|
readonly profile?: ProfileFacts;
|
|
|
|
|
/** The effective round time, once step 7 passed. */
|
|
|
|
|
readonly unlock?: { readonly rfc3339: string; readonly epochMs: number | undefined };
|
|
|
|
|
readonly prelude?: PreludeFacts;
|
|
|
|
|
readonly outerStanzas?: readonly StanzaInfo[];
|
|
|
|
|
readonly payloadStanzas?: readonly StanzaInfo[];
|
|
|
|
|
/** The tlock stanza arguments against the pinned profile. */
|
|
|
|
|
readonly tlock?: readonly Comparison[];
|
|
|
|
|
/** Critical extensions first, then noncritical; undefined until PUBLIC_HEADER decoded. */
|
|
|
|
|
readonly extensions?: readonly ExtensionRow[];
|
|
|
|
|
/**
|
|
|
|
|
* The public note of the header (spec §24.1): text of the creator that
|
|
|
|
|
* nobody has checked, or `unusable` when the header holds a note that
|
|
|
|
|
* breaks the rules of text, which is not shown. Undefined without a note.
|
|
|
|
|
*/
|
|
|
|
|
readonly note?: { readonly text: string } | { readonly unusable: true };
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportInput {
|
|
|
|
|
readonly fileName: string;
|
|
|
|
|
/** The bytes that were inspected: the file or its inspected prefix. */
|
|
|
|
|
readonly bytes: Uint8Array;
|
|
|
|
|
/** Size of the whole file. */
|
|
|
|
|
readonly size: number;
|
|
|
|
|
readonly inspection: Inspection;
|
|
|
|
|
/** The extension registry given to the inspection, if any. */
|
|
|
|
|
readonly extensions?: ExtensionRegistry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hex8 = (v: number): string => `0x${v.toString(16).padStart(2, '0')}`;
|
|
|
|
|
|
|
|
|
|
export function buildReport(input: ReportInput): Report {
|
|
|
|
|
const { inspection: r, bytes, size } = input;
|
|
|
|
|
const view = inspectView(r, input.fileName);
|
|
|
|
|
const out: {
|
|
|
|
|
-readonly [K in keyof Report]: Report[K];
|
|
|
|
|
} = {
|
|
|
|
|
fileName: input.fileName,
|
|
|
|
|
size,
|
|
|
|
|
readLength: bytes.length,
|
|
|
|
|
valid: r.error === undefined,
|
|
|
|
|
steps: steps(r),
|
|
|
|
|
view,
|
|
|
|
|
json: cliJSON(view),
|
|
|
|
|
};
|
|
|
|
|
if (r.error !== undefined) {
|
|
|
|
|
const last = r.checks.at(-1)!;
|
|
|
|
|
out.failure = { step: last.step, code: r.error.code, message: r.error.message };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r.prelude !== undefined && r.payloadOffset !== undefined) {
|
|
|
|
|
const p: { -readonly [K in keyof PreludeFacts]: PreludeFacts[K] } = {
|
|
|
|
|
hex: toHex(bytes.subarray(0, DKC_PRELUDE_SIZE)),
|
|
|
|
|
magic: 'DKC1',
|
Read capsule format 2 of spec v0.9
Syncs testdata with datekeys-go at spec-v0.9 (7e2d83c) and moves the
reader to the DateKeys Protocol Specification v0.9. Both capsule formats
are read; a format 1 capsule keeps the verdict v0.8.2 gave it.
- framing: the VERSION of the prelude is the capsule format, 1 or 2
(Prelude.format, FORMAT_1, FORMAT_2, isFormat).
- control: decodeControl and encodeControl take the format; schema
version 2 adds payload_length (8 bytes, at most L_MAX) and padding
(1 or 2).
- padding.ts: the rules bloque256 and reforzado of spec §29.1, exact up
to L_MAX with BigInt bit lengths and ceil roundings, and the length of
PAYLOAD_AGE.
- open: exactly 16 stanzas in INNER_ACCESS_AGE of format 2 (step 12), P
at step 16, and at step 17 a plaintext of exactly P bytes whose
padding is zero; only the first L bytes are delivered, never the
padding. Step 17 is recorded when it passes, and step 18 gives the
bytes of content, as the reference does. Opened reports the format, L
and, in format 2, the rule and P.
- inspect: the JSON view carries format, as datekeys inspect -json.
- The page shows the format, warns about format 1, and gives the
padding rule and P once a format 2 capsule opens.
Tests: the twelve fixtures, the 125 mutation cases through open from
memory and from a Blob, the 4380 differential cases, padding.json, the
format 2 CBOR vectors, and padding.test.ts against a BigInt statement of
§29.1. The error texts of the 125 corpus cases were compared with
capsule.Open at spec-v0.9. ibe-vectors.json gains the seven format 2
fixtures from scripts/ibe-go-vectors.go; its frozen values are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
format: r.prelude.format,
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
flags: hex8(bytes[5]!),
|
|
|
|
|
reserved: `0x${toHex(bytes.subarray(6, 8))}`,
|
|
|
|
|
publicHeaderLen: r.prelude.publicHeaderLen,
|
|
|
|
|
sealedControlLen: r.prelude.sealedControlLen,
|
|
|
|
|
payloadOffset: r.payloadOffset,
|
|
|
|
|
};
|
|
|
|
|
if (size >= r.payloadOffset) p.payloadLength = size - r.payloadOffset;
|
|
|
|
|
out.prelude = p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const h = r.header;
|
|
|
|
|
if (h !== undefined) {
|
|
|
|
|
out.capsule = {
|
|
|
|
|
capsuleId: toHex(h.capsuleId),
|
|
|
|
|
accessPolicy: policyName(h.policy),
|
|
|
|
|
dateKey: compactDateKey(h.dateKey),
|
|
|
|
|
dateKeyJSON: canonicalJSON(h.dateKey) ?? '',
|
|
|
|
|
network: h.dateKey.profileId,
|
|
|
|
|
round: h.dateKey.round,
|
|
|
|
|
};
|
|
|
|
|
out.extensions = [
|
Phase 2, step 8: the open action of /inspect
After steps 1 to 8, a valid capsule whose date has passed on the device
clock can be opened in the page: steps 9 to 18 of spec section 63 with
open, loaded on demand with a dynamic import (opener.ts), so noble and
age-encryption stay out of the first load of every page.
- The release is supplied directly by the person (spec 63, step 10):
drand's JSON answer or the bare signature, pasted after opening the
drand URL the page links to, or the release in the record of an
official fixture. The page never fetches it and reads only its round
and signature (spec 11, 13). The CSP is unchanged.
- time_and_key credentials: a .dkk (readAccessKey reads at most
12 bytes + 16 MiB + 1) or age identities, one per line.
- The plaintext of the person's own file goes to a temporary OPFS file
(tempfile.ts), committed only after step 18 (spec 56), offered for
download and deleted on request, with another capsule, on pagehide
and, if left over, on the next visit. One directory and one Web Lock
per tab keep other tabs' clean-up away from files in use. Without
OPFS, or when the browser refuses it, capsules up to 64 MiB open in
memory. An opening in progress stops when another capsule is loaded.
- opening.ts builds the page model of steps 9 to 18 as the reference
records them; fixtures show their plaintext and compare its SHA-256
with their record.
- licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts),
the license of every package in the client bundle, Vite's and
rolldown's runtime code, and the site's own license. check-build now
fails if a notice is missing, or if a page loads noble, @scure/base
or age-encryption with its first load.
- The home page no longer says that the page never asks for keys.
Checked in the browser on the production build: the time_only,
time_and_key_portable (with its .dkk) and time_and_key_recipients (with
a pasted identity) fixtures open with the SHA-256 of their records; a
tampered signature fails at step 10 and a tampered STREAM chunk at step
17, with no download and no file left; an own file opens to OPFS,
downloads without a CSP violation and is deleted with its lock; a left
over directory goes on the next visit; no request leaves the origin.
An adversarial review (four dimensions, each finding checked by a
refuter) confirmed 15 findings, all fixed here.
2611 tests; coverage 100 % of the new modules, now a threshold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
...h.critical.map((e) => extensionRow(e, true, r.unusableExtensions, input.extensions)),
|
|
|
|
|
...h.noncritical.map((e) => extensionRow(e, false, r.unusableExtensions, input.extensions)),
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const p = r.profile;
|
|
|
|
|
if (p !== undefined) {
|
|
|
|
|
out.profile = {
|
|
|
|
|
id: p.id,
|
|
|
|
|
provider: p.provider,
|
|
|
|
|
network: p.network,
|
|
|
|
|
chainHash: chainHashHex(p),
|
|
|
|
|
period: p.period,
|
|
|
|
|
genesis: formatRFC3339({ seconds: p.genesisTime, nanos: 0 }),
|
|
|
|
|
scheme: p.scheme,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r.unlockAt !== undefined) {
|
|
|
|
|
out.unlock = { rfc3339: formatRFC3339(r.unlockAt), epochMs: instantToEpochMs(r.unlockAt) };
|
|
|
|
|
}
|
|
|
|
|
if (r.outerStanzas !== undefined) out.outerStanzas = r.outerStanzas;
|
|
|
|
|
if (r.payloadStanzas !== undefined) out.payloadStanzas = r.payloadStanzas;
|
|
|
|
|
|
|
|
|
|
if (r.outerStanzas !== undefined && h !== undefined && p !== undefined) {
|
|
|
|
|
const t = r.outerStanzas.find((s) => s.type === STANZA_TLOCK);
|
|
|
|
|
if (t !== undefined) {
|
|
|
|
|
out.tlock = [
|
|
|
|
|
compare('Argumentos', String(t.args.length), '2'),
|
|
|
|
|
compare('Ronda', t.args[0], String(h.dateKey.round)),
|
|
|
|
|
compare('Cadena (chain hash)', t.args[1], chainHashHex(p)),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (r.publicNote !== undefined) out.note = { text: r.publicNote };
|
|
|
|
|
else if (r.unusableNote === true) out.note = { unusable: true };
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compare(label: string, found: string | undefined, expected: string): Comparison {
|
|
|
|
|
return { label, found, expected, match: found === expected };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function steps(r: Inspection): StepRow[] {
|
|
|
|
|
return INSPECT_STEPS.map((step): StepRow => {
|
|
|
|
|
const c = r.checks.find((x) => x.step === step);
|
|
|
|
|
const base = { step, name: stepName(step), gloss: stepGloss(step) };
|
|
|
|
|
if (c === undefined) return { ...base, state: 'not-run' };
|
|
|
|
|
if (c.ok) return c.detail === undefined ? { ...base, state: 'ok' } : { ...base, state: 'ok', detail: c.detail };
|
|
|
|
|
const failed: { -readonly [K in keyof StepRow]: StepRow[K] } = { ...base, state: 'failed' };
|
|
|
|
|
if (c.detail !== undefined) failed.detail = c.detail;
|
|
|
|
|
if (r.error !== undefined) failed.code = r.error.code;
|
|
|
|
|
return failed;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
Phase 2, step 8: the open action of /inspect
After steps 1 to 8, a valid capsule whose date has passed on the device
clock can be opened in the page: steps 9 to 18 of spec section 63 with
open, loaded on demand with a dynamic import (opener.ts), so noble and
age-encryption stay out of the first load of every page.
- The release is supplied directly by the person (spec 63, step 10):
drand's JSON answer or the bare signature, pasted after opening the
drand URL the page links to, or the release in the record of an
official fixture. The page never fetches it and reads only its round
and signature (spec 11, 13). The CSP is unchanged.
- time_and_key credentials: a .dkk (readAccessKey reads at most
12 bytes + 16 MiB + 1) or age identities, one per line.
- The plaintext of the person's own file goes to a temporary OPFS file
(tempfile.ts), committed only after step 18 (spec 56), offered for
download and deleted on request, with another capsule, on pagehide
and, if left over, on the next visit. One directory and one Web Lock
per tab keep other tabs' clean-up away from files in use. Without
OPFS, or when the browser refuses it, capsules up to 64 MiB open in
memory. An opening in progress stops when another capsule is loaded.
- opening.ts builds the page model of steps 9 to 18 as the reference
records them; fixtures show their plaintext and compare its SHA-256
with their record.
- licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts),
the license of every package in the client bundle, Vite's and
rolldown's runtime code, and the site's own license. check-build now
fails if a notice is missing, or if a page loads noble, @scure/base
or age-encryption with its first load.
- The home page no longer says that the page never asks for keys.
Checked in the browser on the production build: the time_only,
time_and_key_portable (with its .dkk) and time_and_key_recipients (with
a pasted identity) fixtures open with the SHA-256 of their records; a
tampered signature fails at step 10 and a tampered STREAM chunk at step
17, with no download and no file left; an own file opens to OPFS,
downloads without a CSP violation and is deleted with its lock; a left
over directory goes on the next visit; no request leaves the origin.
An adversarial review (four dimensions, each finding checked by a
refuter) confirmed 15 findings, all fixed here.
2611 tests; coverage 100 % of the new modules, now a threshold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
/**
|
|
|
|
|
* The row of one extension of PUBLIC_HEADER, CONTROL_CBOR or a .dkk, given
|
|
|
|
|
* the known noncritical extensions of that object that the registry rejects.
|
|
|
|
|
*/
|
|
|
|
|
export function extensionRow(e: Extension, critical: boolean, unusable: readonly Unusable[], reg: ExtensionRegistry | undefined): ExtensionRow {
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
const id = displayText(e.id);
|
|
|
|
|
const row: { -readonly [K in keyof ExtensionRow]: ExtensionRow[K] } = {
|
|
|
|
|
critical,
|
|
|
|
|
id: id.text,
|
|
|
|
|
idEscaped: id.escaped,
|
|
|
|
|
version: e.version,
|
|
|
|
|
known: reg?.known(e.id, e.version) ?? false,
|
|
|
|
|
length: e.data?.length ?? 0,
|
|
|
|
|
hex: e.data === undefined ? '' : toHex(e.data),
|
|
|
|
|
};
|
Phase 2, step 8: the open action of /inspect
After steps 1 to 8, a valid capsule whose date has passed on the device
clock can be opened in the page: steps 9 to 18 of spec section 63 with
open, loaded on demand with a dynamic import (opener.ts), so noble and
age-encryption stay out of the first load of every page.
- The release is supplied directly by the person (spec 63, step 10):
drand's JSON answer or the bare signature, pasted after opening the
drand URL the page links to, or the release in the record of an
official fixture. The page never fetches it and reads only its round
and signature (spec 11, 13). The CSP is unchanged.
- time_and_key credentials: a .dkk (readAccessKey reads at most
12 bytes + 16 MiB + 1) or age identities, one per line.
- The plaintext of the person's own file goes to a temporary OPFS file
(tempfile.ts), committed only after step 18 (spec 56), offered for
download and deleted on request, with another capsule, on pagehide
and, if left over, on the next visit. One directory and one Web Lock
per tab keep other tabs' clean-up away from files in use. Without
OPFS, or when the browser refuses it, capsules up to 64 MiB open in
memory. An opening in progress stops when another capsule is loaded.
- opening.ts builds the page model of steps 9 to 18 as the reference
records them; fixtures show their plaintext and compare its SHA-256
with their record.
- licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts),
the license of every package in the client bundle, Vite's and
rolldown's runtime code, and the site's own license. check-build now
fails if a notice is missing, or if a page loads noble, @scure/base
or age-encryption with its first load.
- The home page no longer says that the page never asks for keys.
Checked in the browser on the production build: the time_only,
time_and_key_portable (with its .dkk) and time_and_key_recipients (with
a pasted identity) fixtures open with the SHA-256 of their records; a
tampered signature fails at step 10 and a tampered STREAM chunk at step
17, with no download and no file left; an own file opens to OPFS,
downloads without a CSP violation and is deleted with its lock; a left
over directory goes on the next visit; no request leaves the origin.
An adversarial review (four dimensions, each finding checked by a
refuter) confirmed 15 findings, all fixed here.
2611 tests; coverage 100 % of the new modules, now a threshold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
const u = critical ? undefined : unusable.find((x) => x.id === e.id && x.version === e.version);
|
|
|
|
|
if (u !== undefined) row.unusable = u.error.message;
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
if (e.data !== undefined) {
|
|
|
|
|
const text = printableText(e.data);
|
|
|
|
|
if (text !== undefined) row.text = text;
|
|
|
|
|
const cbor = cborView(e.data);
|
|
|
|
|
if (cbor !== undefined) row.cbor = cbor;
|
|
|
|
|
}
|
|
|
|
|
return row;
|
|
|
|
|
}
|