feat(api): add account workspaces and signed content events
This commit is contained in:
1 parent
937b774a93
commit
7b8d61d1ba
63 files changed
+5407
-370
No files matched your search
@@ -9,7 +9,7 @@
|
||||
//
|
||||
// 所有输入都是固定值,输出完全确定,可以放心提交到仓库。
|
||||
|
||||
import { createCipheriv, createHash, hkdfSync } from 'node:crypto';
|
||||
import { createCipheriv, createHash, createPublicKey, hkdfSync, verify as verifySignature } from 'node:crypto';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
@@ -149,6 +149,47 @@ function encodeItem({ itemId, meta, content, maxFrameData = MAX_FRAME_DATA, snap
|
||||
|
||||
const vectors = { version: 1 };
|
||||
|
||||
// 固定 ECDSA P-256 验签向量。签名只用于测试,对应私钥不进入向量。
|
||||
const signatureFixture = {
|
||||
x: 'OJVV0pkDZHH7F92rxIQt1EuXk4ZesLwoWTaMSANt79A',
|
||||
y: 'HRP3ZgqoD_8Iv42Mw1oflcJUKeq3H1gEbbOLNJoC_zs',
|
||||
kind: 'chat.create',
|
||||
payload: '01020304deadbeef',
|
||||
signature: '9dad329614d98c97acc5a60622329e57e111fd7579edc7e4bcc535476aae281cc7e3ee00fa2d5d901af525875af653d74bd441ca5dd54d00081b51b7c3b5adcb',
|
||||
};
|
||||
const signatureKind = Buffer.from(signatureFixture.kind, 'ascii');
|
||||
const signaturePayload = unhex(signatureFixture.payload);
|
||||
const signatureMessage = Buffer.concat([
|
||||
Buffer.from([0x57, 0x44, 0x53, 0x01]), u16(signatureKind.length), signatureKind,
|
||||
u32(signaturePayload.length), signaturePayload,
|
||||
]);
|
||||
const signaturePublicKey = createPublicKey({ key: { kty: 'EC', crv: 'P-256', x: signatureFixture.x, y: signatureFixture.y }, format: 'jwk' });
|
||||
if (!verifySignature('sha256', signatureMessage, { key: signaturePublicKey, dsaEncoding: 'ieee-p1363' }, unhex(signatureFixture.signature)))
|
||||
throw new Error('固定签名向量无效');
|
||||
vectors.signatures = { ...signatureFixture, message: hex(signatureMessage) };
|
||||
|
||||
const eventDigests = [seq(0x31, 32), seq(0x71, 32)];
|
||||
const eventManifestInput = Buffer.concat([Buffer.from('WD1M', 'ascii'), u32(eventDigests.length),
|
||||
...eventDigests.flatMap((digest, index) => [u32(index), digest])]);
|
||||
const eventFields = {
|
||||
space_id: hex(channelId), channel_id: '01234567-89ab-cdef-0123-456789abcdef', username: 'alice',
|
||||
device_id: '11111111-2222-3333-4444-555555555555', event_id: hex(itemC), kind: 'chat.edit',
|
||||
domain: 'chat', epoch: 2, item_id: hex(itemA), frame_count: 2, target_item_id: hex(itemB),
|
||||
};
|
||||
const eventKind = Buffer.from(eventFields.kind, 'ascii');
|
||||
const eventChannel = Buffer.from(eventFields.channel_id, 'ascii');
|
||||
const eventUser = Buffer.from(eventFields.username, 'ascii');
|
||||
const eventDevice = Buffer.from(eventFields.device_id, 'ascii');
|
||||
const eventTarget = unhex(eventFields.target_item_id);
|
||||
const eventManifest = sha256(eventManifestInput);
|
||||
const eventPayload = Buffer.concat([
|
||||
channelId, Buffer.from([eventChannel.length]), eventChannel, Buffer.from([eventUser.length]), eventUser,
|
||||
Buffer.from([eventDevice.length]), eventDevice, itemC, Buffer.from([eventKind.length]), eventKind,
|
||||
Buffer.from([1]), u32(eventFields.epoch), itemA, u32(eventFields.frame_count), eventManifest,
|
||||
Buffer.from([1]), eventTarget,
|
||||
]);
|
||||
vectors.content_event = { ...eventFields, frame_digests: eventDigests.map(hex), manifest_hash: hex(eventManifest), payload: hex(eventPayload) };
|
||||
|
||||
vectors.inputs = {
|
||||
channel_id: hex(channelId),
|
||||
channel_id_b64: b64url(channelId),
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
{
|
||||
"version": 1,
|
||||
"signatures": {
|
||||
"x": "OJVV0pkDZHH7F92rxIQt1EuXk4ZesLwoWTaMSANt79A",
|
||||
"y": "HRP3ZgqoD_8Iv42Mw1oflcJUKeq3H1gEbbOLNJoC_zs",
|
||||
"kind": "chat.create",
|
||||
"payload": "01020304deadbeef",
|
||||
"signature": "9dad329614d98c97acc5a60622329e57e111fd7579edc7e4bcc535476aae281cc7e3ee00fa2d5d901af525875af653d74bd441ca5dd54d00081b51b7c3b5adcb",
|
||||
"message": "57445301000b636861742e6372656174650000000801020304deadbeef"
|
||||
},
|
||||
"content_event": {
|
||||
"space_id": "000102030405060708090a0b0c0d0e0f",
|
||||
"channel_id": "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"username": "alice",
|
||||
"device_id": "11111111-2222-3333-4444-555555555555",
|
||||
"event_id": "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf",
|
||||
"kind": "chat.edit",
|
||||
"domain": "chat",
|
||||
"epoch": 2,
|
||||
"item_id": "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||
"frame_count": 2,
|
||||
"target_item_id": "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf",
|
||||
"frame_digests": [
|
||||
"3132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50",
|
||||
"7172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90"
|
||||
],
|
||||
"manifest_hash": "97c6a9995ae971032e62baa1f2388f966c814d8a2e22c7299715879809d6d98c",
|
||||
"payload": "000102030405060708090a0b0c0d0e0f2430313233343536372d383961622d636465662d303132332d34353637383961626364656605616c6963652431313131313131312d323232322d333333332d343434342d353535353535353535353535d0d1d2d3d4d5d6d7d8d9dadbdcdddedf09636861742e656469740100000002a0a1a2a3a4a5a6a7a8a9aaabacadaeaf0000000297c6a9995ae971032e62baa1f2388f966c814d8a2e22c7299715879809d6d98c01b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
|
||||
},
|
||||
"inputs": {
|
||||
"channel_id": "000102030405060708090a0b0c0d0e0f",
|
||||
"channel_id_b64": "AAECAwQFBgcICQoLDA0ODw",
|
||||
|
||||
Reference in new issue
Block a user