Core Specification (v0.1)
This specification defines the physical layout, manifest schema, Content Security Policy, and database geometry of DAI containers.
1. Container Distribution Layout
A DAI container may be distributed as a standalone binary archive (.dai) or as an executable polyglot HTML document (.dai.html):
[app-name].dai.html
├── <meta name="dai-integrity" content="required">
├── <meta name="dai-public-key" content="<base64 SPKI>">
├── <script id="dai-bootloader"> inlined runtime bootloader
└── <script id="dai-payload"> base64 of ZIP archive:
├── app/** compiled application assets
├── runtime/sqlite3.wasm bundled SQLite engine (865 KB)
├── runtime/sqlite3.mjs Emscripten WebAssembly glue (579 KB)
├── runtime/container.html sealed copy of the container shell
├── runtime/manifest.json manifest, hashes, and signature block
└── document.sqlite stateful database2. Content Security Policy (CSP)
The following CSP header/meta-tag is strictly enforced:
default-src 'none';
script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob:;
style-src 'self' 'unsafe-inline' blob:;
img-src 'self' data: blob:;
font-src 'self' data: blob:;
media-src 'self' data: blob:;
frame-src 'self' blob:;
worker-src blob:;
connect-src 'none';
form-action 'none';
base-uri 'none';
object-src 'none';connect-src 'none'is absolute and non-negotiable.blob:is permitted for scripts, styles, images, and frames because blob URLs are origin-local object URLs minted directly from the embedded payload in memory.'unsafe-eval'is prohibited; only'wasm-unsafe-eval'is granted for SQLite instantiation.
3. Formal Manifest Schema (runtime/manifest.json)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": [
"manifestVersion",
"documentUuid",
"appName",
"createdAt",
"algorithm",
"integrityPolicy",
"hashes"
],
"properties": {
"manifestVersion": { "type": "integer", "const": 1 },
"documentUuid": { "type": "string", "format": "uuid" },
"appName": { "type": "string" },
"favicon": { "type": "string" },
"createdAt": { "type": "string", "format": "date-time" },
"algorithm": { "type": "string", "enum": ["SHA-256"] },
"integrityPolicy": { "type": "string", "enum": ["required", "advisory"] },
"hashes": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"validUntil": {
"type": "integer",
"description": "Optional Unix timestamp after which execution is refused."
},
"signatureAlgorithm": { "type": "string", "enum": ["ECDSA-P256-SHA256"] },
"publicKeyFingerprint": { "type": "string" },
"signedEntries": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"signature": { "type": "string" }
}
}4. The Canonical Payload
Signatures are computed over the canonical payload string generated by canonicalPayload():
export function canonicalPayload(
uuid: string,
entries: Record<string, string>,
validUntil?: number,
): string {
const sorted = Object.keys(entries)
.sort()
.map((name) => name + ":" + entries[name])
.join("\n");
const base = "dai-v1\n" + uuid + "\n" + sorted + "\n";
// Appended only when present so unsigned/perpetual containers remain backward compatible
return validUntil === undefined ? base : base + "!validUntil:" + validUntil + "\n";
}Why validUntil is Covered by the Signature
No other manifest field is signed—the manifest is excluded from its own digest list. If validUntil were an unsigned manifest property, an adversary could modify or delete the timestamp using a text editor. By appending !validUntil:<timestamp> to the canonical signed payload, modifying or extending the expiration invalidates the cryptographic signature.
5. Database Geometry (SQLite)
- Pinned 4096-byte Page Size: All newly initialized databases execute
PRAGMA page_size = 4096before table creation. This ensures deterministic database geometry across varying SQLite engine builds. - In-Memory VFS: Databases are deserialized into memory using
sqlite3_deserializeand exported viasqlite3_js_db_export. - Database Excluded from Signature:
document.sqliteis hashed inmanifest.hashesbut excluded frommanifest.signedEntries. The application logic remains permanently signed and authentic while user data can evolve across saves.