@peac/protocol 0.12.0-preview.1 → 0.12.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/README.md +25 -13
- package/dist/index.cjs +15 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +15 -96
- package/dist/index.mjs.map +1 -1
- package/dist/issue.d.ts +38 -11
- package/dist/issue.d.ts.map +1 -1
- package/dist/verify-local-wire01.d.ts +45 -0
- package/dist/verify-local-wire01.d.ts.map +1 -0
- package/dist/verify-local.cjs +8 -92
- package/dist/verify-local.cjs.map +1 -1
- package/dist/verify-local.d.ts +30 -78
- package/dist/verify-local.d.ts.map +1 -1
- package/dist/verify-local.mjs +8 -92
- package/dist/verify-local.mjs.map +1 -1
- package/dist/verify.d.ts +11 -4
- package/dist/verify.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -22,11 +22,16 @@ const { publicKey, privateKey } = await generateKeypair();
|
|
|
22
22
|
|
|
23
23
|
const { jws } = await issue({
|
|
24
24
|
iss: 'https://api.example.com',
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
kind: 'evidence',
|
|
26
|
+
type: 'org.peacprotocol/payment',
|
|
27
|
+
pillars: ['commerce'],
|
|
28
|
+
extensions: {
|
|
29
|
+
'org.peacprotocol/commerce': {
|
|
30
|
+
payment_rail: 'stripe',
|
|
31
|
+
amount_minor: '10000',
|
|
32
|
+
currency: 'USD',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
30
35
|
privateKey,
|
|
31
36
|
kid: 'key-2026-02',
|
|
32
37
|
});
|
|
@@ -39,10 +44,10 @@ import { verifyLocal } from '@peac/protocol';
|
|
|
39
44
|
|
|
40
45
|
const result = await verifyLocal(jws, publicKey);
|
|
41
46
|
|
|
42
|
-
if (result.valid && result.
|
|
47
|
+
if (result.valid && result.wireVersion === '0.2') {
|
|
43
48
|
console.log(result.claims.iss); // issuer
|
|
44
|
-
console.log(result.claims.
|
|
45
|
-
console.log(result.claims.
|
|
49
|
+
console.log(result.claims.kind); // evidence
|
|
50
|
+
console.log(result.claims.type); // org.peacprotocol/payment
|
|
46
51
|
} else if (!result.valid) {
|
|
47
52
|
console.log(result.code, result.message);
|
|
48
53
|
}
|
|
@@ -50,16 +55,23 @@ if (result.valid && result.variant === 'commerce') {
|
|
|
50
55
|
|
|
51
56
|
## How Do I Verify with JWKS Discovery?
|
|
52
57
|
|
|
58
|
+
> **Note:** `verifyReceipt()` is deprecated (Wire 0.1 only). For Wire 0.2 receipts,
|
|
59
|
+
> resolve the issuer's JWKS manually and pass the public key to `verifyLocal()`.
|
|
60
|
+
> Automated JWKS discovery for Wire 0.2 is planned for a future release.
|
|
61
|
+
|
|
53
62
|
```typescript
|
|
54
|
-
import {
|
|
63
|
+
import { verifyLocal } from '@peac/protocol';
|
|
55
64
|
|
|
56
|
-
//
|
|
57
|
-
|
|
65
|
+
// 1. Resolve issuer's /.well-known/peac-issuer.json -> jwks_uri -> public key
|
|
66
|
+
// 2. Pass the resolved key to verifyLocal()
|
|
67
|
+
const result = await verifyLocal(jws, resolvedPublicKey, {
|
|
68
|
+
issuer: 'https://api.example.com',
|
|
69
|
+
});
|
|
58
70
|
|
|
59
|
-
if (result.
|
|
71
|
+
if (result.valid) {
|
|
60
72
|
console.log('Issuer:', result.claims.iss);
|
|
61
73
|
} else {
|
|
62
|
-
console.log(result.
|
|
74
|
+
console.log(result.code, result.message);
|
|
63
75
|
}
|
|
64
76
|
```
|
|
65
77
|
|
package/dist/index.cjs
CHANGED
|
@@ -35,7 +35,7 @@ var IssueError = class extends Error {
|
|
|
35
35
|
this.peacError = peacError;
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
async function
|
|
38
|
+
async function issueWire01(options) {
|
|
39
39
|
if (!options.iss.startsWith("https://")) {
|
|
40
40
|
throw new Error("Issuer URL must start with https://");
|
|
41
41
|
}
|
|
@@ -176,9 +176,12 @@ async function issue(options) {
|
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
async function issueJws(options) {
|
|
179
|
-
const result = await
|
|
179
|
+
const result = await issueWire01(options);
|
|
180
180
|
return result.jws;
|
|
181
181
|
}
|
|
182
|
+
async function issue(options) {
|
|
183
|
+
return issueWire02(options);
|
|
184
|
+
}
|
|
182
185
|
async function issueWire02(options) {
|
|
183
186
|
if (!schema.isCanonicalIss(options.iss)) {
|
|
184
187
|
throw new IssueError({
|
|
@@ -188,7 +191,7 @@ async function issueWire02(options) {
|
|
|
188
191
|
retryable: false,
|
|
189
192
|
http_status: 400,
|
|
190
193
|
details: {
|
|
191
|
-
message: `iss is not in canonical form: "${options.iss}". Use https
|
|
194
|
+
message: `iss is not in canonical form: "${options.iss}". Use an https://<origin> or did:<method> identifier.`
|
|
192
195
|
}
|
|
193
196
|
});
|
|
194
197
|
}
|
|
@@ -1415,16 +1418,7 @@ function sanitizeParseIssues(issues) {
|
|
|
1415
1418
|
}));
|
|
1416
1419
|
}
|
|
1417
1420
|
async function verifyLocal(jws, publicKey, options = {}) {
|
|
1418
|
-
const {
|
|
1419
|
-
issuer,
|
|
1420
|
-
audience,
|
|
1421
|
-
subjectUri,
|
|
1422
|
-
rid,
|
|
1423
|
-
requireExp = false,
|
|
1424
|
-
maxClockSkew = 300,
|
|
1425
|
-
strictness = "strict",
|
|
1426
|
-
policyDigest
|
|
1427
|
-
} = options;
|
|
1421
|
+
const { issuer, subjectUri, maxClockSkew = 300, strictness = "strict", policyDigest } = options;
|
|
1428
1422
|
const now = options.now ?? Math.floor(Date.now() / 1e3);
|
|
1429
1423
|
try {
|
|
1430
1424
|
const result = await crypto.verify(jws, publicKey);
|
|
@@ -1556,86 +1550,11 @@ async function verifyLocal(jws, publicKey, options = {}) {
|
|
|
1556
1550
|
policy_binding: bindingStatus
|
|
1557
1551
|
};
|
|
1558
1552
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
message: `Issuer mismatch: expected "${issuer}", got "${w01.iss}"`
|
|
1565
|
-
};
|
|
1566
|
-
}
|
|
1567
|
-
if (audience !== void 0 && w01.aud !== audience) {
|
|
1568
|
-
return {
|
|
1569
|
-
valid: false,
|
|
1570
|
-
code: "E_INVALID_AUDIENCE",
|
|
1571
|
-
message: `Audience mismatch: expected "${audience}", got "${w01.aud}"`
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
if (rid !== void 0 && w01.rid !== rid) {
|
|
1575
|
-
return {
|
|
1576
|
-
valid: false,
|
|
1577
|
-
code: "E_INVALID_RECEIPT_ID",
|
|
1578
|
-
message: `Receipt ID mismatch: expected "${rid}", got "${w01.rid}"`
|
|
1579
|
-
};
|
|
1580
|
-
}
|
|
1581
|
-
if (requireExp && w01.exp === void 0) {
|
|
1582
|
-
return {
|
|
1583
|
-
valid: false,
|
|
1584
|
-
code: "E_MISSING_EXP",
|
|
1585
|
-
message: "Receipt missing required exp claim"
|
|
1586
|
-
};
|
|
1587
|
-
}
|
|
1588
|
-
if (w01.iat > now + maxClockSkew) {
|
|
1589
|
-
return {
|
|
1590
|
-
valid: false,
|
|
1591
|
-
code: "E_NOT_YET_VALID",
|
|
1592
|
-
message: `Receipt not yet valid: issued at ${new Date(w01.iat * 1e3).toISOString()}, now is ${new Date(now * 1e3).toISOString()}`
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
if (w01.exp !== void 0 && w01.exp < now - maxClockSkew) {
|
|
1596
|
-
return {
|
|
1597
|
-
valid: false,
|
|
1598
|
-
code: "E_EXPIRED",
|
|
1599
|
-
message: `Receipt expired at ${new Date(w01.exp * 1e3).toISOString()}`
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
if (pr.variant === "commerce") {
|
|
1603
|
-
const claims = pr.claims;
|
|
1604
|
-
if (subjectUri !== void 0 && claims.subject?.uri !== subjectUri) {
|
|
1605
|
-
return {
|
|
1606
|
-
valid: false,
|
|
1607
|
-
code: "E_INVALID_SUBJECT",
|
|
1608
|
-
message: `Subject mismatch: expected "${subjectUri}", got "${claims.subject?.uri ?? "undefined"}"`
|
|
1609
|
-
};
|
|
1610
|
-
}
|
|
1611
|
-
return {
|
|
1612
|
-
valid: true,
|
|
1613
|
-
variant: "commerce",
|
|
1614
|
-
claims,
|
|
1615
|
-
kid: result.header.kid,
|
|
1616
|
-
wireVersion: "0.1",
|
|
1617
|
-
warnings: [],
|
|
1618
|
-
policy_binding: "unavailable"
|
|
1619
|
-
};
|
|
1620
|
-
} else {
|
|
1621
|
-
const claims = pr.claims;
|
|
1622
|
-
if (subjectUri !== void 0 && claims.sub !== subjectUri) {
|
|
1623
|
-
return {
|
|
1624
|
-
valid: false,
|
|
1625
|
-
code: "E_INVALID_SUBJECT",
|
|
1626
|
-
message: `Subject mismatch: expected "${subjectUri}", got "${claims.sub ?? "undefined"}"`
|
|
1627
|
-
};
|
|
1628
|
-
}
|
|
1629
|
-
return {
|
|
1630
|
-
valid: true,
|
|
1631
|
-
variant: "attestation",
|
|
1632
|
-
claims,
|
|
1633
|
-
kid: result.header.kid,
|
|
1634
|
-
wireVersion: "0.1",
|
|
1635
|
-
warnings: [],
|
|
1636
|
-
policy_binding: "unavailable"
|
|
1637
|
-
};
|
|
1638
|
-
}
|
|
1553
|
+
return {
|
|
1554
|
+
valid: false,
|
|
1555
|
+
code: "E_UNSUPPORTED_WIRE_VERSION",
|
|
1556
|
+
message: "Wire 0.1 receipts are not supported. Re-issue as Wire 0.2 using issue()."
|
|
1557
|
+
};
|
|
1639
1558
|
} catch (err) {
|
|
1640
1559
|
if (isCryptoError(err)) {
|
|
1641
1560
|
if (Object.prototype.hasOwnProperty.call(JOSE_CODE_MAP, err.code)) {
|
|
@@ -1684,10 +1603,10 @@ async function verifyLocal(jws, publicKey, options = {}) {
|
|
|
1684
1603
|
}
|
|
1685
1604
|
}
|
|
1686
1605
|
function isCommerceResult(r) {
|
|
1687
|
-
return
|
|
1606
|
+
return false;
|
|
1688
1607
|
}
|
|
1689
1608
|
function isAttestationResult(r) {
|
|
1690
|
-
return
|
|
1609
|
+
return false;
|
|
1691
1610
|
}
|
|
1692
1611
|
function isWire02Result(r) {
|
|
1693
1612
|
return r.valid === true && r.variant === "wire-02";
|
|
@@ -3084,6 +3003,7 @@ exports.isCommerceResult = isCommerceResult;
|
|
|
3084
3003
|
exports.isWire02Result = isWire02Result;
|
|
3085
3004
|
exports.issue = issue;
|
|
3086
3005
|
exports.issueJws = issueJws;
|
|
3006
|
+
exports.issueWire01 = issueWire01;
|
|
3087
3007
|
exports.issueWire02 = issueWire02;
|
|
3088
3008
|
exports.parseBodyProfile = parseBodyProfile;
|
|
3089
3009
|
exports.parseDiscovery = parseDiscovery;
|