@oxyhq/core 3.11.0 → 3.13.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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/crypto/signatureService.js +88 -2
- package/dist/cjs/index.js +19 -4
- package/dist/cjs/mixins/OxyServices.civic.js +611 -0
- package/dist/cjs/mixins/index.js +3 -0
- package/dist/cjs/utils/profileLinks.js +63 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/crypto/signatureService.js +87 -2
- package/dist/esm/index.js +11 -1
- package/dist/esm/mixins/OxyServices.civic.js +605 -0
- package/dist/esm/mixins/index.js +3 -0
- package/dist/esm/utils/profileLinks.js +60 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/crypto/signatureService.d.ts +54 -3
- package/dist/types/index.d.ts +5 -1
- package/dist/types/mixins/OxyServices.civic.d.ts +512 -0
- package/dist/types/mixins/index.d.ts +2 -1
- package/dist/types/utils/profileLinks.d.ts +44 -0
- package/package.json +2 -2
- package/src/crypto/__tests__/signedRecord.test.ts +221 -1
- package/src/crypto/signatureService.ts +102 -3
- package/src/index.ts +29 -1
- package/src/mixins/OxyServices.civic.ts +956 -0
- package/src/mixins/__tests__/OxyServices.civic.test.ts +1097 -0
- package/src/mixins/index.ts +4 -0
- package/src/utils/__tests__/profileLinks.test.ts +180 -0
- package/src/utils/profileLinks.ts +91 -0
|
@@ -16,15 +16,42 @@ const ec = new EC('secp256k1');
|
|
|
16
16
|
/**
|
|
17
17
|
* Compute the canonical signing input for a signed-record envelope.
|
|
18
18
|
*
|
|
19
|
-
* This is the single definition of "what the signature covers"
|
|
20
|
-
* JSON of `{version, type, subject, issuer, record, issuedAt}`. `@oxyhq/core`
|
|
19
|
+
* This is the single definition of "what the signature covers". `@oxyhq/core`
|
|
21
20
|
* (client signing) and `@oxyhq/api` (server verification) both call this, so a
|
|
22
21
|
* record signed by a client and verified by the server cannot drift.
|
|
22
|
+
*
|
|
23
|
+
* - **v1**: the canonical JSON of `{version, type, subject, issuer, record,
|
|
24
|
+
* issuedAt}` — BYTE-IDENTICAL to the original scheme, so every signature
|
|
25
|
+
* already in production keeps verifying.
|
|
26
|
+
* - **v2**: the canonical JSON additionally includes the hash-chain fields
|
|
27
|
+
* `{seq, prev, collection, rkey}`. Because {@link canonicalize} sorts keys,
|
|
28
|
+
* the on-the-wire field order is irrelevant; the resulting canonical key
|
|
29
|
+
* order is `collection, issuedAt, issuer, prev, record, rkey, seq, subject,
|
|
30
|
+
* type, version`. `prev` is `null` at genesis (serialized as `null`, not
|
|
31
|
+
* omitted), so it is always part of the signed bytes.
|
|
23
32
|
*/
|
|
24
33
|
export function signedRecordSigningInput(fields) {
|
|
25
34
|
const { version, type, subject, issuer, record, issuedAt } = fields;
|
|
35
|
+
if (version === 2) {
|
|
36
|
+
const { seq, prev, collection, rkey } = fields;
|
|
37
|
+
return canonicalize({ version, type, subject, issuer, record, issuedAt, seq, prev, collection, rkey });
|
|
38
|
+
}
|
|
26
39
|
return canonicalize({ version, type, subject, issuer, record, issuedAt });
|
|
27
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Compute the `recordId` (content address) of a signed record: the SHA-256 hex
|
|
43
|
+
* digest of its canonical {@link signedRecordSigningInput}.
|
|
44
|
+
*
|
|
45
|
+
* Deterministic and stable across runtimes (it reuses the same canonicalization
|
|
46
|
+
* + SHA-256 the signature itself is built on). The recordId is what `prev`
|
|
47
|
+
* references in the per-subject hash chain, so `@oxyhq/core` (client) and
|
|
48
|
+
* `@oxyhq/api` (server) MUST compute it identically — both call this function.
|
|
49
|
+
* It is taken over the SIGNING input (excluding `publicKey`/`signature`), so it
|
|
50
|
+
* is a pure content address of the record's meaning, independent of who signed.
|
|
51
|
+
*/
|
|
52
|
+
export async function computeRecordId(fields) {
|
|
53
|
+
return sha256(signedRecordSigningInput(fields));
|
|
54
|
+
}
|
|
28
55
|
/**
|
|
29
56
|
* Compute SHA-256 hash of a string
|
|
30
57
|
*/
|
|
@@ -340,6 +367,64 @@ export class SignatureService {
|
|
|
340
367
|
signature,
|
|
341
368
|
};
|
|
342
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Build a signed-record envelope (v2) carrying the per-subject hash-chain
|
|
372
|
+
* fields.
|
|
373
|
+
*
|
|
374
|
+
* Identical to {@link signRecord} (self-issued: `issuer === subject`; same
|
|
375
|
+
* `ES256K-DER-SHA256` scheme over {@link signedRecordSigningInput}) but
|
|
376
|
+
* `version` is `2` and the signed bytes additionally cover the chain fields:
|
|
377
|
+
*
|
|
378
|
+
* @param type - The record category.
|
|
379
|
+
* @param subject - The subject DID the record is about (also the issuer).
|
|
380
|
+
* @param record - The arbitrary record payload to attest to.
|
|
381
|
+
* @param chain - The hash-chain coordinates:
|
|
382
|
+
* - `seq` — strictly-increasing sequence number for this subject's chain.
|
|
383
|
+
* - `prev` — the `recordId` of the previous record, or `null` at genesis.
|
|
384
|
+
* - `collection` + `rkey` — the AtProto-style record key.
|
|
385
|
+
*
|
|
386
|
+
* The caller is responsible for fetching the current chain head (so `seq` /
|
|
387
|
+
* `prev` are correct) before signing. Requires a stored identity; throws if
|
|
388
|
+
* none exists.
|
|
389
|
+
*/
|
|
390
|
+
static async signRecordV2(type, subject, record, chain) {
|
|
391
|
+
const publicKey = await KeyManager.getPublicKey();
|
|
392
|
+
if (!publicKey) {
|
|
393
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
394
|
+
}
|
|
395
|
+
const version = 2;
|
|
396
|
+
const issuer = subject;
|
|
397
|
+
const issuedAt = Date.now();
|
|
398
|
+
const { seq, prev, collection, rkey } = chain;
|
|
399
|
+
const signingInput = signedRecordSigningInput({
|
|
400
|
+
version,
|
|
401
|
+
type,
|
|
402
|
+
subject,
|
|
403
|
+
issuer,
|
|
404
|
+
record,
|
|
405
|
+
issuedAt,
|
|
406
|
+
seq,
|
|
407
|
+
prev,
|
|
408
|
+
collection,
|
|
409
|
+
rkey,
|
|
410
|
+
});
|
|
411
|
+
const signature = await SignatureService.sign(signingInput);
|
|
412
|
+
return {
|
|
413
|
+
version,
|
|
414
|
+
type,
|
|
415
|
+
subject,
|
|
416
|
+
issuer,
|
|
417
|
+
record,
|
|
418
|
+
issuedAt,
|
|
419
|
+
seq,
|
|
420
|
+
prev,
|
|
421
|
+
collection,
|
|
422
|
+
rkey,
|
|
423
|
+
publicKey,
|
|
424
|
+
alg: 'ES256K-DER-SHA256',
|
|
425
|
+
signature,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
343
428
|
/**
|
|
344
429
|
* Verify a signed-record envelope: recompute the canonical signing input from
|
|
345
430
|
* the envelope's own fields and check the signature against the envelope's
|
package/dist/esm/index.js
CHANGED
|
@@ -35,6 +35,7 @@ export { OxyAppDataIdentifierError } from './mixins/OxyServices.appData.js';
|
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
36
|
export { getNormalizedUserId, normalizeUserIdentity, normalizeUserIdentityOrNull, } from './utils/userIdentity.js';
|
|
37
37
|
export { getCanonicalUserHandle, getNormalizedUserHandle, } from './utils/userHandle.js';
|
|
38
|
+
export { normalizeProfileLinks } from './utils/profileLinks.js';
|
|
38
39
|
// ---------------------------------------------------------------------------
|
|
39
40
|
// Self-sovereign identity (DID, signed records, auth-method ↔ VM mapping,
|
|
40
41
|
// verified domains). Wire shapes (DidDocument, SignedRecordEnvelope,
|
|
@@ -43,6 +44,15 @@ export { getCanonicalUserHandle, getNormalizedUserHandle, } from './utils/userHa
|
|
|
43
44
|
// ---------------------------------------------------------------------------
|
|
44
45
|
export { buildUserDid } from './mixins/OxyServices.identity.js';
|
|
45
46
|
// ---------------------------------------------------------------------------
|
|
47
|
+
// Civic / Commons "Oxy ID" (public signed cards + Oxy ID QR payload) and Fase 2
|
|
48
|
+
// anti-gaming (real-life attestation QR + validator/jury). Wire shapes
|
|
49
|
+
// (PublicCard, SignedPublicCard, RealLifeAttestationResult,
|
|
50
|
+
// ValidationRequestSummary, ValidationVoteResult, ValidationVerdict, …) live in
|
|
51
|
+
// `@oxyhq/contracts` — import them from there. The SDK adds the client verdict
|
|
52
|
+
// wrapper, the QR payload parsers/builders, and the submit inputs/results.
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
export { parseIdPayload, parseAttestPayload, verifyPublicCardAttestation, } from './mixins/OxyServices.civic.js';
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
46
56
|
// Auth helpers (token refresh, error normalisation, retry policies)
|
|
47
57
|
// ---------------------------------------------------------------------------
|
|
48
58
|
export { SessionSyncRequiredError, AuthenticationFailedError, ensureValidToken, isAuthenticationError, withAuthErrorHandling, authenticatedApiCall, } from './utils/authHelpers.js';
|
|
@@ -54,7 +64,7 @@ export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual, } from '.
|
|
|
54
64
|
// Crypto / identity
|
|
55
65
|
// ---------------------------------------------------------------------------
|
|
56
66
|
export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, } from './crypto/keyManager.js';
|
|
57
|
-
export { SignatureService, signedRecordSigningInput } from './crypto/signatureService.js';
|
|
67
|
+
export { SignatureService, signedRecordSigningInput, computeRecordId } from './crypto/signatureService.js';
|
|
58
68
|
export { canonicalize } from './crypto/canonicalJson.js';
|
|
59
69
|
export { RecoveryPhraseService } from './crypto/recoveryPhrase.js';
|
|
60
70
|
// ---------------------------------------------------------------------------
|