@oxyhq/core 4.0.0 → 5.0.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.
Files changed (119) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +6 -18
  3. package/dist/cjs/OxyServices.base.js +0 -21
  4. package/dist/cjs/crypto/keyManager.js +7 -7
  5. package/dist/cjs/crypto/polyfill.js +6 -5
  6. package/dist/cjs/crypto/signatureService.js +44 -220
  7. package/dist/cjs/i18n/locales/en-US.json +391 -17
  8. package/dist/cjs/i18n/locales/es-ES.json +391 -17
  9. package/dist/cjs/i18n/locales/locales/en-US.json +391 -17
  10. package/dist/cjs/i18n/locales/locales/es-ES.json +391 -17
  11. package/dist/cjs/index.js +4 -8
  12. package/dist/cjs/mixins/OxyServices.accounts.js +54 -0
  13. package/dist/cjs/mixins/OxyServices.assets.js +2 -2
  14. package/dist/cjs/mixins/OxyServices.auth.js +3 -3
  15. package/dist/cjs/mixins/OxyServices.civic.js +3 -3
  16. package/dist/cjs/mixins/OxyServices.language.js +2 -2
  17. package/dist/cjs/mixins/OxyServices.utility.js +7 -95
  18. package/dist/cjs/utils/cacheKey.js +17 -19
  19. package/dist/cjs/utils/deviceManager.js +2 -2
  20. package/dist/cjs/utils/platform.js +0 -14
  21. package/dist/esm/.tsbuildinfo +1 -1
  22. package/dist/esm/HttpService.js +6 -18
  23. package/dist/esm/OxyServices.base.js +0 -21
  24. package/dist/esm/crypto/keyManager.js +4 -4
  25. package/dist/esm/crypto/polyfill.js +5 -4
  26. package/dist/esm/crypto/signatureService.js +39 -214
  27. package/dist/esm/i18n/locales/en-US.json +391 -17
  28. package/dist/esm/i18n/locales/es-ES.json +391 -17
  29. package/dist/esm/i18n/locales/locales/en-US.json +391 -17
  30. package/dist/esm/i18n/locales/locales/es-ES.json +391 -17
  31. package/dist/esm/index.js +1 -2
  32. package/dist/esm/mixins/OxyServices.accounts.js +54 -0
  33. package/dist/esm/mixins/OxyServices.assets.js +1 -1
  34. package/dist/esm/mixins/OxyServices.auth.js +1 -1
  35. package/dist/esm/mixins/OxyServices.civic.js +3 -3
  36. package/dist/esm/mixins/OxyServices.language.js +1 -1
  37. package/dist/esm/mixins/OxyServices.utility.js +6 -94
  38. package/dist/esm/utils/cacheKey.js +17 -19
  39. package/dist/esm/utils/deviceManager.js +1 -1
  40. package/dist/esm/utils/platform.js +0 -12
  41. package/dist/types/.tsbuildinfo +1 -1
  42. package/dist/types/HttpService.d.ts +3 -6
  43. package/dist/types/OxyServices.base.d.ts +0 -17
  44. package/dist/types/crypto/polyfill.d.ts +2 -2
  45. package/dist/types/crypto/signatureService.d.ts +18 -84
  46. package/dist/types/index.d.ts +3 -4
  47. package/dist/types/mixins/OxyServices.accounts.d.ts +57 -5
  48. package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
  49. package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
  50. package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
  51. package/dist/types/mixins/OxyServices.auth.d.ts +0 -2
  52. package/dist/types/mixins/OxyServices.civic.d.ts +3 -5
  53. package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
  54. package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
  55. package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
  56. package/dist/types/mixins/OxyServices.features.d.ts +0 -2
  57. package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -2
  58. package/dist/types/mixins/OxyServices.identity.d.ts +8 -5
  59. package/dist/types/mixins/OxyServices.language.d.ts +0 -2
  60. package/dist/types/mixins/OxyServices.links.d.ts +0 -2
  61. package/dist/types/mixins/OxyServices.location.d.ts +0 -2
  62. package/dist/types/mixins/OxyServices.nodes.d.ts +0 -44
  63. package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
  64. package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
  65. package/dist/types/mixins/OxyServices.redirect.d.ts +0 -2
  66. package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
  67. package/dist/types/mixins/OxyServices.security.d.ts +0 -2
  68. package/dist/types/mixins/OxyServices.silent.d.ts +0 -2
  69. package/dist/types/mixins/OxyServices.sso.d.ts +0 -2
  70. package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
  71. package/dist/types/mixins/OxyServices.user.d.ts +0 -2
  72. package/dist/types/mixins/OxyServices.utility.d.ts +0 -32
  73. package/dist/types/server/auth.d.ts +0 -6
  74. package/dist/types/server/index.d.ts +1 -1
  75. package/dist/types/utils/cacheKey.d.ts +6 -7
  76. package/dist/types/utils/platform.d.ts +0 -8
  77. package/package.json +4 -7
  78. package/src/HttpService.ts +6 -22
  79. package/src/OxyServices.base.ts +0 -23
  80. package/src/__tests__/httpServiceCache.test.ts +0 -19
  81. package/src/crypto/__tests__/keyManager.atomicity.test.ts +2 -1
  82. package/src/crypto/__tests__/keyManager.test.ts +9 -7
  83. package/src/crypto/__tests__/signChallengeShared.test.ts +2 -1
  84. package/src/crypto/__tests__/signedRecord.test.ts +37 -150
  85. package/src/crypto/keyManager.ts +28 -17
  86. package/src/crypto/polyfill.ts +5 -4
  87. package/src/crypto/signatureService.ts +67 -255
  88. package/src/i18n/locales/en-US.json +391 -17
  89. package/src/i18n/locales/es-ES.json +391 -17
  90. package/src/index.ts +3 -3
  91. package/src/mixins/OxyServices.accounts.ts +91 -3
  92. package/src/mixins/OxyServices.assets.ts +1 -1
  93. package/src/mixins/OxyServices.auth.ts +1 -1
  94. package/src/mixins/OxyServices.civic.ts +6 -17
  95. package/src/mixins/OxyServices.identity.ts +8 -2
  96. package/src/mixins/OxyServices.language.ts +1 -1
  97. package/src/mixins/OxyServices.nodes.ts +1 -12
  98. package/src/mixins/OxyServices.utility.ts +6 -119
  99. package/src/mixins/__tests__/OxyServices.civic.test.ts +2 -2
  100. package/src/mixins/__tests__/accounts.test.ts +70 -0
  101. package/src/server/auth.ts +0 -7
  102. package/src/server/index.ts +0 -1
  103. package/src/utils/__tests__/cacheKey.test.ts +0 -0
  104. package/src/utils/cacheKey.ts +16 -21
  105. package/src/utils/deviceManager.ts +1 -1
  106. package/src/utils/platform.ts +0 -14
  107. package/dist/cjs/crypto/canonicalJson.js +0 -107
  108. package/dist/cjs/utils/platformCrypto.js +0 -165
  109. package/dist/cjs/utils/platformCrypto.native.js +0 -123
  110. package/dist/esm/crypto/canonicalJson.js +0 -104
  111. package/dist/esm/utils/platformCrypto.js +0 -125
  112. package/dist/esm/utils/platformCrypto.native.js +0 -80
  113. package/dist/types/crypto/canonicalJson.d.ts +0 -44
  114. package/dist/types/utils/platformCrypto.d.ts +0 -87
  115. package/dist/types/utils/platformCrypto.native.d.ts +0 -54
  116. package/src/crypto/__tests__/canonicalJson.test.ts +0 -116
  117. package/src/crypto/canonicalJson.ts +0 -120
  118. package/src/utils/platformCrypto.native.ts +0 -101
  119. package/src/utils/platformCrypto.ts +0 -145
