sign every write as an MMUR2 claim (POST /api/claims)
Build and Push Docker Image / build (push) Successful in 2m35s

This commit is contained in:
Worph
2026-10-25 17:37:05 +00:00
parent c62e671eb3
commit 8e242225dd
2 changed files with 383 additions and 32 deletions
+41 -2
View File
@@ -1,12 +1,21 @@
/**
* In-process stand-in for the two HTTP surfaces a plugin talks to:
* - WebDAV at /webdav/... (JSON directory listing, HEAD, Range GET, PUT)
* - meta API at /meta/... (GET record / property, PATCH merge, DELETE property)
* - meta API at /meta/... (GET record / property)
* - POST /api/claims (signed MMUR2 claims — every signature is verified)
* Records are stored FLAT (`subtitles/fre/<cid>`), the way meta-core keeps them.
*
* Claims are folded back into the old call shape so tests keep asserting on
* writes per record: a batch's text claims become one `PATCH /meta/<cid>`
* (body = key → value) and each retraction a `DELETE /meta/<cid>/<key>`.
*/
import http from 'http';
import type { AddressInfo } from 'net';
import { verifyClaim, type ClaimValue } from '../src/meta-core-client.js';
// Fixed test signing key (scalar 0x0101…01) — the plugin signs as this.
process.env.METAMESH_SIGNING_KEY ??= '01'.repeat(32);
export interface FakeCall {
method: string;
@@ -99,6 +108,36 @@ export async function startFakeCore(): Promise<FakeCore> {
return send(200, data, { 'Content-Length': String(data.length), 'Accept-Ranges': 'bytes' });
}
if (pathname === '/api/claims' && req.method === 'POST') {
const claims = JSON.parse((await readBody(req)).toString('utf8')) as Array<{
cid: string; uid: string; key: string; value: string | { b64: string } | null; ts: number; sig: string;
}>;
if (core.failPatch) return send(500, { error: 'boom' });
const statuses: Array<{ status: string }> = [];
const sets = new Map<string, Record<string, string>>();
for (const c of claims) {
const value: ClaimValue = c.value === null ? null
: typeof c.value === 'string' ? c.value : Buffer.from(c.value.b64, 'base64');
if (!verifyClaim({ ...c, value, sig: Buffer.from(c.sig, 'base64') })) {
statuses.push({ status: 'bad_signature' });
continue;
}
statuses.push({ status: 'accepted' });
if (value === null) {
core.calls.push({ method: 'DELETE', path: `/meta/${c.cid}/${c.key}` });
const record = core.records.get(c.cid);
if (record) delete record[c.key];
} else {
sets.set(c.cid, { ...(sets.get(c.cid) ?? {}), [c.key]: String(value) });
}
}
for (const [cid, body] of sets) {
core.calls.push({ method: 'PATCH', path: `/meta/${cid}`, body });
core.records.set(cid, { ...(core.records.get(cid) ?? {}), ...body });
}
return send(200, statuses);
}
const m = /^\/meta\/([^/]+)(?:\/(.+))?$/.exec(pathname);
if (m) {
const [, hash, key] = m;
@@ -141,7 +180,7 @@ export async function startFakeCore(): Promise<FakeCore> {
};
}
/** Mutating calls (PATCH / DELETE) against one record. */
/** Mutating calls (claims folded to PATCH / DELETE) against one record. */
export function writesTo(core: FakeCore, hash: string): FakeCall[] {
return core.calls.filter((c) => c.path === `/meta/${hash}` || c.path.startsWith(`/meta/${hash}/`));
}