hbsig 0.0.1
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/cjs/bin_to_str.js +44 -0
- package/cjs/collect-body-keys.js +470 -0
- package/cjs/encode-array-item.js +110 -0
- package/cjs/encode-utils.js +236 -0
- package/cjs/encode.js +1318 -0
- package/cjs/erl_json.js +317 -0
- package/cjs/erl_str.js +1037 -0
- package/cjs/flat.js +222 -0
- package/cjs/http-message-signatures/httpbis.js +489 -0
- package/cjs/http-message-signatures/index.js +25 -0
- package/cjs/http-message-signatures/structured-header.js +129 -0
- package/cjs/httpsig.js +716 -0
- package/cjs/httpsig2.js +1160 -0
- package/cjs/id.js +470 -0
- package/cjs/index.js +63 -0
- package/cjs/send.js +194 -0
- package/cjs/signer-utils.js +617 -0
- package/cjs/signer.js +606 -0
- package/cjs/structured.js +296 -0
- package/cjs/test.js +27 -0
- package/cjs/utils.js +42 -0
- package/esm/bin_to_str.js +46 -0
- package/esm/collect-body-keys.js +436 -0
- package/esm/encode-array-item.js +112 -0
- package/esm/encode-utils.js +185 -0
- package/esm/encode.js +1219 -0
- package/esm/erl_json.js +289 -0
- package/esm/erl_str.js +1139 -0
- package/esm/flat.js +196 -0
- package/esm/http-message-signatures/httpbis.js +438 -0
- package/esm/http-message-signatures/index.js +4 -0
- package/esm/http-message-signatures/structured-header.js +105 -0
- package/esm/httpsig.js +658 -0
- package/esm/httpsig2.js +1097 -0
- package/esm/id.js +459 -0
- package/esm/index.js +4 -0
- package/esm/package.json +3 -0
- package/esm/send.js +124 -0
- package/esm/signer-utils.js +494 -0
- package/esm/signer.js +452 -0
- package/esm/structured.js +269 -0
- package/esm/test.js +6 -0
- package/esm/utils.js +28 -0
- package/package.json +28 -0
package/cjs/id.js
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.base = base;
|
|
7
|
+
exports.extractCommitmentIds = extractCommitmentIds;
|
|
8
|
+
exports.generateCommitmentId = generateCommitmentId;
|
|
9
|
+
exports.hashpath = hashpath;
|
|
10
|
+
exports.hmacid = hmacid;
|
|
11
|
+
exports.id = id;
|
|
12
|
+
exports.parseStructuredFieldDictionary = parseStructuredFieldDictionary;
|
|
13
|
+
exports.rsaid = rsaid;
|
|
14
|
+
exports.verifyCommitmentId = verifyCommitmentId;
|
|
15
|
+
var _fastSha = require("fast-sha256");
|
|
16
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
17
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
18
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
19
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
20
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
21
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
22
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
23
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
24
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
25
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
26
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
27
|
+
/**
|
|
28
|
+
* Parse structured field dictionary format
|
|
29
|
+
* Handles both complex format: name=(components);params
|
|
30
|
+
* and simple format: name=:value:
|
|
31
|
+
*/
|
|
32
|
+
function parseStructuredFieldDictionary(input) {
|
|
33
|
+
// Try complex format first
|
|
34
|
+
var match = input.match(/([^=]+)=\((.*?)\);(.*)$/);
|
|
35
|
+
if (match) {
|
|
36
|
+
var name = match[1];
|
|
37
|
+
var components = match[2].split(" ");
|
|
38
|
+
var params = {};
|
|
39
|
+
var paramPairs = match[3].split(";").filter(function (p) {
|
|
40
|
+
return p;
|
|
41
|
+
});
|
|
42
|
+
paramPairs.forEach(function (pair) {
|
|
43
|
+
var _pair$split = pair.split("="),
|
|
44
|
+
_pair$split2 = _slicedToArray(_pair$split, 2),
|
|
45
|
+
key = _pair$split2[0],
|
|
46
|
+
value = _pair$split2[1];
|
|
47
|
+
if (key && value) {
|
|
48
|
+
params[key] = value.replace(/"/g, "");
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
name: name,
|
|
53
|
+
components: components,
|
|
54
|
+
params: params
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Try simple format
|
|
59
|
+
var simpleMatch = input.match(/([^=]+)=:([^:]+):/);
|
|
60
|
+
if (simpleMatch) {
|
|
61
|
+
return {
|
|
62
|
+
name: simpleMatch[1],
|
|
63
|
+
value: simpleMatch[2]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Convert base64url string to base64
|
|
71
|
+
*/
|
|
72
|
+
function base64urlToBase64(str) {
|
|
73
|
+
return str.replace(/-/g, "+").replace(/_/g, "/");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generate commitment ID for RSA-PSS and ECDSA signatures
|
|
78
|
+
* The ID is the SHA256 hash of the raw signature bytes
|
|
79
|
+
*
|
|
80
|
+
* @param {Object} commitment - The commitment object containing signature
|
|
81
|
+
* @returns {string} The commitment ID in base64url format
|
|
82
|
+
*/
|
|
83
|
+
function rsaid(commitment) {
|
|
84
|
+
// Extract the base64 signature from structured field format
|
|
85
|
+
// Format: "signature-name=:BASE64_SIGNATURE:"
|
|
86
|
+
var match = commitment.signature.match(/^[^=]+=:([^:]+):/);
|
|
87
|
+
if (!match) {
|
|
88
|
+
throw new Error("Invalid signature format");
|
|
89
|
+
}
|
|
90
|
+
var signatureBase64 = match[1];
|
|
91
|
+
// Convert base64 to Uint8Array
|
|
92
|
+
var signatureBinary = Uint8Array.from(atob(signatureBase64), function (c) {
|
|
93
|
+
return c.charCodeAt(0);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// SHA256 hash of the raw signature
|
|
97
|
+
var hashResult = (0, _fastSha.hash)(signatureBinary);
|
|
98
|
+
var id = uint8ArrayToBase64url(hashResult);
|
|
99
|
+
return id;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Generate HMAC commitment ID for HyperBEAM messages
|
|
104
|
+
* The ID is deterministic based on message content only
|
|
105
|
+
*
|
|
106
|
+
* The Erlang implementation sorts components WITH @ prefix included,
|
|
107
|
+
* then removes @ from derived components in the signature base.
|
|
108
|
+
*
|
|
109
|
+
* @param {Object} message - The message with signature and signature-input
|
|
110
|
+
* @returns {string} The commitment ID in base64url format
|
|
111
|
+
*/
|
|
112
|
+
function hmacid(message) {
|
|
113
|
+
// Parse signature-input to get components
|
|
114
|
+
var parsed = parseStructuredFieldDictionary(message["signature-input"]);
|
|
115
|
+
if (!parsed || !parsed.components) {
|
|
116
|
+
throw new Error("Failed to parse signature-input");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Sort components AS-IS (with quotes and @ prefix)
|
|
120
|
+
var sortedComponents = _toConsumableArray(parsed.components).sort();
|
|
121
|
+
|
|
122
|
+
// Build signature base in sorted order
|
|
123
|
+
var lines = [];
|
|
124
|
+
sortedComponents.forEach(function (component) {
|
|
125
|
+
var cleanComponent = component.replace(/"/g, "");
|
|
126
|
+
var fieldName = cleanComponent;
|
|
127
|
+
var value;
|
|
128
|
+
|
|
129
|
+
// For derived components (starting with @), remove @ in the signature base
|
|
130
|
+
if (cleanComponent.startsWith("@")) {
|
|
131
|
+
fieldName = cleanComponent.substring(1);
|
|
132
|
+
value = message[fieldName];
|
|
133
|
+
} else {
|
|
134
|
+
value = message[cleanComponent];
|
|
135
|
+
}
|
|
136
|
+
if (value === undefined || value === null) {
|
|
137
|
+
value = "";
|
|
138
|
+
} else if (typeof value === "number") {
|
|
139
|
+
value = value.toString();
|
|
140
|
+
}
|
|
141
|
+
lines.push("\"".concat(fieldName, "\": ").concat(value));
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Add signature-params line with sorted components (keeping @ prefix)
|
|
145
|
+
var paramsComponents = sortedComponents.join(" ");
|
|
146
|
+
lines.push("\"@signature-params\": (".concat(paramsComponents, ");alg=\"hmac-sha256\";keyid=\"ao\""));
|
|
147
|
+
var signatureBase = lines.join("\n");
|
|
148
|
+
|
|
149
|
+
// Generate HMAC with key "ao"
|
|
150
|
+
// Convert string to Uint8Array
|
|
151
|
+
var messageBytes = new TextEncoder().encode(signatureBase);
|
|
152
|
+
var keyBytes = new TextEncoder().encode("ao");
|
|
153
|
+
var hmacResult = (0, _fastSha.hmac)(keyBytes, messageBytes);
|
|
154
|
+
return uint8ArrayToBase64url(hmacResult);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generate commitment ID based on the algorithm type
|
|
159
|
+
*
|
|
160
|
+
* @param {Object} commitment - The commitment object containing alg, signature, etc.
|
|
161
|
+
* @param {Object} fullMessage - The full message (required for HMAC)
|
|
162
|
+
* @returns {string} The commitment ID in base64url format
|
|
163
|
+
*/
|
|
164
|
+
function generateCommitmentId(commitment) {
|
|
165
|
+
var fullMessage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
166
|
+
switch (commitment.alg) {
|
|
167
|
+
case "rsa-pss-sha512":
|
|
168
|
+
case "ecdsa-p256-sha256":
|
|
169
|
+
return rsaid(commitment);
|
|
170
|
+
case "hmac-sha256":
|
|
171
|
+
if (!fullMessage) {
|
|
172
|
+
throw new Error("HMAC commitment IDs require full message context");
|
|
173
|
+
}
|
|
174
|
+
return hmacid(fullMessage);
|
|
175
|
+
default:
|
|
176
|
+
throw new Error("Unsupported algorithm: ".concat(commitment.alg));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Extract all commitment IDs from a HyperBEAM message
|
|
182
|
+
*
|
|
183
|
+
* @param {Object} message - The message with commitments
|
|
184
|
+
* @returns {Object} Map of commitment IDs to their types
|
|
185
|
+
*/
|
|
186
|
+
function extractCommitmentIds(message) {
|
|
187
|
+
var ids = {};
|
|
188
|
+
if (!message.commitments) {
|
|
189
|
+
return ids;
|
|
190
|
+
}
|
|
191
|
+
for (var _i = 0, _Object$entries = Object.entries(message.commitments); _i < _Object$entries.length; _i++) {
|
|
192
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
193
|
+
_id = _Object$entries$_i[0],
|
|
194
|
+
commitment = _Object$entries$_i[1];
|
|
195
|
+
ids[_id] = {
|
|
196
|
+
alg: commitment.alg,
|
|
197
|
+
committer: commitment.committer,
|
|
198
|
+
device: commitment["commitment-device"]
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return ids;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Verify a commitment ID matches the expected value
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} commitment - The commitment object
|
|
208
|
+
* @param {string} expectedId - The expected commitment ID
|
|
209
|
+
* @param {Object} fullMessage - The full message (required for HMAC)
|
|
210
|
+
* @returns {boolean} True if the ID matches
|
|
211
|
+
*/
|
|
212
|
+
function verifyCommitmentId(commitment, expectedId) {
|
|
213
|
+
var fullMessage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
214
|
+
try {
|
|
215
|
+
var calculatedId = generateCommitmentId(commitment, fullMessage);
|
|
216
|
+
return calculatedId === expectedId;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error("Error verifying commitment ID:", error);
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Convert Uint8Array to base64url string
|
|
225
|
+
*/
|
|
226
|
+
function uint8ArrayToBase64url(bytes) {
|
|
227
|
+
var binary = "";
|
|
228
|
+
for (var i = 0; i < bytes.length; i++) {
|
|
229
|
+
binary += String.fromCharCode(bytes[i]);
|
|
230
|
+
}
|
|
231
|
+
var base64 = btoa(binary);
|
|
232
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Parse structured field dictionary to extract components
|
|
237
|
+
* Handles format: name=(components);params
|
|
238
|
+
*/
|
|
239
|
+
function parseSignatureInput(sigInput) {
|
|
240
|
+
// Extract components from format: name=(components);params
|
|
241
|
+
var match = sigInput.match(/[^=]+=\(([^)]+)\)/);
|
|
242
|
+
if (!match) return [];
|
|
243
|
+
|
|
244
|
+
// Split components and clean quotes
|
|
245
|
+
return match[1].split(" ").map(function (c) {
|
|
246
|
+
return c.replace(/"/g, "");
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Calculate HMAC commitment ID for HyperBEAM messages
|
|
252
|
+
*/
|
|
253
|
+
function calculateHmacId(message) {
|
|
254
|
+
if (!message["signature-input"]) {
|
|
255
|
+
throw new Error("HMAC calculation requires signature-input");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Parse components from signature-input
|
|
259
|
+
var components = parseSignatureInput(message["signature-input"]);
|
|
260
|
+
|
|
261
|
+
// Sort components AS-IS (with @ prefix)
|
|
262
|
+
var sortedComponents = _toConsumableArray(components).sort();
|
|
263
|
+
|
|
264
|
+
// Build signature base in sorted order
|
|
265
|
+
var lines = [];
|
|
266
|
+
var _iterator = _createForOfIteratorHelper(sortedComponents),
|
|
267
|
+
_step;
|
|
268
|
+
try {
|
|
269
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
270
|
+
var component = _step.value;
|
|
271
|
+
var fieldName = component;
|
|
272
|
+
var value = void 0;
|
|
273
|
+
|
|
274
|
+
// For derived components (starting with @), remove @ in the signature base
|
|
275
|
+
if (component.startsWith("@")) {
|
|
276
|
+
fieldName = component.substring(1);
|
|
277
|
+
value = message[fieldName];
|
|
278
|
+
} else {
|
|
279
|
+
value = message[component];
|
|
280
|
+
}
|
|
281
|
+
if (value === undefined || value === null) {
|
|
282
|
+
value = "";
|
|
283
|
+
} else if (typeof value === "number") {
|
|
284
|
+
value = value.toString();
|
|
285
|
+
}
|
|
286
|
+
lines.push("\"".concat(fieldName, "\": ").concat(value));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Add signature-params line with sorted components (keeping @ prefix)
|
|
290
|
+
} catch (err) {
|
|
291
|
+
_iterator.e(err);
|
|
292
|
+
} finally {
|
|
293
|
+
_iterator.f();
|
|
294
|
+
}
|
|
295
|
+
var paramsComponents = sortedComponents.join(" ");
|
|
296
|
+
lines.push("\"@signature-params\": (".concat(paramsComponents, ");alg=\"hmac-sha256\";keyid=\"ao\""));
|
|
297
|
+
var signatureBase = lines.join("\n");
|
|
298
|
+
|
|
299
|
+
// Generate HMAC with key "ao"
|
|
300
|
+
var messageBytes = new TextEncoder().encode(signatureBase);
|
|
301
|
+
var keyBytes = new TextEncoder().encode("ao");
|
|
302
|
+
var hmacResult = (0, _fastSha.hmac)(keyBytes, messageBytes);
|
|
303
|
+
return uint8ArrayToBase64url(hmacResult);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Calculate unsigned message ID following the exact Erlang flow
|
|
308
|
+
*/
|
|
309
|
+
function calculateUnsignedId(message) {
|
|
310
|
+
// Derived components from Erlang ?DERIVED_COMPONENTS
|
|
311
|
+
var DERIVED_COMPONENTS = ["method", "target-uri", "authority", "scheme", "request-target", "path", "query", "query-param", "status"];
|
|
312
|
+
|
|
313
|
+
// Convert message for httpsig format
|
|
314
|
+
var httpsigMsg = {};
|
|
315
|
+
for (var _i2 = 0, _Object$entries2 = Object.entries(message); _i2 < _Object$entries2.length; _i2++) {
|
|
316
|
+
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
|
317
|
+
key = _Object$entries2$_i[0],
|
|
318
|
+
value = _Object$entries2$_i[1];
|
|
319
|
+
httpsigMsg[key.toLowerCase()] = value;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Get keys and add @ to derived components
|
|
323
|
+
var keys = Object.keys(httpsigMsg);
|
|
324
|
+
var componentsWithPrefix = keys.map(function (key) {
|
|
325
|
+
// Check if this is a derived component
|
|
326
|
+
if (DERIVED_COMPONENTS.includes(key.replace(/_/g, "-"))) {
|
|
327
|
+
return "@" + key;
|
|
328
|
+
}
|
|
329
|
+
return key;
|
|
330
|
+
}).sort(); // Sort AFTER adding @ prefix
|
|
331
|
+
|
|
332
|
+
// Build signature base - use the components in order
|
|
333
|
+
var lines = [];
|
|
334
|
+
var _iterator2 = _createForOfIteratorHelper(componentsWithPrefix),
|
|
335
|
+
_step2;
|
|
336
|
+
try {
|
|
337
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
338
|
+
var component = _step2.value;
|
|
339
|
+
var _key = component.replace("@", "");
|
|
340
|
+
var _value = httpsigMsg[_key];
|
|
341
|
+
var valueStr = typeof _value === "string" ? _value : String(_value);
|
|
342
|
+
lines.push("\"".concat(_key, "\": ").concat(valueStr));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Add signature-params line with the @ prefixes
|
|
346
|
+
} catch (err) {
|
|
347
|
+
_iterator2.e(err);
|
|
348
|
+
} finally {
|
|
349
|
+
_iterator2.f();
|
|
350
|
+
}
|
|
351
|
+
var componentsList = componentsWithPrefix.map(function (k) {
|
|
352
|
+
return "\"".concat(k, "\"");
|
|
353
|
+
}).join(" ");
|
|
354
|
+
lines.push("\"@signature-params\": (".concat(componentsList, ");alg=\"hmac-sha256\";keyid=\"ao\""));
|
|
355
|
+
var signatureBase = lines.join("\n");
|
|
356
|
+
|
|
357
|
+
// HMAC with key "ao"
|
|
358
|
+
var messageBytes = new TextEncoder().encode(signatureBase);
|
|
359
|
+
var keyBytes = new TextEncoder().encode("ao");
|
|
360
|
+
var hmacResult = (0, _fastSha.hmac)(keyBytes, messageBytes);
|
|
361
|
+
return uint8ArrayToBase64url(hmacResult);
|
|
362
|
+
}
|
|
363
|
+
function id(message) {
|
|
364
|
+
// Get commitment IDs
|
|
365
|
+
var commitmentIds = Object.keys(message.commitments || {});
|
|
366
|
+
if (commitmentIds.length === 0) {
|
|
367
|
+
// No commitments - calculate unsigned ID using HMAC
|
|
368
|
+
return calculateUnsignedId(message);
|
|
369
|
+
} else if (commitmentIds.length === 1) {
|
|
370
|
+
// Single commitment - the ID is just the commitment ID
|
|
371
|
+
return commitmentIds[0];
|
|
372
|
+
} else {
|
|
373
|
+
// Multiple commitments - sort, join with ", ", and hash
|
|
374
|
+
var sortedIds = commitmentIds.sort();
|
|
375
|
+
var idsLine = sortedIds.join(", ");
|
|
376
|
+
|
|
377
|
+
// Calculate SHA-256 hash using fast-sha256
|
|
378
|
+
var encoder = new TextEncoder();
|
|
379
|
+
var data = encoder.encode(idsLine);
|
|
380
|
+
var hashArray = (0, _fastSha.hash)(data);
|
|
381
|
+
|
|
382
|
+
// Convert to base64url
|
|
383
|
+
return uint8ArrayToBase64url(hashArray);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Export all functions
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Calculate the next base from a hashpath
|
|
390
|
+
* A hashpath has the format: base/request
|
|
391
|
+
* The next base is calculated as: sha256(base + request)
|
|
392
|
+
*
|
|
393
|
+
* @param {string} hashpath - The current hashpath in format "base/request"
|
|
394
|
+
* @returns {string} The next base in base64url format
|
|
395
|
+
*/
|
|
396
|
+
function base(hashpath) {
|
|
397
|
+
// Split the hashpath into base and request
|
|
398
|
+
var parts = hashpath.split("/");
|
|
399
|
+
if (parts.length !== 2) {
|
|
400
|
+
throw new Error("Invalid hashpath format. Expected 'base/request'");
|
|
401
|
+
}
|
|
402
|
+
var _parts = _slicedToArray(parts, 2),
|
|
403
|
+
base = _parts[0],
|
|
404
|
+
request = _parts[1];
|
|
405
|
+
|
|
406
|
+
// Convert base64url to native binary (Uint8Array)
|
|
407
|
+
var baseBinary = base64urlToUint8Array(base);
|
|
408
|
+
var requestBinary = base64urlToUint8Array(request);
|
|
409
|
+
|
|
410
|
+
// Concatenate base and request
|
|
411
|
+
var combined = new Uint8Array(baseBinary.length + requestBinary.length);
|
|
412
|
+
combined.set(baseBinary, 0);
|
|
413
|
+
combined.set(requestBinary, baseBinary.length);
|
|
414
|
+
|
|
415
|
+
// Calculate SHA256 of the combined data
|
|
416
|
+
var nextBaseHash = (0, _fastSha.hash)(combined);
|
|
417
|
+
|
|
418
|
+
// Convert to base64url
|
|
419
|
+
return uint8ArrayToBase64url(nextBaseHash);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Calculate the next hashpath given the current hashpath and a new message
|
|
424
|
+
*
|
|
425
|
+
* @param {string} currentHashpath - The current hashpath (or null for first operation)
|
|
426
|
+
* @param {Object} newMessage - The new message/request
|
|
427
|
+
* @returns {string} The next hashpath in format "nextBase/newMessageId"
|
|
428
|
+
*/
|
|
429
|
+
function hashpath(currentHashpath, newMessage) {
|
|
430
|
+
// Calculate the ID of the new message
|
|
431
|
+
var newMessageId = id(newMessage);
|
|
432
|
+
if (!currentHashpath) {
|
|
433
|
+
// First operation: the hashpath is just the message ID
|
|
434
|
+
// In the Erlang code, the first hashpath is "baseId/requestId"
|
|
435
|
+
// where baseId is the ID of the initial message
|
|
436
|
+
throw new Error("For first operation, provide the base message ID as currentHashpath");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Check if this is the first operation (currentHashpath is just an ID, not a path)
|
|
440
|
+
if (!currentHashpath.includes("/")) {
|
|
441
|
+
// First operation: currentHashpath is the base message ID
|
|
442
|
+
return "".concat(currentHashpath, "/").concat(newMessageId);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Subsequent operations: calculate the next base from current hashpath
|
|
446
|
+
var nextBase = base(currentHashpath);
|
|
447
|
+
|
|
448
|
+
// Return the new hashpath
|
|
449
|
+
return "".concat(nextBase, "/").concat(newMessageId);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Helper function to convert base64url string to Uint8Array
|
|
454
|
+
*/
|
|
455
|
+
function base64urlToUint8Array(base64url) {
|
|
456
|
+
// Convert base64url to base64
|
|
457
|
+
var base64 = base64urlToBase64(base64url);
|
|
458
|
+
|
|
459
|
+
// Decode base64 to binary string
|
|
460
|
+
var binaryString = atob(base64);
|
|
461
|
+
|
|
462
|
+
// Convert binary string to Uint8Array
|
|
463
|
+
var bytes = new Uint8Array(binaryString.length);
|
|
464
|
+
for (var i = 0; i < binaryString.length; i++) {
|
|
465
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
466
|
+
}
|
|
467
|
+
return bytes;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Export the new functions
|
package/cjs/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "base", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _id.base;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "hashpath", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _id.hashpath;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "hmacid", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function get() {
|
|
21
|
+
return _id.hmacid;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "id", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function get() {
|
|
27
|
+
return _id.id;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "rsaid", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function get() {
|
|
33
|
+
return _id.rsaid;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "send", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function get() {
|
|
39
|
+
return _send.send;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(exports, "sign", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function get() {
|
|
45
|
+
return _signer.sign;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "signer", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function get() {
|
|
51
|
+
return _signer.signer;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "toAddr", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function get() {
|
|
57
|
+
return _utils.toAddr;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
var _id = require("./id.js");
|
|
61
|
+
var _utils = require("./utils.js");
|
|
62
|
+
var _signer = require("./signer.js");
|
|
63
|
+
var _send = require("./send.js");
|