@@ -1,108 +1,26 @@
1
1
  /**
2
- * Signature Service - ECDSA Digital Signatures
3
- *
4
- * Handles signing and verification of messages using ECDSA secp256k1.
5
- * Used for authenticating requests and proving identity ownership.
2
+ * Signature Service - ECDSA Digital Signatures (device-key bound)
3
+ *
4
+ * Handles signing and verification of messages with the user's DEVICE identity
5
+ * key (read from {@link KeyManager} / secure storage). All cryptography itself —
6
+ * canonical signing input, SHA-256, secp256k1 sign/verify, envelope assembly —
7
+ * is delegated to `@oxyhq/protocol`; this service only resolves the key from
8
+ * storage and orchestrates the protocol primitives.
6
9
  */
7
10
 
8
- import { ec as EC } from 'elliptic';
9
11
  import type { SignedRecordEnvelope } from '@oxyhq/contracts';
12
+ import {
13
+ signEnvelope,
14
+ signMessage,
15
+ verifySignature,
16
+ sha256,
17
+ loadExpoCrypto,
18
+ loadNodeCrypto,
19
+ isReactNative,
20
+ isNodeJS,
21
+ } from '@oxyhq/protocol';
10
22
  import { KeyManager } from './keyManager';
11
- import { canonicalize } from './canonicalJson';
12
- import { isReactNative, isNodeJS } from '../utils/platform';
13
- import { loadExpoCrypto, loadNodeCrypto } from '../utils/platformCrypto';
14
23
  import { logger } from '../utils/loggerUtils';
