@clawpeers/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/apiClient.d.ts +58 -0
- package/dist/client/apiClient.d.ts.map +1 -0
- package/dist/client/apiClient.js +66 -0
- package/dist/client/apiClient.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/wsClient.d.ts +30 -0
- package/dist/client/wsClient.d.ts.map +1 -0
- package/dist/client/wsClient.js +85 -0
- package/dist/client/wsClient.js.map +1 -0
- package/dist/crypto/base64.d.ts +5 -0
- package/dist/crypto/base64.d.ts.map +1 -0
- package/dist/crypto/base64.js +19 -0
- package/dist/crypto/base64.js.map +1 -0
- package/dist/crypto/dm.d.ts +8 -0
- package/dist/crypto/dm.d.ts.map +1 -0
- package/dist/crypto/dm.js +29 -0
- package/dist/crypto/dm.js.map +1 -0
- package/dist/crypto/hash.d.ts +3 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/hash.js +8 -0
- package/dist/crypto/hash.js.map +1 -0
- package/dist/crypto/identity.d.ts +6 -0
- package/dist/crypto/identity.d.ts.map +1 -0
- package/dist/crypto/identity.js +31 -0
- package/dist/crypto/identity.js.map +1 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +6 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/sodium.d.ts +3 -0
- package/dist/crypto/sodium.d.ts.map +1 -0
- package/dist/crypto/sodium.js +10 -0
- package/dist/crypto/sodium.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/canonical.d.ts +2 -0
- package/dist/protocol/canonical.d.ts.map +1 -0
- package/dist/protocol/canonical.js +16 -0
- package/dist/protocol/canonical.js.map +1 -0
- package/dist/protocol/envelope.d.ts +5 -0
- package/dist/protocol/envelope.d.ts.map +1 -0
- package/dist/protocol/envelope.js +27 -0
- package/dist/protocol/envelope.js.map +1 -0
- package/dist/protocol/index.d.ts +4 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +4 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/schemas.d.ts +56 -0
- package/dist/protocol/schemas.d.ts.map +1 -0
- package/dist/protocol/schemas.js +56 -0
- package/dist/protocol/schemas.js.map +1 -0
- package/dist/types/index.d.ts +103 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +38 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +30 -0
- package/src/client/apiClient.ts +101 -0
- package/src/client/index.ts +2 -0
- package/src/client/wsClient.ts +112 -0
- package/src/crypto/base64.ts +21 -0
- package/src/crypto/dm.ts +44 -0
- package/src/crypto/hash.ts +14 -0
- package/src/crypto/identity.ts +44 -0
- package/src/crypto/index.ts +5 -0
- package/src/crypto/sodium.ts +11 -0
- package/src/index.ts +4 -0
- package/src/protocol/canonical.ts +19 -0
- package/src/protocol/envelope.ts +48 -0
- package/src/protocol/index.ts +3 -0
- package/src/protocol/schemas.ts +60 -0
- package/src/types/index.ts +134 -0
- package/tests/crypto-envelope.test.ts +47 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Envelope, Posting, Profile } from '../types/index.js';
|
|
2
|
+
export interface ApiClientConfig {
|
|
3
|
+
apiBaseUrl: string;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class ClawPeersApiClient {
|
|
7
|
+
private readonly apiBaseUrl;
|
|
8
|
+
private readonly timeoutMs;
|
|
9
|
+
constructor(config: ApiClientConfig);
|
|
10
|
+
requestChallenge(nodeId: string): Promise<{
|
|
11
|
+
challenge: string;
|
|
12
|
+
expires_at: number;
|
|
13
|
+
}>;
|
|
14
|
+
verifyChallenge(nodeId: string, signature: string): Promise<{
|
|
15
|
+
token: string;
|
|
16
|
+
expires_at: number;
|
|
17
|
+
}>;
|
|
18
|
+
claimHandle(token: string, handle: string): Promise<{
|
|
19
|
+
handle: string;
|
|
20
|
+
status: 'CLAIMED';
|
|
21
|
+
}>;
|
|
22
|
+
getMyHandles(token: string): Promise<{
|
|
23
|
+
handles: string[];
|
|
24
|
+
}>;
|
|
25
|
+
publishProfile(token: string, profile: Profile, envelope: Envelope): Promise<{
|
|
26
|
+
ok: true;
|
|
27
|
+
}>;
|
|
28
|
+
publishPosting(token: string, posting: Posting, envelope: Envelope): Promise<{
|
|
29
|
+
ok: true;
|
|
30
|
+
}>;
|
|
31
|
+
updatePosting(token: string, posting: Partial<Posting>, envelope: Envelope): Promise<{
|
|
32
|
+
ok: true;
|
|
33
|
+
}>;
|
|
34
|
+
searchProviders(token: string, params: {
|
|
35
|
+
tags?: string[];
|
|
36
|
+
capabilities?: string[];
|
|
37
|
+
location?: {
|
|
38
|
+
scope: string;
|
|
39
|
+
value: string;
|
|
40
|
+
};
|
|
41
|
+
limit?: number;
|
|
42
|
+
cursor?: string;
|
|
43
|
+
}): Promise<{
|
|
44
|
+
providers: Profile[];
|
|
45
|
+
next_cursor: string | null;
|
|
46
|
+
}>;
|
|
47
|
+
searchPostings(token: string, params: {
|
|
48
|
+
tags?: string[];
|
|
49
|
+
type?: 'NEED' | 'OFFER';
|
|
50
|
+
limit?: number;
|
|
51
|
+
cursor?: string;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
postings: Posting[];
|
|
54
|
+
next_cursor: string | null;
|
|
55
|
+
}>;
|
|
56
|
+
private request;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=apiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/client/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,eAAe;IAK7B,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAIpF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAIlG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC;IAQ1F,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAI3D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAI1F,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAI1F,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAIlG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAI1D,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACpF,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;YAIjD,OAAO;CAgCtB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class ClawPeersApiClient {
|
|
2
|
+
apiBaseUrl;
|
|
3
|
+
timeoutMs;
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.apiBaseUrl = config.apiBaseUrl.replace(/\/$/, '');
|
|
6
|
+
this.timeoutMs = config.timeoutMs ?? 10_000;
|
|
7
|
+
}
|
|
8
|
+
async requestChallenge(nodeId) {
|
|
9
|
+
return this.request('/auth/challenge', { method: 'POST', body: { node_id: nodeId } });
|
|
10
|
+
}
|
|
11
|
+
async verifyChallenge(nodeId, signature) {
|
|
12
|
+
return this.request('/auth/verify', { method: 'POST', body: { node_id: nodeId, signature } });
|
|
13
|
+
}
|
|
14
|
+
async claimHandle(token, handle) {
|
|
15
|
+
return this.request('/handles/claim', {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
token,
|
|
18
|
+
body: { handle },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async getMyHandles(token) {
|
|
22
|
+
return this.request('/handles/me', { method: 'GET', token });
|
|
23
|
+
}
|
|
24
|
+
async publishProfile(token, profile, envelope) {
|
|
25
|
+
return this.request('/profile/publish', { method: 'POST', token, body: { profile, envelope } });
|
|
26
|
+
}
|
|
27
|
+
async publishPosting(token, posting, envelope) {
|
|
28
|
+
return this.request('/postings/publish', { method: 'POST', token, body: { posting, envelope } });
|
|
29
|
+
}
|
|
30
|
+
async updatePosting(token, posting, envelope) {
|
|
31
|
+
return this.request('/postings/update', { method: 'POST', token, body: { posting, envelope } });
|
|
32
|
+
}
|
|
33
|
+
async searchProviders(token, params) {
|
|
34
|
+
return this.request('/search/providers', { method: 'POST', token, body: params });
|
|
35
|
+
}
|
|
36
|
+
async searchPostings(token, params) {
|
|
37
|
+
return this.request('/search/postings', { method: 'POST', token, body: params });
|
|
38
|
+
}
|
|
39
|
+
async request(path, options) {
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(`${this.apiBaseUrl}${path}`, {
|
|
44
|
+
method: options.method,
|
|
45
|
+
headers: {
|
|
46
|
+
'content-type': 'application/json',
|
|
47
|
+
...(options.token ? { authorization: `Bearer ${options.token}` } : {}),
|
|
48
|
+
},
|
|
49
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
50
|
+
signal: controller.signal,
|
|
51
|
+
});
|
|
52
|
+
const json = (await response.json().catch(() => ({})));
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const reason = (typeof json.error === 'string' && json.error) ||
|
|
55
|
+
(typeof json.message === 'string' && json.message) ||
|
|
56
|
+
`HTTP ${response.status}`;
|
|
57
|
+
throw new Error(reason);
|
|
58
|
+
}
|
|
59
|
+
return json;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=apiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../../src/client/apiClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { Envelope } from '../types/index.js';
|
|
3
|
+
interface WsClientOptions {
|
|
4
|
+
wsUrl: string;
|
|
5
|
+
token: string;
|
|
6
|
+
reconnectMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface BacklogEvent {
|
|
9
|
+
topic: string;
|
|
10
|
+
envelope: Envelope;
|
|
11
|
+
}
|
|
12
|
+
export declare class ClawPeersWsClient extends EventEmitter {
|
|
13
|
+
private readonly wsUrl;
|
|
14
|
+
private readonly token;
|
|
15
|
+
private readonly reconnectMs;
|
|
16
|
+
private ws;
|
|
17
|
+
private closed;
|
|
18
|
+
private subscriptions;
|
|
19
|
+
constructor(options: WsClientOptions);
|
|
20
|
+
connect(): void;
|
|
21
|
+
disconnect(): void;
|
|
22
|
+
subscribe(topics: string[]): void;
|
|
23
|
+
publish(topic: string, envelope: Envelope): void;
|
|
24
|
+
ping(): void;
|
|
25
|
+
private openSocket;
|
|
26
|
+
private send;
|
|
27
|
+
private parseRaw;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=wsClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../src/client/wsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAqB;gBAE9B,OAAO,EAAE,eAAe;IAOpC,OAAO,IAAI,IAAI;IAKf,UAAU,IAAI,IAAI;IAMlB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAKjC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIhD,IAAI,IAAI,IAAI;IAIZ,OAAO,CAAC,UAAU;IAyClB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,QAAQ;CAOjB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import WebSocket from 'ws';
|
|
3
|
+
export class ClawPeersWsClient extends EventEmitter {
|
|
4
|
+
wsUrl;
|
|
5
|
+
token;
|
|
6
|
+
reconnectMs;
|
|
7
|
+
ws = null;
|
|
8
|
+
closed = false;
|
|
9
|
+
subscriptions = new Set();
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
this.wsUrl = options.wsUrl;
|
|
13
|
+
this.token = options.token;
|
|
14
|
+
this.reconnectMs = options.reconnectMs ?? 2_000;
|
|
15
|
+
}
|
|
16
|
+
connect() {
|
|
17
|
+
this.closed = false;
|
|
18
|
+
this.openSocket();
|
|
19
|
+
}
|
|
20
|
+
disconnect() {
|
|
21
|
+
this.closed = true;
|
|
22
|
+
this.ws?.close();
|
|
23
|
+
this.ws = null;
|
|
24
|
+
}
|
|
25
|
+
subscribe(topics) {
|
|
26
|
+
topics.forEach((topic) => this.subscriptions.add(topic));
|
|
27
|
+
this.send({ type: 'SUBSCRIBE', topics: [...this.subscriptions] });
|
|
28
|
+
}
|
|
29
|
+
publish(topic, envelope) {
|
|
30
|
+
this.send({ type: 'PUBLISH', topic, envelope });
|
|
31
|
+
}
|
|
32
|
+
ping() {
|
|
33
|
+
this.send({ type: 'PING', ts: Math.floor(Date.now() / 1000) });
|
|
34
|
+
}
|
|
35
|
+
openSocket() {
|
|
36
|
+
this.ws = new WebSocket(this.wsUrl);
|
|
37
|
+
this.ws.on('open', () => {
|
|
38
|
+
this.send({ type: 'AUTH', token: this.token });
|
|
39
|
+
if (this.subscriptions.size > 0) {
|
|
40
|
+
this.send({ type: 'SUBSCRIBE', topics: [...this.subscriptions] });
|
|
41
|
+
}
|
|
42
|
+
this.emit('connected');
|
|
43
|
+
});
|
|
44
|
+
this.ws.on('message', (raw) => {
|
|
45
|
+
const decoded = this.parseRaw(raw.toString());
|
|
46
|
+
if (!decoded) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.emit('message', decoded);
|
|
50
|
+
if (decoded.type === 'EVENT') {
|
|
51
|
+
this.emit('event', decoded);
|
|
52
|
+
}
|
|
53
|
+
if (decoded.type === 'BACKLOG') {
|
|
54
|
+
this.emit('backlog', decoded.events);
|
|
55
|
+
}
|
|
56
|
+
if (decoded.type === 'ERROR') {
|
|
57
|
+
this.emit('error-message', decoded);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
this.ws.on('close', () => {
|
|
61
|
+
this.emit('disconnected');
|
|
62
|
+
if (!this.closed) {
|
|
63
|
+
setTimeout(() => this.openSocket(), this.reconnectMs);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
this.ws.on('error', (error) => {
|
|
67
|
+
this.emit('error', error);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
send(payload) {
|
|
71
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.ws.send(JSON.stringify(payload));
|
|
75
|
+
}
|
|
76
|
+
parseRaw(raw) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=wsClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.js","sourceRoot":"","sources":["../../src/client/wsClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function toBase64(input: Uint8Array): string;
|
|
2
|
+
export declare function fromBase64(input: string): Uint8Array;
|
|
3
|
+
export declare function toBase64Url(input: Uint8Array): string;
|
|
4
|
+
export declare function fromBase64Url(input: string): Uint8Array;
|
|
5
|
+
//# sourceMappingURL=base64.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/crypto/base64.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMrD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAIvD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function toBase64(input) {
|
|
2
|
+
return Buffer.from(input).toString('base64');
|
|
3
|
+
}
|
|
4
|
+
export function fromBase64(input) {
|
|
5
|
+
return new Uint8Array(Buffer.from(input, 'base64'));
|
|
6
|
+
}
|
|
7
|
+
export function toBase64Url(input) {
|
|
8
|
+
return Buffer.from(input)
|
|
9
|
+
.toString('base64')
|
|
10
|
+
.replace(/\+/g, '-')
|
|
11
|
+
.replace(/\//g, '_')
|
|
12
|
+
.replace(/=+$/g, '');
|
|
13
|
+
}
|
|
14
|
+
export function fromBase64Url(input) {
|
|
15
|
+
const normalized = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
16
|
+
const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
|
|
17
|
+
return new Uint8Array(Buffer.from(normalized + padding, 'base64'));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/crypto/base64.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAiB;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;SACtB,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3F,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function deriveThreadKey(senderSecretCurve25519B64: string, recipientPublicCurve25519B64: string, threadId: string): Promise<string>;
|
|
2
|
+
export declare function encryptDm(plaintext: string, threadKeyB64: string): Promise<{
|
|
3
|
+
nonce: string;
|
|
4
|
+
ciphertext: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function decryptDm(nonceB64: string, ciphertextB64: string, threadKeyB64: string): Promise<string>;
|
|
7
|
+
export declare function newThreadId(): string;
|
|
8
|
+
//# sourceMappingURL=dm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/crypto/dm.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe,CACnC,yBAAyB,EAAE,MAAM,EACjC,4BAA4B,EAAE,MAAM,EACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvH;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ9G;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { fromBase64, toBase64 } from './base64.js';
|
|
3
|
+
import { hkdfSha256 } from './hash.js';
|
|
4
|
+
import { initSodium } from './sodium.js';
|
|
5
|
+
const DM_INFO = Buffer.from('clawpeers-dm-v0.1', 'utf8');
|
|
6
|
+
export async function deriveThreadKey(senderSecretCurve25519B64, recipientPublicCurve25519B64, threadId) {
|
|
7
|
+
const sodium = await initSodium();
|
|
8
|
+
const shared = sodium.crypto_scalarmult(fromBase64(senderSecretCurve25519B64), fromBase64(recipientPublicCurve25519B64));
|
|
9
|
+
const threadKey = hkdfSha256(shared, Buffer.from(threadId, 'utf8'), DM_INFO, sodium.crypto_secretbox_KEYBYTES);
|
|
10
|
+
return toBase64(threadKey);
|
|
11
|
+
}
|
|
12
|
+
export async function encryptDm(plaintext, threadKeyB64) {
|
|
13
|
+
const sodium = await initSodium();
|
|
14
|
+
const nonceBytes = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
|
|
15
|
+
const cipher = sodium.crypto_secretbox_easy(plaintext, nonceBytes, fromBase64(threadKeyB64));
|
|
16
|
+
return {
|
|
17
|
+
nonce: toBase64(nonceBytes),
|
|
18
|
+
ciphertext: toBase64(cipher),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function decryptDm(nonceB64, ciphertextB64, threadKeyB64) {
|
|
22
|
+
const sodium = await initSodium();
|
|
23
|
+
const plaintext = sodium.crypto_secretbox_open_easy(fromBase64(ciphertextB64), fromBase64(nonceB64), fromBase64(threadKeyB64));
|
|
24
|
+
return Buffer.from(plaintext).toString('utf8');
|
|
25
|
+
}
|
|
26
|
+
export function newThreadId() {
|
|
27
|
+
return randomUUID();
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=dm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm.js","sourceRoot":"","sources":["../../src/crypto/dm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,yBAAiC,EACjC,4BAAoC,EACpC,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CACrC,UAAU,CAAC,yBAAyB,CAAC,EACrC,UAAU,CAAC,4BAA4B,CAAC,CACzC,CAAC;IACF,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC/G,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB,EAAE,YAAoB;IACrE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;IAC7F,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QAC3B,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,aAAqB,EAAE,YAAoB;IAC3F,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,0BAA0B,CACjD,UAAU,CAAC,aAAa,CAAC,EACzB,UAAU,CAAC,QAAQ,CAAC,EACpB,UAAU,CAAC,YAAY,CAAC,CACzB,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAE5D;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,SAAK,GACV,UAAU,CAEZ"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createHash, hkdfSync } from 'node:crypto';
|
|
2
|
+
export function sha256(data) {
|
|
3
|
+
return new Uint8Array(createHash('sha256').update(data).digest());
|
|
4
|
+
}
|
|
5
|
+
export function hkdfSha256(ikm, salt, info, length = 32) {
|
|
6
|
+
return new Uint8Array(hkdfSync('sha256', ikm, salt, info, length));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,MAAM,CAAC,IAAyB;IAC9C,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,GAAe,EACf,IAAgB,EAChB,IAAgB,EAChB,MAAM,GAAG,EAAE;IAEX,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IdentityKeyBundle } from '../types/index.js';
|
|
2
|
+
export declare function generateIdentity(): Promise<IdentityKeyBundle>;
|
|
3
|
+
export declare function signUtf8(challenge: string, signingSecretKeyB64: string): Promise<string>;
|
|
4
|
+
export declare function verifyUtf8(challenge: string, signatureB64: string, signingPublicKeyB64: string): Promise<boolean>;
|
|
5
|
+
export declare function newNonce(): string;
|
|
6
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAcnE;AAED,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9F;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { fromBase64, toBase64, toBase64Url } from './base64.js';
|
|
3
|
+
import { sha256 } from './hash.js';
|
|
4
|
+
import { initSodium } from './sodium.js';
|
|
5
|
+
export async function generateIdentity() {
|
|
6
|
+
const sodium = await initSodium();
|
|
7
|
+
const signing = sodium.crypto_sign_keypair();
|
|
8
|
+
const encPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signing.publicKey);
|
|
9
|
+
const encSecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519(signing.privateKey);
|
|
10
|
+
const nodeId = toBase64Url(sha256(signing.publicKey));
|
|
11
|
+
return {
|
|
12
|
+
nodeId,
|
|
13
|
+
signingPublicKey: toBase64(signing.publicKey),
|
|
14
|
+
signingSecretKey: toBase64(signing.privateKey),
|
|
15
|
+
encryptionPublicKey: toBase64(encPublicKey),
|
|
16
|
+
encryptionSecretKey: toBase64(encSecretKey),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export async function signUtf8(challenge, signingSecretKeyB64) {
|
|
20
|
+
const sodium = await initSodium();
|
|
21
|
+
const signature = sodium.crypto_sign_detached(challenge, fromBase64(signingSecretKeyB64));
|
|
22
|
+
return toBase64(signature);
|
|
23
|
+
}
|
|
24
|
+
export async function verifyUtf8(challenge, signatureB64, signingPublicKeyB64) {
|
|
25
|
+
const sodium = await initSodium();
|
|
26
|
+
return sodium.crypto_sign_verify_detached(fromBase64(signatureB64), challenge, fromBase64(signingPublicKeyB64));
|
|
27
|
+
}
|
|
28
|
+
export function newNonce() {
|
|
29
|
+
return randomUUID();
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;IAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,oCAAoC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,MAAM,CAAC,oCAAoC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtD,OAAO;QACL,MAAM;QACN,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;QAC7C,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC;QAC9C,mBAAmB,EAAE,QAAQ,CAAC,YAAY,CAAC;QAC3C,mBAAmB,EAAE,QAAQ,CAAC,YAAY,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,SAAiB,EAAE,mBAA2B;IAC3E,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAAC,SAAS,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC1F,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAAiB,EACjB,YAAoB,EACpB,mBAA2B;IAE3B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,2BAA2B,CACvC,UAAU,CAAC,YAAY,CAAC,EACxB,SAAS,EACT,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sodium.d.ts","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAIxC,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,MAAM,CAAC,CAMzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sodium.js","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,KAAK,CAAC;QACnB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/protocol/canonical.ts"],"names":[],"mappings":"AAgBA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function sortValue(value) {
|
|
2
|
+
if (Array.isArray(value)) {
|
|
3
|
+
return value.map((entry) => sortValue(entry));
|
|
4
|
+
}
|
|
5
|
+
if (value !== null && typeof value === 'object') {
|
|
6
|
+
const entries = Object.entries(value)
|
|
7
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
8
|
+
.map(([key, nested]) => [key, sortValue(nested)]);
|
|
9
|
+
return Object.fromEntries(entries);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
export function canonicalizeJson(value) {
|
|
14
|
+
return JSON.stringify(sortValue(value));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/protocol/canonical.ts"],"names":[],"mappings":"AAAA,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aAC7D,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aACtC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAEpD,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Envelope, UnsignedEnvelope } from '../types/index.js';
|
|
2
|
+
export declare function buildSignatureInput<TPayload extends Record<string, unknown>>(envelope: UnsignedEnvelope<TPayload>): Uint8Array;
|
|
3
|
+
export declare function signEnvelope<TPayload extends Record<string, unknown>>(envelope: UnsignedEnvelope<TPayload>, signingSecretKeyB64: string): Promise<Envelope<TPayload>>;
|
|
4
|
+
export declare function verifyEnvelope<TPayload extends Record<string, unknown>>(envelope: Envelope<TPayload>, signingPublicKeyB64: string): Promise<boolean>;
|
|
5
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/protocol/envelope.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAIpE,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACnC,UAAU,CAGZ;AAED,wBAAsB,YAAY,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACpC,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAW7B;AAED,wBAAsB,cAAc,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3E,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { fromBase64, toBase64 } from '../crypto/base64.js';
|
|
2
|
+
import { sha256 } from '../crypto/hash.js';
|
|
3
|
+
import { initSodium } from '../crypto/sodium.js';
|
|
4
|
+
import { canonicalizeJson } from './canonical.js';
|
|
5
|
+
import { envelopeSchema } from './schemas.js';
|
|
6
|
+
export function buildSignatureInput(envelope) {
|
|
7
|
+
const canonical = canonicalizeJson(envelope);
|
|
8
|
+
return sha256(Buffer.from(canonical, 'utf8'));
|
|
9
|
+
}
|
|
10
|
+
export async function signEnvelope(envelope, signingSecretKeyB64) {
|
|
11
|
+
const sodium = await initSodium();
|
|
12
|
+
const signature = sodium.crypto_sign_detached(buildSignatureInput(envelope), fromBase64(signingSecretKeyB64));
|
|
13
|
+
return {
|
|
14
|
+
...envelope,
|
|
15
|
+
sig: toBase64(signature),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export async function verifyEnvelope(envelope, signingPublicKeyB64) {
|
|
19
|
+
const parsed = envelopeSchema.safeParse(envelope);
|
|
20
|
+
if (!parsed.success) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const sodium = await initSodium();
|
|
24
|
+
const { sig, ...unsignedEnvelope } = envelope;
|
|
25
|
+
return sodium.crypto_sign_verify_detached(fromBase64(sig), buildSignatureInput(unsignedEnvelope), fromBase64(signingPublicKeyB64));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/protocol/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,UAAU,mBAAmB,CACjC,QAAoC;IAEpC,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAoC,EACpC,mBAA2B;IAE3B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAC3C,mBAAmB,CAAC,QAAQ,CAAC,EAC7B,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;IAEF,OAAO;QACL,GAAG,QAAQ;QACX,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA4B,EAC5B,mBAA2B;IAE3B,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,EAAE,GAAG,EAAE,GAAG,gBAAgB,EAAE,GAAG,QAAQ,CAAC;IAE9C,OAAO,MAAM,CAAC,2BAA2B,CACvC,UAAU,CAAC,GAAG,CAAC,EACf,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|