@datumesh/verify 0.1.1 → 0.2.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 +7 -5
- package/dist/cjs/envelope.d.ts +38 -0
- package/dist/cjs/envelope.js +243 -0
- package/dist/cjs/errors.d.ts +2 -2
- package/dist/cjs/errors.js +5 -1
- package/dist/cjs/index.d.ts +12 -2
- package/dist/cjs/index.js +21 -3
- package/dist/cjs/json.d.ts +3 -3
- package/dist/cjs/json.js +15 -11
- package/dist/cjs/lexical.d.ts +11 -1
- package/dist/cjs/lexical.js +28 -4
- package/dist/cjs/units-data.d.ts +4 -0
- package/dist/cjs/units-data.js +11 -0
- package/dist/cjs/units.d.ts +24 -0
- package/dist/cjs/units.js +131 -0
- package/dist/cjs/uri.d.ts +14 -2
- package/dist/cjs/uri.js +17 -9
- package/dist/cjs/validate.d.ts +8 -0
- package/dist/cjs/validate.js +63 -4
- package/dist/cjs/verify.d.ts +21 -2
- package/dist/cjs/verify.js +47 -7
- package/dist/esm/envelope.d.ts +38 -0
- package/dist/esm/envelope.js +240 -0
- package/dist/esm/errors.d.ts +2 -2
- package/dist/esm/errors.js +5 -1
- package/dist/esm/index.d.ts +12 -2
- package/dist/esm/index.js +19 -3
- package/dist/esm/json.d.ts +3 -3
- package/dist/esm/json.js +15 -11
- package/dist/esm/lexical.d.ts +11 -1
- package/dist/esm/lexical.js +24 -2
- package/dist/esm/units-data.d.ts +4 -0
- package/dist/esm/units-data.js +8 -0
- package/dist/esm/units.d.ts +24 -0
- package/dist/esm/units.js +123 -0
- package/dist/esm/uri.d.ts +14 -2
- package/dist/esm/uri.js +20 -12
- package/dist/esm/validate.d.ts +8 -0
- package/dist/esm/validate.js +61 -4
- package/dist/esm/verify.d.ts +21 -2
- package/dist/esm/verify.js +46 -8
- package/package.json +3 -3
package/dist/cjs/lexical.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VALID_TIME_TYPES = exports.TYPES = exports.LIMITS = void 0;
|
|
3
|
+
exports.URL_RE = exports.MEDIA_TYPE_MAX = exports.VALID_TIME_TYPES = exports.TYPES = exports.LIMITS = void 0;
|
|
4
4
|
exports.isTypeName = isTypeName;
|
|
5
5
|
exports.checkName = checkName;
|
|
6
6
|
exports.checkArgName = checkArgName;
|
|
@@ -10,12 +10,14 @@ exports.checkFunctionName = checkFunctionName;
|
|
|
10
10
|
exports.isHex = isHex;
|
|
11
11
|
exports.checkHex = checkHex;
|
|
12
12
|
exports.checkKeyRef = checkKeyRef;
|
|
13
|
+
exports.isNumber = isNumber;
|
|
13
14
|
exports.checkNumber = checkNumber;
|
|
14
15
|
exports.isDate = isDate;
|
|
15
16
|
exports.isInstant = isInstant;
|
|
16
17
|
exports.checkDate = checkDate;
|
|
17
18
|
exports.checkInstant = checkInstant;
|
|
18
19
|
exports.checkString = checkString;
|
|
20
|
+
exports.checkBlob = checkBlob;
|
|
19
21
|
exports.checkLicence = checkLicence;
|
|
20
22
|
exports.checkTypedValue = checkTypedValue;
|
|
21
23
|
// Lexical rules of SPEC.md sections 2-3 and 8.1. Each check throws a DatumeshError with the
|
|
@@ -37,7 +39,7 @@ exports.LIMITS = {
|
|
|
37
39
|
licence_url: 512,
|
|
38
40
|
keys: 64,
|
|
39
41
|
};
|
|
40
|
-
exports.TYPES = ['boolean', 'date', 'instant', 'number', 'string'];
|
|
42
|
+
exports.TYPES = ['blob', 'boolean', 'date', 'instant', 'number', 'string'];
|
|
41
43
|
exports.VALID_TIME_TYPES = ['date', 'instant', 'string'];
|
|
42
44
|
function isTypeName(t) {
|
|
43
45
|
return typeof t === 'string' && exports.TYPES.includes(t);
|
|
@@ -107,6 +109,10 @@ function checkKeyRef(s, path) {
|
|
|
107
109
|
return { host, id };
|
|
108
110
|
}
|
|
109
111
|
const NUMBER_RE = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]*[1-9])?$/;
|
|
112
|
+
/** SPEC 3.1: a canonical decimal of at most 128 characters. */
|
|
113
|
+
function isNumber(s) {
|
|
114
|
+
return NUMBER_RE.test(s) && s !== '-0' && s.length <= exports.LIMITS.number;
|
|
115
|
+
}
|
|
110
116
|
/** SPEC 3.1. Grammar (E_CANON_NUMBER) before the 128-character limit (E_CANON_LIMIT). */
|
|
111
117
|
function checkNumber(s, path) {
|
|
112
118
|
if (!NUMBER_RE.test(s) || s === '-0')
|
|
@@ -166,8 +172,24 @@ function checkString(s, path, opts = {}) {
|
|
|
166
172
|
function hex4(cp) {
|
|
167
173
|
return cp.toString(16).toUpperCase().padStart(4, '0');
|
|
168
174
|
}
|
|
175
|
+
// SPEC 3.7: <sha256>:<length>:<type>/<subtype>, with RFC 6838 restricted names in lowercase.
|
|
176
|
+
const BLOB_RE = /^[0-9a-f]{64}:(0|[1-9][0-9]*):([a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*)$/;
|
|
177
|
+
const MAX_SAFE = '9007199254740991';
|
|
178
|
+
exports.MEDIA_TYPE_MAX = 128;
|
|
179
|
+
/** SPEC 3.7. Grammar, then length <= 2^53 - 1, then media type <= 128 characters; all E_CANON_BLOB. */
|
|
180
|
+
function checkBlob(s, path) {
|
|
181
|
+
const m = BLOB_RE.exec(s);
|
|
182
|
+
if (!m)
|
|
183
|
+
(0, errors_js_1.fail)('E_CANON_BLOB', `not <sha256>:<length>:<type/subtype>: ${JSON.stringify(s)}`, path);
|
|
184
|
+
const len = m[1];
|
|
185
|
+
if (len.length > MAX_SAFE.length || (len.length === MAX_SAFE.length && len > MAX_SAFE))
|
|
186
|
+
(0, errors_js_1.fail)('E_CANON_BLOB', `length above ${MAX_SAFE}`, path);
|
|
187
|
+
if (m[2].length > exports.MEDIA_TYPE_MAX)
|
|
188
|
+
(0, errors_js_1.fail)('E_CANON_BLOB', `media type longer than ${exports.MEDIA_TYPE_MAX} characters`, path);
|
|
189
|
+
return { sha256: s.slice(0, 64), length: Number(len), mediaType: m[2] };
|
|
190
|
+
}
|
|
169
191
|
const SPDX_RE = /^[A-Za-z0-9][A-Za-z0-9.+-]*$/;
|
|
170
|
-
|
|
192
|
+
exports.URL_RE = /^https:\/\/[!-~]+$/;
|
|
171
193
|
/**
|
|
172
194
|
* SPEC 8.1 `licence`: an SPDX licence identifier or an https:// URL. SPEC.md gives no grammar;
|
|
173
195
|
* this follows schemas/receipt.schema.json (and the reference tool): an identifier matches
|
|
@@ -176,7 +198,7 @@ const URL_RE = /^https:\/\/[!-~]+$/;
|
|
|
176
198
|
*/
|
|
177
199
|
function checkLicence(s, path) {
|
|
178
200
|
if (s.startsWith('https://')) {
|
|
179
|
-
if (!URL_RE.test(s))
|
|
201
|
+
if (!exports.URL_RE.test(s))
|
|
180
202
|
(0, errors_js_1.fail)('E_CANON_LICENCE', 'licence URL has characters outside printable ASCII', path);
|
|
181
203
|
if (s.length > exports.LIMITS.licence_url)
|
|
182
204
|
(0, errors_js_1.fail)('E_CANON_LIMIT', 'licence URL too long', path);
|
|
@@ -202,6 +224,8 @@ function checkTypedValue(type, value, path) {
|
|
|
202
224
|
checkDate(value, path);
|
|
203
225
|
else if (type === 'instant')
|
|
204
226
|
checkInstant(value, path);
|
|
227
|
+
else if (type === 'blob')
|
|
228
|
+
checkBlob(value, path);
|
|
205
229
|
else
|
|
206
230
|
checkString(value, path);
|
|
207
231
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// GENERATED by tools/gen-units.mjs from spec/units.md (the `units-…` fenced blocks).
|
|
3
|
+
// Do not edit by hand; test/units.test.mjs checks that this file matches units.md.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.UNIT_GROUPS = void 0;
|
|
6
|
+
/** Literal units by group, in units.md order. Index units (units.md 2.4) are a pattern. */
|
|
7
|
+
exports.UNIT_GROUPS = {
|
|
8
|
+
currency: ["AED", "AFN", "ALL", "AMD", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SOS", "SRD", "SSP", "STN", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UYW", "UZS", "VED", "VES", "VND", "VUV", "WST", "XAD", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XCG", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "YER", "ZAR", "ZMW", "ZWG", "BGN", "CYP", "EEK", "GRD", "HRK", "LTL", "LVL", "MTL", "ROL", "SIT", "SKK", "TRL"],
|
|
9
|
+
physical: ["m", "kg", "s", "A", "K", "mol", "cd", "degC", "m/s", "W", "kWh", "mm", "cm", "km/h", "hPa", "W/m2"],
|
|
10
|
+
ratio: ["percent", "permille", "bp", "1", "count"],
|
|
11
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type JsonObject, type JsonValue } from './json.js';
|
|
2
|
+
/** A currency code from units.md 2.1 (List One and the withdrawn codes). */
|
|
3
|
+
export declare function isCurrency(s: unknown): boolean;
|
|
4
|
+
/** units.md 2.4: index:<YYYY[-MM[-DD]]>=<number greater than 0>, at most 64 characters. */
|
|
5
|
+
export declare function isIndexUnit(s: string): boolean;
|
|
6
|
+
/** A literal unit (units.md section 2): a listed string or an index unit. Byte-for-byte. */
|
|
7
|
+
export declare function isUnitLiteral(s: unknown): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Step 2 for a unit: a string, {"arg": <string>}, or {"of": side, "per": side} where a side is
|
|
10
|
+
* a string or {"arg": <string>}. Anything else is E_SCHEMA (SPEC 7.1, units.md 1).
|
|
11
|
+
*/
|
|
12
|
+
export declare function structUnit(u: JsonValue, path: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Step 3 for a unit whose shape passed structUnit. `args` is the signature's `args`: a
|
|
15
|
+
* reference must name one of them whose declared type is `string` (E_CANON_UNIT).
|
|
16
|
+
*/
|
|
17
|
+
export declare function canonUnit(u: JsonValue, args: JsonObject, path: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* units.md section 3: the unit of one cell's value, for a descriptor and a cell that have
|
|
20
|
+
* passed validation and whose fn_hash matches. `returns` is the signature's `returns`.
|
|
21
|
+
* A referenced argument must be bound (E_ARG_MISSING), not a slice (E_SLICE), of its declared
|
|
22
|
+
* type (E_ARG_TYPE), and a literal unit (E_CANON_UNIT); on a rate side, a currency.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveUnit(returns: JsonValue, cellArgs: JsonObject, path: string, argsPath: string): string | null;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isCurrency = isCurrency;
|
|
4
|
+
exports.isIndexUnit = isIndexUnit;
|
|
5
|
+
exports.isUnitLiteral = isUnitLiteral;
|
|
6
|
+
exports.structUnit = structUnit;
|
|
7
|
+
exports.canonUnit = canonUnit;
|
|
8
|
+
exports.resolveUnit = resolveUnit;
|
|
9
|
+
// Units (SPEC.md 7.1, units.md): shapes in a signature (step 2, E_SCHEMA), validity against the
|
|
10
|
+
// closed list (step 3, E_CANON_UNIT), and resolution of a cell's unit (units.md section 3).
|
|
11
|
+
const errors_js_1 = require("./errors.js");
|
|
12
|
+
const json_js_1 = require("./json.js");
|
|
13
|
+
const lexical_js_1 = require("./lexical.js");
|
|
14
|
+
const units_data_js_1 = require("./units-data.js");
|
|
15
|
+
const CURRENCY = new Set(units_data_js_1.UNIT_GROUPS.currency);
|
|
16
|
+
const LITERAL = new Set(Object.values(units_data_js_1.UNIT_GROUPS).flat());
|
|
17
|
+
const INDEX_RE = /^index:([0-9]{4}(?:-[0-9]{2}(?:-[0-9]{2})?)?)=(.*)$/;
|
|
18
|
+
const INDEX_MAX = 64;
|
|
19
|
+
/** A currency code from units.md 2.1 (List One and the withdrawn codes). */
|
|
20
|
+
function isCurrency(s) {
|
|
21
|
+
return typeof s === 'string' && CURRENCY.has(s);
|
|
22
|
+
}
|
|
23
|
+
/** units.md 2.4: index:<YYYY[-MM[-DD]]>=<number greater than 0>, at most 64 characters. */
|
|
24
|
+
function isIndexUnit(s) {
|
|
25
|
+
if (s.length > INDEX_MAX)
|
|
26
|
+
return false;
|
|
27
|
+
const m = INDEX_RE.exec(s);
|
|
28
|
+
if (!m)
|
|
29
|
+
return false;
|
|
30
|
+
const [y, mo = '01', d = '01'] = m[1].split('-');
|
|
31
|
+
if (!(0, lexical_js_1.isDate)(`${y}-${mo}-${d}`))
|
|
32
|
+
return false;
|
|
33
|
+
return (0, lexical_js_1.isNumber)(m[2]) && !m[2].startsWith('-') && m[2] !== '0';
|
|
34
|
+
}
|
|
35
|
+
/** A literal unit (units.md section 2): a listed string or an index unit. Byte-for-byte. */
|
|
36
|
+
function isUnitLiteral(s) {
|
|
37
|
+
return typeof s === 'string' && (LITERAL.has(s) || isIndexUnit(s));
|
|
38
|
+
}
|
|
39
|
+
const isRef = (u) => Object.keys(u).length === 1 && (0, json_js_1.has)(u, 'arg') && typeof u.arg === 'string';
|
|
40
|
+
/**
|
|
41
|
+
* Step 2 for a unit: a string, {"arg": <string>}, or {"of": side, "per": side} where a side is
|
|
42
|
+
* a string or {"arg": <string>}. Anything else is E_SCHEMA (SPEC 7.1, units.md 1).
|
|
43
|
+
*/
|
|
44
|
+
function structUnit(u, path) {
|
|
45
|
+
if (typeof u === 'string')
|
|
46
|
+
return;
|
|
47
|
+
if ((0, json_js_1.isObject)(u)) {
|
|
48
|
+
if (isRef(u))
|
|
49
|
+
return;
|
|
50
|
+
const keys = Object.keys(u);
|
|
51
|
+
if (keys.length === 2 && (0, json_js_1.has)(u, 'of') && (0, json_js_1.has)(u, 'per')) {
|
|
52
|
+
for (const side of ['of', 'per']) {
|
|
53
|
+
const v = u[side];
|
|
54
|
+
if (typeof v === 'string' || ((0, json_js_1.isObject)(v) && isRef(v)))
|
|
55
|
+
continue;
|
|
56
|
+
(0, errors_js_1.fail)('E_SCHEMA', 'a rate side is a currency code or {"arg": name}', (0, json_js_1.memberPath)(path, side));
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
(0, errors_js_1.fail)('E_SCHEMA', 'a unit is a string, {"arg": name} or {"of", "per"}', path);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Step 3 for a unit whose shape passed structUnit. `args` is the signature's `args`: a
|
|
65
|
+
* reference must name one of them whose declared type is `string` (E_CANON_UNIT).
|
|
66
|
+
*/
|
|
67
|
+
function canonUnit(u, args, path) {
|
|
68
|
+
const checkRef = (r, p) => {
|
|
69
|
+
const name = r.arg;
|
|
70
|
+
const d = (0, json_js_1.has)(args, name) ? args[name] : null;
|
|
71
|
+
if (!(0, json_js_1.isObject)(d) || d.type !== 'string')
|
|
72
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', `a unit names a string argument of the signature: ${JSON.stringify(name)}`, p);
|
|
73
|
+
};
|
|
74
|
+
if (typeof u === 'string') {
|
|
75
|
+
if (!isUnitLiteral(u))
|
|
76
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', `not a unit listed in units.md: ${JSON.stringify(u)}`, path);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const o = u;
|
|
80
|
+
if ((0, json_js_1.has)(o, 'arg'))
|
|
81
|
+
return checkRef(o, path);
|
|
82
|
+
for (const side of ['of', 'per']) {
|
|
83
|
+
const v = o[side];
|
|
84
|
+
const p = (0, json_js_1.memberPath)(path, side);
|
|
85
|
+
if (typeof v === 'string') {
|
|
86
|
+
if (!isCurrency(v))
|
|
87
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', `a rate side is a currency code: ${JSON.stringify(v)}`, p);
|
|
88
|
+
}
|
|
89
|
+
else
|
|
90
|
+
checkRef(v, p);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* units.md section 3: the unit of one cell's value, for a descriptor and a cell that have
|
|
95
|
+
* passed validation and whose fn_hash matches. `returns` is the signature's `returns`.
|
|
96
|
+
* A referenced argument must be bound (E_ARG_MISSING), not a slice (E_SLICE), of its declared
|
|
97
|
+
* type (E_ARG_TYPE), and a literal unit (E_CANON_UNIT); on a rate side, a currency.
|
|
98
|
+
*/
|
|
99
|
+
function resolveUnit(returns, cellArgs, path, argsPath) {
|
|
100
|
+
if (!(0, json_js_1.isObject)(returns))
|
|
101
|
+
return null; // only a number return is an object, and only it has a unit
|
|
102
|
+
const u = returns.unit;
|
|
103
|
+
const side = (v, p, currency) => {
|
|
104
|
+
if (typeof v === 'string')
|
|
105
|
+
return v; // a literal, already checked by canonUnit
|
|
106
|
+
const name = v.arg;
|
|
107
|
+
const ap = (0, json_js_1.memberPath)(argsPath, name);
|
|
108
|
+
if (!(0, json_js_1.has)(cellArgs, name))
|
|
109
|
+
(0, errors_js_1.fail)('E_ARG_MISSING', `the cell does not bind ${JSON.stringify(name)}`, argsPath);
|
|
110
|
+
const a = cellArgs[name];
|
|
111
|
+
if (a === '*')
|
|
112
|
+
(0, errors_js_1.fail)('E_SLICE', `${name} is a slice; its unit is not one string`, ap);
|
|
113
|
+
const scalar = a;
|
|
114
|
+
if (scalar.type !== 'string')
|
|
115
|
+
(0, errors_js_1.fail)('E_ARG_TYPE', `${name} is declared string`, ap);
|
|
116
|
+
const value = scalar.value;
|
|
117
|
+
if (currency ? !isCurrency(value) : !isUnitLiteral(value)) {
|
|
118
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', `argument ${name} is not ${currency ? 'a currency code' : 'a unit'}: ${JSON.stringify(value)}`, p);
|
|
119
|
+
}
|
|
120
|
+
return value;
|
|
121
|
+
};
|
|
122
|
+
const p = (0, json_js_1.memberPath)(path, 'unit');
|
|
123
|
+
if (typeof u === 'string')
|
|
124
|
+
return u;
|
|
125
|
+
const o = u;
|
|
126
|
+
if ((0, json_js_1.has)(o, 'arg'))
|
|
127
|
+
return side(o, p, false);
|
|
128
|
+
const of = side(o.of, (0, json_js_1.memberPath)(p, 'of'), true);
|
|
129
|
+
const per = side(o.per, (0, json_js_1.memberPath)(p, 'per'), true);
|
|
130
|
+
return `${of}/${per}`;
|
|
131
|
+
}
|
package/dist/cjs/uri.d.ts
CHANGED
|
@@ -11,13 +11,25 @@ export interface CellRef {
|
|
|
11
11
|
ns: string;
|
|
12
12
|
asof?: string;
|
|
13
13
|
}
|
|
14
|
-
/** A
|
|
14
|
+
/** A unit in a signature (SPEC 7.1): a literal from units.md, an argument reference, or a rate. */
|
|
15
|
+
export type UnitRef = {
|
|
16
|
+
arg: string;
|
|
17
|
+
};
|
|
18
|
+
export type Unit = string | UnitRef | {
|
|
19
|
+
of: string | UnitRef;
|
|
20
|
+
per: string | UnitRef;
|
|
21
|
+
};
|
|
22
|
+
/** A function descriptor's `signature` member (SPEC 7). Numbers declare a unit. */
|
|
15
23
|
export interface Signature {
|
|
16
24
|
args: Record<string, {
|
|
17
25
|
type: TypeName;
|
|
18
26
|
valid: boolean;
|
|
27
|
+
unit?: Unit;
|
|
19
28
|
}>;
|
|
20
|
-
returns: TypeName
|
|
29
|
+
returns: Exclude<TypeName, 'number'> | {
|
|
30
|
+
type: 'number';
|
|
31
|
+
unit: Unit;
|
|
32
|
+
};
|
|
21
33
|
}
|
|
22
34
|
/**
|
|
23
35
|
* Parse a cell URI into a cell reference, taking argument types from the function's
|
package/dist/cjs/uri.js
CHANGED
|
@@ -49,20 +49,21 @@ function encodeValue(s) {
|
|
|
49
49
|
}
|
|
50
50
|
return out;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* SPEC 5.4: the signature is taken as given (it comes from a descriptor already checked under
|
|
54
|
+
* section 7); only the declared argument names and types are used. Something that is not a
|
|
55
|
+
* signature at all is a programmer error.
|
|
56
|
+
*/
|
|
52
57
|
function readSignature(signature) {
|
|
53
|
-
if (signature === null || signature === undefined)
|
|
54
|
-
throw new TypeError('parseUri needs the function signature (descriptor.signature)');
|
|
55
58
|
let sig;
|
|
56
59
|
try {
|
|
57
60
|
sig = (0, json_js_1.toJson)(signature);
|
|
58
|
-
(0, validate_js_1.structSignature)(sig, 'signature');
|
|
59
|
-
(0, validate_js_1.canonSignature)(sig, 'signature');
|
|
60
61
|
}
|
|
61
|
-
catch
|
|
62
|
-
|
|
63
|
-
throw new errors_js_1.DatumeshError(e.code, `invalid signature: ${e.detail}`, e.path?.replace(/^\$/, 'signature') ?? 'signature');
|
|
64
|
-
throw e;
|
|
62
|
+
catch {
|
|
63
|
+
throw new TypeError('parseUri needs the function signature (descriptor.signature) as JSON');
|
|
65
64
|
}
|
|
65
|
+
if (!(0, json_js_1.isObject)(sig) || !(0, json_js_1.isObject)(sig.args))
|
|
66
|
+
throw new TypeError('parseUri needs the function signature (descriptor.signature): an object with args');
|
|
66
67
|
return sig;
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
@@ -151,8 +152,15 @@ function parseUri(uri, signature) {
|
|
|
151
152
|
args[p.name] = '*';
|
|
152
153
|
continue;
|
|
153
154
|
}
|
|
154
|
-
const
|
|
155
|
+
const decl = declared[p.name];
|
|
156
|
+
const type = ((0, json_js_1.isObject)(decl) ? decl.type : undefined);
|
|
155
157
|
const s = decodeValue(p.value, at(p.name));
|
|
158
|
+
// The signature is not validated (5.4), but a value is read by its declared type: a
|
|
159
|
+
// declaration without a string type is E_SCHEMA, an unknown type name E_CANON_TYPE.
|
|
160
|
+
if (typeof type !== 'string')
|
|
161
|
+
(0, errors_js_1.fail)('E_SCHEMA', `the signature declares ${p.name} without a string type`, `signature.args.${p.name}`);
|
|
162
|
+
if (!(0, lexical_js_1.isTypeName)(type))
|
|
163
|
+
(0, errors_js_1.fail)('E_CANON_TYPE', `unknown type ${JSON.stringify(type)} in the signature`, `signature.args.${p.name}.type`);
|
|
156
164
|
if (type === 'boolean') {
|
|
157
165
|
if (s !== 'true' && s !== 'false')
|
|
158
166
|
(0, errors_js_1.fail)('E_CANON_TYPE', 'boolean must be true or false', at(p.name));
|
package/dist/cjs/validate.d.ts
CHANGED
|
@@ -3,8 +3,16 @@ export type Kind = 'scalar' | 'cell' | 'ref' | 'function' | 'receipt' | 'jcs';
|
|
|
3
3
|
export declare const KINDS: readonly Kind[];
|
|
4
4
|
export declare function structSignature(v: JsonValue, path: string): void;
|
|
5
5
|
export declare function canonSignature(sig: JsonObject, path: string): void;
|
|
6
|
+
/** The return type named by a valid signature's `returns` (SPEC 10.1 step 7.4). */
|
|
7
|
+
export declare function returnType(sig: JsonObject): string;
|
|
6
8
|
/** Validate `v` as `kind` (steps 2-3; for receipts also step 4). Throws DatumeshError. */
|
|
7
9
|
export declare function validate(v: JsonValue, kind: Kind, path?: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* The unit of a cell's value (SPEC 7.1, units.md 3). Order: the cell (structure, canonical
|
|
12
|
+
* form), fn_hash against the descriptor (E_FN_HASH_MISMATCH), the descriptor (structure,
|
|
13
|
+
* canonical form), then substitution.
|
|
14
|
+
*/
|
|
15
|
+
export declare function cellUnit(desc: JsonValue, cell: JsonValue, fnHash: (d: JsonValue) => string): string | null;
|
|
8
16
|
/** Receipt step 2 only: true when the receipt has the right members and JSON types. */
|
|
9
17
|
export declare function receiptStructure(v: JsonValue): void;
|
|
10
18
|
/** Receipt steps 3 and 4, after receiptStructure has passed. */
|
package/dist/cjs/validate.js
CHANGED
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.KINDS = void 0;
|
|
4
4
|
exports.structSignature = structSignature;
|
|
5
5
|
exports.canonSignature = canonSignature;
|
|
6
|
+
exports.returnType = returnType;
|
|
6
7
|
exports.validate = validate;
|
|
8
|
+
exports.cellUnit = cellUnit;
|
|
7
9
|
exports.receiptStructure = receiptStructure;
|
|
8
10
|
exports.receiptCanonicalAndConsistent = receiptCanonicalAndConsistent;
|
|
9
11
|
exports.inferKind = inferKind;
|
|
@@ -13,6 +15,7 @@ exports.inferKind = inferKind;
|
|
|
13
15
|
const errors_js_1 = require("./errors.js");
|
|
14
16
|
const json_js_1 = require("./json.js");
|
|
15
17
|
const lexical_js_1 = require("./lexical.js");
|
|
18
|
+
const units_js_1 = require("./units.js");
|
|
16
19
|
exports.KINDS = ['scalar', 'cell', 'ref', 'function', 'receipt', 'jcs'];
|
|
17
20
|
const SLICE = '*';
|
|
18
21
|
// ---------------------------------------------------------------- step 2: structure
|
|
@@ -85,12 +88,24 @@ function structSignature(v, path) {
|
|
|
85
88
|
for (const k of (0, json_js_1.sortedKeys)(args)) {
|
|
86
89
|
const p = (0, json_js_1.memberPath)(argsPath, k);
|
|
87
90
|
const d = expectObject(args[k], p);
|
|
88
|
-
members(d, ['type', 'valid'], [], p);
|
|
91
|
+
members(d, ['type', 'valid'], ['unit'], p);
|
|
89
92
|
expectString(d, 'type', p);
|
|
93
|
+
if ((0, json_js_1.has)(d, 'unit'))
|
|
94
|
+
(0, units_js_1.structUnit)(d.unit, (0, json_js_1.memberPath)(p, 'unit'));
|
|
90
95
|
if (typeof d.valid !== 'boolean')
|
|
91
96
|
(0, errors_js_1.fail)('E_SCHEMA', 'valid must be a boolean', (0, json_js_1.memberPath)(p, 'valid'));
|
|
92
97
|
}
|
|
93
|
-
|
|
98
|
+
// SPEC 7: a type name, or {"type", "unit"} (the unit's absence is E_CANON_UNIT, in step 3).
|
|
99
|
+
const rp = (0, json_js_1.memberPath)(path, 'returns');
|
|
100
|
+
const r = sig.returns;
|
|
101
|
+
if (typeof r === 'string')
|
|
102
|
+
return;
|
|
103
|
+
if (!(0, json_js_1.isObject)(r))
|
|
104
|
+
(0, errors_js_1.fail)('E_SCHEMA', 'returns must be a type name or an object', rp);
|
|
105
|
+
members(r, ['type'], ['unit'], rp);
|
|
106
|
+
expectString(r, 'type', rp);
|
|
107
|
+
if ((0, json_js_1.has)(r, 'unit'))
|
|
108
|
+
(0, units_js_1.structUnit)(r.unit, (0, json_js_1.memberPath)(rp, 'unit'));
|
|
94
109
|
}
|
|
95
110
|
const RECEIPT_MEMBERS = [
|
|
96
111
|
'asof',
|
|
@@ -194,14 +209,43 @@ function canonSignature(sig, path) {
|
|
|
194
209
|
const p = (0, json_js_1.memberPath)(argsPath, k);
|
|
195
210
|
(0, lexical_js_1.checkArgName)(k, p);
|
|
196
211
|
const d = args[k];
|
|
212
|
+
// SPEC 7: type, then unit, then valid.
|
|
197
213
|
if (!(0, lexical_js_1.isTypeName)(d.type))
|
|
198
214
|
(0, errors_js_1.fail)('E_CANON_TYPE', `unknown type ${JSON.stringify(d.type)}`, (0, json_js_1.memberPath)(p, 'type'));
|
|
215
|
+
if (d.type === 'number') {
|
|
216
|
+
if (!(0, json_js_1.has)(d, 'unit'))
|
|
217
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', 'a number argument declares its unit', p);
|
|
218
|
+
(0, units_js_1.canonUnit)(d.unit, args, (0, json_js_1.memberPath)(p, 'unit'));
|
|
219
|
+
}
|
|
220
|
+
else if ((0, json_js_1.has)(d, 'unit')) {
|
|
221
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', 'only number arguments have a unit', (0, json_js_1.memberPath)(p, 'unit'));
|
|
222
|
+
}
|
|
199
223
|
if (d.valid === true && !lexical_js_1.VALID_TIME_TYPES.includes(d.type)) {
|
|
200
224
|
(0, errors_js_1.fail)('E_CANON_TYPE', 'a valid-time argument must be a date, instant or string', p);
|
|
201
225
|
}
|
|
202
226
|
}
|
|
203
|
-
|
|
204
|
-
|
|
227
|
+
const rp = (0, json_js_1.memberPath)(path, 'returns');
|
|
228
|
+
const r = sig.returns;
|
|
229
|
+
if (typeof r === 'string') {
|
|
230
|
+
if (!(0, lexical_js_1.isTypeName)(r))
|
|
231
|
+
(0, errors_js_1.fail)('E_CANON_TYPE', `unknown type ${JSON.stringify(r)}`, rp);
|
|
232
|
+
if (r === 'number')
|
|
233
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', 'a number return is {"type": "number", "unit": ...}, not the bare name', rp);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const o = r;
|
|
237
|
+
if (!(0, lexical_js_1.isTypeName)(o.type))
|
|
238
|
+
(0, errors_js_1.fail)('E_CANON_TYPE', `unknown type ${JSON.stringify(o.type)}`, (0, json_js_1.memberPath)(rp, 'type'));
|
|
239
|
+
if (o.type !== 'number')
|
|
240
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', 'only a number return is written as an object', rp);
|
|
241
|
+
if (!(0, json_js_1.has)(o, 'unit'))
|
|
242
|
+
(0, errors_js_1.fail)('E_CANON_UNIT', 'a number return declares its unit', rp);
|
|
243
|
+
(0, units_js_1.canonUnit)(o.unit, args, (0, json_js_1.memberPath)(rp, 'unit'));
|
|
244
|
+
}
|
|
245
|
+
/** The return type named by a valid signature's `returns` (SPEC 10.1 step 7.4). */
|
|
246
|
+
function returnType(sig) {
|
|
247
|
+
const r = sig.returns;
|
|
248
|
+
return typeof r === 'string' ? r : r.type;
|
|
205
249
|
}
|
|
206
250
|
function canonFunction(o, path) {
|
|
207
251
|
const code = o.code;
|
|
@@ -317,6 +361,21 @@ function validate(v, kind, path = '$') {
|
|
|
317
361
|
return;
|
|
318
362
|
}
|
|
319
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* The unit of a cell's value (SPEC 7.1, units.md 3). Order: the cell (structure, canonical
|
|
366
|
+
* form), fn_hash against the descriptor (E_FN_HASH_MISMATCH), the descriptor (structure,
|
|
367
|
+
* canonical form), then substitution.
|
|
368
|
+
*/
|
|
369
|
+
function cellUnit(desc, cell, fnHash) {
|
|
370
|
+
structCell(cell, 'cell', false);
|
|
371
|
+
canonCell(cell, 'cell');
|
|
372
|
+
if (fnHash(desc) !== cell.fn_hash)
|
|
373
|
+
(0, errors_js_1.fail)('E_FN_HASH_MISMATCH', 'the descriptor does not hash to cell.fn_hash', 'descriptor');
|
|
374
|
+
structFunction(desc, 'descriptor');
|
|
375
|
+
canonFunction(desc, 'descriptor');
|
|
376
|
+
const sig = desc.signature;
|
|
377
|
+
return (0, units_js_1.resolveUnit)(sig.returns, cell.args, 'descriptor.signature.returns', 'cell.args');
|
|
378
|
+
}
|
|
320
379
|
/** Receipt step 2 only: true when the receipt has the right members and JSON types. */
|
|
321
380
|
function receiptStructure(v) {
|
|
322
381
|
structReceipt(v, '$');
|
package/dist/cjs/verify.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ErrorCode } from './errors.js';
|
|
2
|
+
import { type JsonObject, type JsonValue } from './json.js';
|
|
3
|
+
import { type Sources } from './keys.js';
|
|
2
4
|
export interface VerifyResult {
|
|
3
5
|
/** True when the receipt is signature-valid (and, if recompute was given, fully verified). */
|
|
4
6
|
ok: boolean;
|
|
@@ -14,6 +16,8 @@ export interface VerifyResult {
|
|
|
14
16
|
detail: string;
|
|
15
17
|
/** Where the failure was found (a JSON path like `$.cell.args.base`), or null. */
|
|
16
18
|
path: string | null;
|
|
19
|
+
/** True only when blob content was supplied and step 7.7 ran and passed. Does not change `level`. */
|
|
20
|
+
blobChecked: boolean;
|
|
17
21
|
}
|
|
18
22
|
/** Input for SPEC 10.1 step 7. The library does not evaluate functions; `value` is the result. */
|
|
19
23
|
export interface Recompute {
|
|
@@ -27,12 +31,27 @@ export interface Recompute {
|
|
|
27
31
|
value: string | boolean;
|
|
28
32
|
};
|
|
29
33
|
}
|
|
34
|
+
declare class Stop extends Error {
|
|
35
|
+
readonly code: ErrorCode;
|
|
36
|
+
readonly detail: string;
|
|
37
|
+
readonly path: string | null;
|
|
38
|
+
constructor(code: ErrorCode, detail: string, path: string | null);
|
|
39
|
+
}
|
|
30
40
|
/**
|
|
31
41
|
* Verify a receipt (SPEC 10.1). `receipt` is JSON text, UTF-8 bytes or a parsed object (only
|
|
32
42
|
* text and bytes allow duplicate-member detection). `keys` is a key document, a KeysResult, a
|
|
33
|
-
* {keyId: publicKeyHex} map, or an array of these. With `recompute`, step 7 runs too.
|
|
43
|
+
* {keyId: publicKeyHex} map, or an array of these. With `recompute`, step 7 runs too. With
|
|
44
|
+
* `blob`, the content of a blob value, step 7.7 runs last (after step 7 when recomputing,
|
|
45
|
+
* otherwise right after step 6): E_SCHEMA if the value is not a blob, E_BLOB_MISMATCH if the
|
|
46
|
+
* content does not match. It does not change `level`; `blobChecked` reports it.
|
|
34
47
|
*
|
|
35
48
|
* Never throws for an invalid receipt or bad key material; throws TypeError only when an
|
|
36
49
|
* argument is of the wrong kind altogether.
|
|
37
50
|
*/
|
|
38
|
-
export declare function verify(receipt: unknown, keys: unknown, recomputeArg?: Recompute | null): VerifyResult;
|
|
51
|
+
export declare function verify(receipt: unknown, keys: unknown, recomputeArg?: Recompute | null, blob?: Uint8Array | ArrayBuffer | null): VerifyResult;
|
|
52
|
+
/** Steps 1-6 for an already-parsed receipt (used by checkEnvelope). Throws a Stop. */
|
|
53
|
+
export declare function verifyEmbedded(receipt: JsonValue, sources: Sources): {
|
|
54
|
+
receipt: JsonObject;
|
|
55
|
+
hash: string;
|
|
56
|
+
};
|
|
57
|
+
export { Stop };
|
package/dist/cjs/verify.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Stop = void 0;
|
|
3
4
|
exports.verify = verify;
|
|
5
|
+
exports.verifyEmbedded = verifyEmbedded;
|
|
4
6
|
// Receipt verification (SPEC.md 10.1). Synchronous, offline, no global state, no logging.
|
|
5
7
|
const errors_js_1 = require("./errors.js");
|
|
6
8
|
const ed25519_js_1 = require("./ed25519.js");
|
|
@@ -8,6 +10,7 @@ const hash_js_1 = require("./hash.js");
|
|
|
8
10
|
const json_js_1 = require("./json.js");
|
|
9
11
|
const jcs_js_1 = require("./jcs.js");
|
|
10
12
|
const keys_js_1 = require("./keys.js");
|
|
13
|
+
const lexical_js_1 = require("./lexical.js");
|
|
11
14
|
const validate_js_1 = require("./validate.js");
|
|
12
15
|
class Stop extends Error {
|
|
13
16
|
constructor(code, detail, path) {
|
|
@@ -17,6 +20,7 @@ class Stop extends Error {
|
|
|
17
20
|
this.path = path;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
23
|
+
exports.Stop = Stop;
|
|
20
24
|
function stop(code, detail, path = '$') {
|
|
21
25
|
throw new Stop(code, detail, path);
|
|
22
26
|
}
|
|
@@ -106,9 +110,10 @@ function recompute(receipt, rc, sources) {
|
|
|
106
110
|
if (validNames.join('\u0000') !== declaredValid.join('\u0000')) {
|
|
107
111
|
stop('E_VALID_MISMATCH', 'valid must echo exactly the declared valid-time arguments', '$.valid');
|
|
108
112
|
}
|
|
109
|
-
// 7.4 Return type.
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
// 7.4 Return type: `returns`, or its `type` member when it is an object.
|
|
114
|
+
const rt = (0, validate_js_1.returnType)(sig);
|
|
115
|
+
if (receipt.type !== rt)
|
|
116
|
+
stop('E_RETURN_TYPE', `function returns ${rt}`, '$.type');
|
|
112
117
|
// 7.5 Inputs.
|
|
113
118
|
const declaredInputs = desc.inputs;
|
|
114
119
|
const supplied = rc.inputs ?? {};
|
|
@@ -144,6 +149,28 @@ function recompute(receipt, rc, sources) {
|
|
|
144
149
|
if (v.type !== receipt.type || v.value !== receipt.value)
|
|
145
150
|
stop('E_VALUE_MISMATCH', 'recomputed value differs from the receipt', '$.value');
|
|
146
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Step 7.7: content is only for a blob value (E_SCHEMA otherwise); it has exactly `length`
|
|
154
|
+
* bytes, then a SHA-256 equal to the blob's hash (E_BLOB_MISMATCH).
|
|
155
|
+
*/
|
|
156
|
+
function checkContent(receipt, content) {
|
|
157
|
+
if (receipt.type !== 'blob')
|
|
158
|
+
stop('E_SCHEMA', `content was supplied, but the value is a ${String(receipt.type)}, not a blob`, '$.type');
|
|
159
|
+
const blob = (0, lexical_js_1.checkBlob)(receipt.value, '$.value'); // already checked in step 3
|
|
160
|
+
if (content.length !== blob.length)
|
|
161
|
+
stop('E_BLOB_MISMATCH', `content is ${content.length} bytes, the blob says ${blob.length}`, '$.value');
|
|
162
|
+
if ((0, hash_js_1.sha256Hex)(content) !== blob.sha256)
|
|
163
|
+
stop('E_BLOB_MISMATCH', "the content's SHA-256 is not the blob's hash", '$.value');
|
|
164
|
+
}
|
|
165
|
+
function checkBlobArg(b) {
|
|
166
|
+
if (b === undefined || b === null)
|
|
167
|
+
return null;
|
|
168
|
+
if (b instanceof Uint8Array)
|
|
169
|
+
return b;
|
|
170
|
+
if (b instanceof ArrayBuffer)
|
|
171
|
+
return new Uint8Array(b);
|
|
172
|
+
throw new TypeError('blob must be the content bytes (Uint8Array or ArrayBuffer)');
|
|
173
|
+
}
|
|
147
174
|
function checkRecomputeArg(rc) {
|
|
148
175
|
if (rc === undefined || rc === null)
|
|
149
176
|
return null;
|
|
@@ -161,32 +188,45 @@ function checkRecomputeArg(rc) {
|
|
|
161
188
|
/**
|
|
162
189
|
* Verify a receipt (SPEC 10.1). `receipt` is JSON text, UTF-8 bytes or a parsed object (only
|
|
163
190
|
* text and bytes allow duplicate-member detection). `keys` is a key document, a KeysResult, a
|
|
164
|
-
* {keyId: publicKeyHex} map, or an array of these. With `recompute`, step 7 runs too.
|
|
191
|
+
* {keyId: publicKeyHex} map, or an array of these. With `recompute`, step 7 runs too. With
|
|
192
|
+
* `blob`, the content of a blob value, step 7.7 runs last (after step 7 when recomputing,
|
|
193
|
+
* otherwise right after step 6): E_SCHEMA if the value is not a blob, E_BLOB_MISMATCH if the
|
|
194
|
+
* content does not match. It does not change `level`; `blobChecked` reports it.
|
|
165
195
|
*
|
|
166
196
|
* Never throws for an invalid receipt or bad key material; throws TypeError only when an
|
|
167
197
|
* argument is of the wrong kind altogether.
|
|
168
198
|
*/
|
|
169
|
-
function verify(receipt, keys, recomputeArg) {
|
|
199
|
+
function verify(receipt, keys, recomputeArg, blob) {
|
|
170
200
|
const sources = (0, keys_js_1.collectSources)(keys);
|
|
171
201
|
const rc = checkRecomputeArg(recomputeArg);
|
|
202
|
+
const content = checkBlobArg(blob);
|
|
172
203
|
let hash = null;
|
|
173
204
|
try {
|
|
174
205
|
const { receipt: r } = verifySigned(receipt, sources, (h) => (hash = h));
|
|
175
206
|
if (rc)
|
|
176
207
|
recompute(r, rc, sources);
|
|
208
|
+
const checked = content !== null;
|
|
209
|
+
if (checked)
|
|
210
|
+
checkContent(r, content);
|
|
211
|
+
const what = rc ? 'fully verified: signature valid and value recomputed' : `signature-valid: signed by ${r.computed_by}`;
|
|
177
212
|
return {
|
|
178
213
|
ok: true,
|
|
179
214
|
code: 'OK',
|
|
180
215
|
level: rc ? 'recomputed' : 'signed',
|
|
181
216
|
hash,
|
|
182
217
|
key: r.computed_by,
|
|
183
|
-
detail:
|
|
218
|
+
detail: checked ? `${what}; blob content matches` : what,
|
|
184
219
|
path: null,
|
|
220
|
+
blobChecked: checked,
|
|
185
221
|
};
|
|
186
222
|
}
|
|
187
223
|
catch (e) {
|
|
188
224
|
if (e instanceof Stop)
|
|
189
|
-
return { ok: false, code: e.code, level: null, hash, key: null, detail: e.detail, path: e.path };
|
|
225
|
+
return { ok: false, code: e.code, level: null, hash, key: null, detail: e.detail, path: e.path, blobChecked: false };
|
|
190
226
|
throw e; // a bug in this library, not a property of the receipt
|
|
191
227
|
}
|
|
192
228
|
}
|
|
229
|
+
/** Steps 1-6 for an already-parsed receipt (used by checkEnvelope). Throws a Stop. */
|
|
230
|
+
function verifyEmbedded(receipt, sources) {
|
|
231
|
+
return verifySigned(receipt, sources, () => undefined);
|
|
232
|
+
}
|