15
- import { isDev } from '../shared/utils/debugUtils';
16
-
17
- const ec = new EC('secp256k1');
18
-
19
- /**
20
- * The signing-input portion of a {@link SignedRecordEnvelope}: every field
21
- * EXCEPT the `publicKey` and `signature`. Both the client (when signing) and
22
- * the server (when verifying) canonicalize exactly these fields, so they agree
23
- * on the bytes that the signature covers.
24
- *
25
- * The v2 chain fields (`seq`/`prev`/`collection`/`rkey`) are optional: a v1
26
- * envelope omits them and is signed over only the base fields; a v2 envelope
27
- * carries them and includes them in the signed bytes.
28
- */
29
- export type SignedRecordSigningFields = Pick<
30
- SignedRecordEnvelope,
31
- 'version' | 'type' | 'subject' | 'issuer' | 'record' | 'issuedAt'
32
- > &
33
- Partial<Pick<SignedRecordEnvelope, 'seq' | 'prev' | 'collection' | 'rkey'>>;
34
-
35
- /**
36
- * Compute the canonical signing input for a signed-record envelope.
37
- *
38
- * This is the single definition of "what the signature covers". `@oxyhq/core`
39
- * (client signing) and `@oxyhq/api` (server verification) both call this, so a
40
- * record signed by a client and verified by the server cannot drift.
41
- *
42
- * - **v1**: the canonical JSON of `{version, type, subject, issuer, record,
43
- * issuedAt}` — BYTE-IDENTICAL to the original scheme, so every signature
44
- * already in production keeps verifying.
45
- * - **v2**: the canonical JSON additionally includes the hash-chain fields
46
- * `{seq, prev, collection, rkey}`. Because {@link canonicalize} sorts keys,
47
- * the on-the-wire field order is irrelevant; the resulting canonical key
48
- * order is `collection, issuedAt, issuer, prev, record, rkey, seq, subject,
49
- * type, version`. `prev` is `null` at genesis (serialized as `null`, not
50
- * omitted), so it is always part of the signed bytes.
51
- */
52
- export function signedRecordSigningInput(fields: SignedRecordSigningFields): string {
53
- const { version, type, subject, issuer, record, issuedAt } = fields;
54
- if (version === 2) {
55
- const { seq, prev, collection, rkey } = fields;
56
- return canonicalize({ version, type, subject, issuer, record, issuedAt, seq, prev, collection, rkey });
57
- }
58
- return canonicalize({ version, type, subject, issuer, record, issuedAt });
59
- }
60
-
61
- /**
62
- * Compute the `recordId` (content address) of a signed record: the SHA-256 hex
63
- * digest of its canonical {@link signedRecordSigningInput}.
64
- *
65
- * Deterministic and stable across runtimes (it reuses the same canonicalization
66
- * + SHA-256 the signature itself is built on). The recordId is what `prev`
67
- * references in the per-subject hash chain, so `@oxyhq/core` (client) and
68
- * `@oxyhq/api` (server) MUST compute it identically — both call this function.
69
- * It is taken over the SIGNING input (excluding `publicKey`/`signature`), so it
70
- * is a pure content address of the record's meaning, independent of who signed.
71
- */
72
- export async function computeRecordId(fields: SignedRecordSigningFields): Promise<string> {
73
- return sha256(signedRecordSigningInput(fields));
74
- }
75
-
76
- /**
77
- * Compute SHA-256 hash of a string
78
- */
79
- async function sha256(message: string): Promise<string> {
80
- // In React Native, use expo-crypto
81
- if (isReactNative()) {
82
- const Crypto = await loadExpoCrypto();
83
- return Crypto.digestStringAsync(
84
- Crypto.CryptoDigestAlgorithm.SHA256,
85
- message
86
- );
87
- }
88
-
89
- if (isNodeJS()) {
90
- try {
91
- const nodeCrypto = await loadNodeCrypto();
92
- return nodeCrypto.createHash('sha256').update(message).digest('hex');
93
- } catch (error) {
94
- // Node crypto failed to load — log and fall through to Web Crypto API
95
- logger.warn('[oxy.crypto] Node crypto unavailable, falling back to Web Crypto', { component: 'SignatureService' }, error);
96
- }
97
- }
98
-
99
- // Browser: use Web Crypto API
100
- const encoder = new TextEncoder();
101
- const data = encoder.encode(message);
102
- const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', data);
103
- const hashArray = Array.from(new Uint8Array(hashBuffer));
104
- return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
105
- }
106
24
 
