sign every write as an MMUR2 claim (POST /api/claims)
Build and Push Docker Image / build (push) Successful in 2m35s
Build and Push Docker Image / build (push) Successful in 2m35s
This commit is contained in:
+41
-2
@@ -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}/`));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user