107
25
  export interface SignedMessage {
108
26
  message: string;
@@ -158,78 +76,15 @@ export class SignatureService {
158
76
  }
159
77
 
160
78
  /**
161
- * Sign a message using the stored private key
79
+ * Sign a message using the stored device private key
162
80
  * Returns the signature in DER format (hex encoded)
163
81
  */
164
82
  static async sign(message: string): Promise<string> {
165
- const keyPair = await KeyManager.getKeyPairObject();
166
- if (!keyPair) {
83
+ const privateKey = await KeyManager.getPrivateKey();
84
+ if (!privateKey) {
167
85
  throw new Error('No identity found. Please create or import an identity first.');
168
86
  }
169
-
170
- const messageHash = await sha256(message);
171
- const signature = keyPair.sign(messageHash);
172
- return signature.toDER('hex');
173
- }
174
-
175
- /**
176
- * Sign a message with an explicit private key (without storing)
177
- * Useful for one-time operations or testing
178
- */
179
- static async signWithKey(message: string, privateKey: string): Promise<string> {
180
- const keyPair = ec.keyFromPrivate(privateKey);
181
- const messageHash = await sha256(message);
182
- const signature = keyPair.sign(messageHash);
183
- return signature.toDER('hex');
184
- }
185
-
186
- /**
187
- * Verify a signature against a message and public key
188
- *
189
- * Returns false on any error (invalid signature, malformed input, etc.).
190
- * Errors are logged at debug level so they're available when troubleshooting
191
- * signature mismatches but don't surface to the caller.
192
- */
193
- static async verify(message: string, signature: string, publicKey: string): Promise<boolean> {
194
- try {
195
- const key = ec.keyFromPublic(publicKey, 'hex');
196
- const messageHash = await sha256(message);
197
- return key.verify(messageHash, signature);
198
- } catch (error) {
199
- if (isDev()) {
200
- logger.debug('[oxy.crypto] verify() returned false', { component: 'SignatureService' }, error);
201
- }
202
- return false;
203
- }
204
- }
205
-
206
- /**
207
- * Synchronous verification (for Node.js backend)
208
- * Uses crypto module directly for hashing
209
- * Note: This method should only be used in Node.js environments
210
- */
211
- static verifySync(message: string, signature: string, publicKey: string): boolean {
212
- try {
213
- if (!isNodeJS()) {
214
- // In React Native, use async verify instead
215
- throw new Error('verifySync should only be used in Node.js. Use verify() in React Native.');
216
- }
217
- // Intentionally using Function constructor here: this method is synchronous by design
218
- // (Node.js backend hot-path) so we cannot use `await import()`. The Function constructor
219
- // prevents Metro/bundlers from statically resolving the require. This is acceptable because
220
- // verifySync is gated by isNodeJS() and will never execute in browser/RN environments.
221
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
222
- const getCrypto = new Function('return require("crypto")');
223
- const crypto = getCrypto();
224
- const key = ec.keyFromPublic(publicKey, 'hex');
225
- const messageHash = crypto.createHash('sha256').update(message).digest('hex');
226
- return key.verify(messageHash, signature);
227
- } catch (error) {
228
- if (isDev()) {
229
- logger.debug('[oxy.crypto] verifySync() returned false', { component: 'SignatureService' }, error);
230
- }
231
- return false;
232
- }
87
+ return signMessage(message, privateKey);
233
88
  }
234
89
 
235
90
  /**
@@ -271,7 +126,7 @@ export class SignatureService {
271
126
 
272
127
  // Verify signature
273
128
  const messageWithTimestamp = `${message}:${timestamp}`;
274
- return SignatureService.verify(messageWithTimestamp, signature, publicKey);
129
+ return verifySignature(messageWithTimestamp, signature, publicKey);
275
130
  }
276
131
 
277
132
  /**
@@ -303,9 +158,10 @@ export class SignatureService {
303
158
  * Mirrors {@link signChallenge} exactly — same message format
304
159
  * (`auth:${publicKey}:${challenge}:${timestamp}`) so the server verification
305
160
  * path is unchanged — but sources the shared public/private key from
306
- * `KeyManager` and signs with `signWithKey`. Used by "Sign in with Oxy"
307
- * same-device shared-keychain SSO (Mechanism A): a sibling native app proves
308
- * control of the shared identity to mint its own session.
161
+ * `KeyManager` and signs with the protocol's explicit-key {@link signMessage}.
162
+ * Used by "Sign in with Oxy" same-device shared-keychain SSO (Mechanism A): a
163
+ * sibling native app proves control of the shared identity to mint its own
164
+ * session.
309
165
  *
310
166
  * Throws if no shared identity exists (native-only; the shared keychain is
311
167
  * unavailable on web).
@@ -319,7 +175,7 @@ export class SignatureService {
319
175
 
320
176
  const timestamp = Date.now();
321
177
  const message = `auth:${publicKey}:${challenge}:${timestamp}`;
322
- const signature = await SignatureService.signWithKey(message, privateKey);
178
+ const signature = await signMessage(message, privateKey);
323
179
 
324
180
  return {
325
181
  challenge: signature,
@@ -345,7 +201,7 @@ export class SignatureService {
345
201
  }
346
202
 
347
203
  const message = `auth:${publicKey}:${originalChallenge}:${timestamp}`;
348
- return SignatureService.verify(message, signature, publicKey);
204
+ return verifySignature(message, signature, publicKey);
349
205
  }
350
206
 
351
207
  /**
@@ -385,12 +241,12 @@ export class SignatureService {
385
241
  }
386
242
 
387
243
  const timestamp = Date.now();
388
-
244
+
389
245
  // Create canonical string representation
390
246
  const sortedKeys = Object.keys(data).sort();
391
247
  const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
392
248
  const canonicalString = canonicalParts.join('|');
393
-
249
+
394
250
  const message = `request:${publicKey}:${timestamp}:${canonicalString}`;
395
251
  const signature = await SignatureService.sign(message);
396
252
 
@@ -406,9 +262,11 @@ export class SignatureService {
406
262
  *
407
263
  * The envelope is self-issued: `issuer` equals `subject` (the signer's DID).
408
264
  * The signature covers the canonical JSON of every field EXCEPT `publicKey`
409
- * and `signature` (see {@link signedRecordSigningInput}); `alg` is
410
- * `ES256K-DER-SHA256` (secp256k1 over the SHA-256 of the canonical bytes,
411
- * DER-encoded), the same scheme this service uses everywhere else.
265
+ * and `signature`; `alg` is `ES256K-DER-SHA256` (secp256k1 over the SHA-256 of
266
+ * the canonical bytes, DER-encoded). The cryptography is delegated to the
267
+ * protocol's {@link signEnvelope}, which derives the (uncompressed-hex)
268
+ * `publicKey` from the stored device key — identical to the registered
269
+ * verification method.
412
270
  *
413
271
  * Requires a stored identity (native secure storage); throws if none exists.
414
272
  *
@@ -421,35 +279,22 @@ export class SignatureService {
421
279
  subject: string,
422
280
  record: Record<string, unknown>,
423
281
  ): Promise<SignedRecordEnvelope> {
424
- const publicKey = await KeyManager.getPublicKey();
425
- if (!publicKey) {
282
+ const privateKey = await KeyManager.getPrivateKey();
283
+ if (!privateKey) {
426
284
  throw new Error('No identity found. Please create or import an identity first.');
427
285
  }
428
286
 
429
- const version = 1 as const;
430
- const issuer = subject;
431
- const issuedAt = Date.now();
432
- const signingInput = signedRecordSigningInput({
433
- version,
434
- type,
435
- subject,
436
- issuer,
437
- record,
438
- issuedAt,
439
- });
440
- const signature = await SignatureService.sign(signingInput);
441
-
442
- return {
443
- version,
444
- type,
445
- subject,
446
- issuer,
447
- record,
448
- issuedAt,
449
- publicKey,
450
- alg: 'ES256K-DER-SHA256',
451
- signature,
452
- };
287
+ return signEnvelope(
288
+ {
289
+ version: 1,
290
+ type,
291
+ subject,
292
+ issuer: subject,
293
+ record,
294
+ issuedAt: Date.now(),
295
+ },
296
+ privateKey,
297
+ );
453
298
  }
454
299
 
455
300
  /**
@@ -457,8 +302,8 @@ export class SignatureService {
457
302
  * fields.
458
303
  *
459
304
  * Identical to {@link signRecord} (self-issued: `issuer === subject`; same
460
- * `ES256K-DER-SHA256` scheme over {@link signedRecordSigningInput}) but
461
- * `version` is `2` and the signed bytes additionally cover the chain fields:
305
+ * `ES256K-DER-SHA256` scheme) but `version` is `2` and the signed bytes
306
+ * additionally cover the chain fields:
462
307
  *
463
308
  * @param type - The record category.
464
309
  * @param subject - The subject DID the record is about (also the issuer).
@@ -478,60 +323,27 @@ export class SignatureService {
478
323
  record: Record<string, unknown>,
479
324
  chain: { seq: number; prev: string | null; collection: string; rkey: string },
480
325
  ): Promise<SignedRecordEnvelope> {
481
- const publicKey = await KeyManager.getPublicKey();
482
- if (!publicKey) {
326
+ const privateKey = await KeyManager.getPrivateKey();
327
+ if (!privateKey) {
483
328
  throw new Error('No identity found. Please create or import an identity first.');
484
329
  }
485
330
 
486
- const version = 2 as const;
487
- const issuer = subject;
488
- const issuedAt = Date.now();
489
331
  const { seq, prev, collection, rkey } = chain;
490
- const signingInput = signedRecordSigningInput({
491
- version,
492
- type,
493
- subject,
494
- issuer,
495
- record,
496
- issuedAt,
497
- seq,
498
- prev,
499
- collection,
500
- rkey,
501
- });
502
- const signature = await SignatureService.sign(signingInput);
503
-
504
- return {
505
- version,
506
- type,
507
- subject,
508
- issuer,
509
- record,
510
- issuedAt,
511
- seq,
512
- prev,
513
- collection,
514
- rkey,
515
- publicKey,
516
- alg: 'ES256K-DER-SHA256',
517
- signature,
518
- };
519
- }
520
-
521
- /**
522
- * Verify a signed-record envelope: recompute the canonical signing input from
523
- * the envelope's own fields and check the signature against the envelope's
524
- * `publicKey`.
525
- *
526
- * Note: this confirms the signature is internally consistent with the
527
- * embedded `publicKey`. It does NOT establish that `publicKey` is an
528
- * authorized verification method for `subject` — that authorization check is
529
- * the server's responsibility (it asserts the key is a current verification
530
- * method on the subject's DID).
531
- */
532
- static async verifyRecord(envelope: SignedRecordEnvelope): Promise<boolean> {
533
- const signingInput = signedRecordSigningInput(envelope);
534
- return SignatureService.verify(signingInput, envelope.signature, envelope.publicKey);
332
+ return signEnvelope(
333
+ {
334
+ version: 2,
335
+ type,
336
+ subject,
337
+ issuer: subject,
338
+ record,
339
+ issuedAt: Date.now(),
340
+ seq,
341
+ prev,
342
+ collection,
343
+ rkey,
344
+ },
345
+ privateKey,
346
+ );
535
347
  }
536
348
  }
537
349