@request-seal/core 0.2.0 → 0.4.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/CHANGELOG.md +37 -1
- package/README.md +10 -9
- package/dist/adapters/node-http/index.d.ts +8 -1
- package/dist/adapters/node-http/index.js +21 -5
- package/dist/constants.d.ts +4 -4
- package/dist/constants.js +2 -2
- package/dist/crypto/algorithm.d.ts +4 -0
- package/dist/crypto/algorithm.js +12 -0
- package/dist/discovery/body.d.ts +12 -2
- package/dist/discovery/body.js +33 -11
- package/dist/discovery/cache.d.ts +13 -3
- package/dist/discovery/cache.js +103 -39
- package/dist/discovery/headers.d.ts +2 -0
- package/dist/discovery/headers.js +27 -1
- package/dist/discovery/index.d.ts +9 -2
- package/dist/discovery/index.js +22 -6
- package/dist/discovery/node.d.ts +6 -2
- package/dist/discovery/node.js +124 -18
- package/dist/discovery/proof.js +2 -2
- package/dist/discovery/snapshot.js +3 -0
- package/dist/errors/parity.d.ts +29 -3
- package/dist/errors/parity.js +32 -3
- package/dist/errors/types.d.ts +4 -2
- package/dist/errors/types.js +14 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/jose/nested.js +23 -1
- package/dist/key_handle.js +23 -1
- package/dist/message/index.js +2 -1
- package/dist/policy.d.ts +13 -1
- package/dist/policy.js +13 -1
- package/dist/quorum/evaluation.d.ts +1 -1
- package/dist/quorum/evaluation.js +18 -4
- package/dist/replay/postgres.d.ts +2 -0
- package/dist/replay/postgres.js +6 -0
- package/dist/sign.d.ts +22 -1
- package/dist/sign.js +28 -6
- package/dist/signature-fields.d.ts +5 -1
- package/dist/signature-fields.js +9 -1
- package/dist/telemetry.d.ts +43 -0
- package/dist/telemetry.js +86 -0
- package/dist/verify-quorum.js +34 -9
- package/dist/verify.d.ts +19 -1
- package/dist/verify.js +48 -6
- package/dist/web-bot-auth/verify.js +7 -3
- package/package.json +13 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Result } from "./result.ts";
|
|
2
|
+
/** The versioned event names (v1), mirroring the reference telemetry contract. */
|
|
3
|
+
export type TelemetryEventName = "verify" | "verifyQuorum" | "webBotAuthVerify" | "replayClaim" | "custodySign";
|
|
4
|
+
/** What an event reports: the operation's outcome within a closed vocabulary. */
|
|
5
|
+
export type TelemetryOutcome = "ok" | "error" | "claimed" | "already_claimed";
|
|
6
|
+
/** One bounded, low-cardinality observation of a RequestSeal operation. */
|
|
7
|
+
export type TelemetryEvent = Readonly<{
|
|
8
|
+
event: TelemetryEventName;
|
|
9
|
+
outcome: TelemetryOutcome;
|
|
10
|
+
reason: string | null;
|
|
11
|
+
layer: string | null;
|
|
12
|
+
detail: string | null;
|
|
13
|
+
durationMs: number;
|
|
14
|
+
}>;
|
|
15
|
+
/** A caller-owned subscriber; handlers own storage and aggregation. */
|
|
16
|
+
export type TelemetrySubscriber = (event: TelemetryEvent) => void;
|
|
17
|
+
/** A caller-owned attachment; `detach` stops delivery and is idempotent. */
|
|
18
|
+
export type TelemetryHandle = Readonly<{
|
|
19
|
+
/** Stop delivering events to this attachment; calling it again does nothing. */
|
|
20
|
+
detach(): void;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Emit one event to every attached subscriber. Telemetry is an optional path:
|
|
24
|
+
* a throwing subscriber degrades silently and never fails the operation it
|
|
25
|
+
* observes. Payloads carry closed vocabulary only — never labels, key IDs,
|
|
26
|
+
* URLs, principals, nonces, bytes, or exception text.
|
|
27
|
+
*/
|
|
28
|
+
export declare function emit(event: TelemetryEventName, durationMs: number, outcome: TelemetryOutcome, error?: unknown): void;
|
|
29
|
+
/** Measure an operation and emit its stop event with the result's metadata. */
|
|
30
|
+
export declare function span<T>(event: TelemetryEventName, work: () => Promise<T>, outcome: (result: T) => TelemetryOutcome, errorOf: (result: T) => unknown): Promise<T>;
|
|
31
|
+
/** The captured monotonic clock used for event durations, in milliseconds. */
|
|
32
|
+
export declare function monotonicMs(): number;
|
|
33
|
+
/** Attach a telemetry subscriber; at most sixteen run at once. */
|
|
34
|
+
export declare function attach(input: unknown): Result<TelemetryHandle>;
|
|
35
|
+
/** The v1 event names, as documented in the observability reference. */
|
|
36
|
+
export declare const Telemetry: Readonly<{
|
|
37
|
+
/** The v1 event names. */
|
|
38
|
+
events(): readonly TelemetryEventName[];
|
|
39
|
+
/** Attach a telemetry subscriber; the handle's `detach` stops delivery. */
|
|
40
|
+
attach: typeof attach;
|
|
41
|
+
/** Check the private brand of a telemetry attachment handle. */
|
|
42
|
+
isHandle(value: unknown): value is TelemetryHandle;
|
|
43
|
+
}>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { err, ok } from "./result.js";
|
|
2
|
+
import { coreError, isRequestSealError, ruleId } from "./errors/types.js";
|
|
3
|
+
const names = Object.freeze([
|
|
4
|
+
"verify",
|
|
5
|
+
"verifyQuorum",
|
|
6
|
+
"webBotAuthVerify",
|
|
7
|
+
"replayClaim",
|
|
8
|
+
"custodySign",
|
|
9
|
+
]);
|
|
10
|
+
const MAX_SUBSCRIBERS = 16;
|
|
11
|
+
const handles = new WeakSet();
|
|
12
|
+
let subscribers = Object.freeze([]);
|
|
13
|
+
// A captured monotonic clock: replacing the global later cannot change a duration.
|
|
14
|
+
const now = performance.now.bind(performance);
|
|
15
|
+
/**
|
|
16
|
+
* Emit one event to every attached subscriber. Telemetry is an optional path:
|
|
17
|
+
* a throwing subscriber degrades silently and never fails the operation it
|
|
18
|
+
* observes. Payloads carry closed vocabulary only — never labels, key IDs,
|
|
19
|
+
* URLs, principals, nonces, bytes, or exception text.
|
|
20
|
+
*/
|
|
21
|
+
export function emit(event, durationMs, outcome, error) {
|
|
22
|
+
if (subscribers.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
const payload = Object.freeze({
|
|
25
|
+
event,
|
|
26
|
+
outcome,
|
|
27
|
+
reason: isRequestSealError(error) ? ruleId(error) : null,
|
|
28
|
+
layer: isRequestSealError(error) && "layer" in error ? error.layer : null,
|
|
29
|
+
detail: isRequestSealError(error) && "detail" in error && typeof error.detail === "string" ? error.detail : null,
|
|
30
|
+
durationMs,
|
|
31
|
+
});
|
|
32
|
+
for (const subscriber of subscribers) {
|
|
33
|
+
try {
|
|
34
|
+
subscriber(payload);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Degrade: a defective observer is not the observed operation's failure.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Measure an operation and emit its stop event with the result's metadata. */
|
|
42
|
+
export async function span(event, work, outcome, errorOf) {
|
|
43
|
+
const start = now();
|
|
44
|
+
const result = await work();
|
|
45
|
+
emit(event, now() - start, outcome(result), errorOf(result));
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
/** The captured monotonic clock used for event durations, in milliseconds. */
|
|
49
|
+
export function monotonicMs() { return now(); }
|
|
50
|
+
/** Attach a telemetry subscriber; at most sixteen run at once. */
|
|
51
|
+
export function attach(input) {
|
|
52
|
+
if (typeof input !== "function")
|
|
53
|
+
return err(coreError("invalid_options", "input"));
|
|
54
|
+
if (subscribers.length >= MAX_SUBSCRIBERS)
|
|
55
|
+
return err(coreError("invalid_options", "input"));
|
|
56
|
+
const subscriber = input;
|
|
57
|
+
subscribers = Object.freeze([...subscribers, subscriber]);
|
|
58
|
+
let live = true;
|
|
59
|
+
const handle = Object.freeze({
|
|
60
|
+
detach() {
|
|
61
|
+
if (!live)
|
|
62
|
+
return;
|
|
63
|
+
live = false;
|
|
64
|
+
// Remove exactly one occurrence: two attachments of one function are
|
|
65
|
+
// independently detachable, mirroring the reference's handler ids.
|
|
66
|
+
const index = subscribers.indexOf(subscriber);
|
|
67
|
+
if (index >= 0)
|
|
68
|
+
subscribers = Object.freeze(subscribers.slice(0, index).concat(subscribers.slice(index + 1)));
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
handles.add(handle);
|
|
72
|
+
return ok(handle);
|
|
73
|
+
}
|
|
74
|
+
/** The v1 event names, as documented in the observability reference. */
|
|
75
|
+
export const Telemetry = Object.freeze({
|
|
76
|
+
/** The v1 event names. */
|
|
77
|
+
events() {
|
|
78
|
+
return names;
|
|
79
|
+
},
|
|
80
|
+
/** Attach a telemetry subscriber; the handle's `detach` stops delivery. */
|
|
81
|
+
attach,
|
|
82
|
+
/** Check the private brand of a telemetry attachment handle. */
|
|
83
|
+
isHandle(value) {
|
|
84
|
+
return !!value && typeof value === "object" && handles.has(value);
|
|
85
|
+
},
|
|
86
|
+
});
|
package/dist/verify-quorum.js
CHANGED
|
@@ -3,14 +3,18 @@ import { isMessage, Message } from "./message/index.js";
|
|
|
3
3
|
import { isQuorum } from "./quorum.js";
|
|
4
4
|
import { isContext, withDeadline, remainingMs } from "./context.js";
|
|
5
5
|
import { isAcceptSignature, applicable, } from "./accept-signature.js";
|
|
6
|
-
import { dictionaries, parameters, identities, ensure, fail,
|
|
6
|
+
import { dictionaries, parameters, identities, ensure, fail, envelope, } from "./signature-fields.js";
|
|
7
7
|
import { verifyCandidate } from "./verify.js";
|
|
8
|
+
import { span } from "./telemetry.js";
|
|
8
9
|
import { evaluateQuorum } from "./quorum/evaluation.js";
|
|
9
10
|
import { completeQuorum, } from "./quorum/verification.js";
|
|
10
11
|
import { custodyError, isRequestSealError } from "./errors/types.js";
|
|
11
12
|
import { ok, err } from "./result.js";
|
|
12
13
|
/** Verify bounded HTTP signatures and evaluate the configured quorum policy. */
|
|
13
|
-
export
|
|
14
|
+
export function verifyQuorum(message, quorum, options) {
|
|
15
|
+
return span("verifyQuorum", () => verifyQuorumSpanned(message, quorum, options), r => r.ok ? "ok" : "error", r => r.ok ? undefined : r.error);
|
|
16
|
+
}
|
|
17
|
+
async function verifyQuorumSpanned(message, quorum, options) {
|
|
14
18
|
try {
|
|
15
19
|
const a = snapshotOptions(options, ["acceptSignature", "context"]);
|
|
16
20
|
ensure(a.ok, "invalid_options", "input");
|
|
@@ -56,10 +60,30 @@ export async function verifyQuorum(message, quorum, options) {
|
|
|
56
60
|
let qualified = false, last;
|
|
57
61
|
const baseCache = new Map();
|
|
58
62
|
for (const slot of slots) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
let r;
|
|
64
|
+
try {
|
|
65
|
+
r = await verifyCandidate(m, slot.policy, {
|
|
66
|
+
label: l,
|
|
67
|
+
context: c.value,
|
|
68
|
+
}, { input, signature: signatures.get(l), baseCache });
|
|
69
|
+
}
|
|
70
|
+
catch (fault) {
|
|
71
|
+
// Per-label rescue isolates a defective label as its own
|
|
72
|
+
// nonqualifying internal fact, never a whole-call failure.
|
|
73
|
+
if (isRequestSealError(fault) && fault.kind === "custody")
|
|
74
|
+
return err(fault);
|
|
75
|
+
const faulted = envelope(fault);
|
|
76
|
+
if (faulted.kind !== "core")
|
|
77
|
+
throw fault;
|
|
78
|
+
last = {
|
|
79
|
+
label: l,
|
|
80
|
+
slot: slot.id,
|
|
81
|
+
reason: faulted.reason,
|
|
82
|
+
layer: faulted.layer,
|
|
83
|
+
};
|
|
84
|
+
facts.push(last);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
63
87
|
if (r.ok) {
|
|
64
88
|
const record = Object.freeze({
|
|
65
89
|
slot,
|
|
@@ -108,8 +132,9 @@ export async function verifyQuorum(message, quorum, options) {
|
|
|
108
132
|
const original = candidates.find((c) => c.slot === r.slot && c.label === r.label);
|
|
109
133
|
results[r.label] = verified.get(original);
|
|
110
134
|
}
|
|
111
|
-
|
|
112
|
-
|
|
135
|
+
// The wall-clock bound lives in the assignment search: an accepted
|
|
136
|
+
// assignment, including one accepted at deadline exhaustion, completes.
|
|
137
|
+
// The remaining work here is synchronous and bounded.
|
|
113
138
|
return completeQuorum({
|
|
114
139
|
profile: { name: "rfc9421" },
|
|
115
140
|
mode: quorum.mode,
|
|
@@ -140,6 +165,6 @@ export async function verifyQuorum(message, quorum, options) {
|
|
|
140
165
|
catch (e) {
|
|
141
166
|
if (isRequestSealError(e) && e.kind === "custody")
|
|
142
167
|
return err(e);
|
|
143
|
-
return err(
|
|
168
|
+
return err(envelope(e));
|
|
144
169
|
}
|
|
145
170
|
}
|
package/dist/verify.d.ts
CHANGED
|
@@ -20,7 +20,25 @@ type ParsedCandidate = Readonly<{
|
|
|
20
20
|
baseCache: BaseCache;
|
|
21
21
|
}>;
|
|
22
22
|
export declare function verifyLabel(message: unknown, policy: unknown, options: unknown, observeIdentity?: (identity: KeyIdentity) => void, parsed?: ParsedCandidate, profile?: ReplayFacts["profile"]): Promise<Result<Verification>>;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Verify one HTTP signature under an explicit branded policy.
|
|
25
|
+
*
|
|
26
|
+
* Checks exactly the named label; it never tries other labels. Success means the
|
|
27
|
+
* cryptography, coverage, freshness, content, and replay layers all passed. It does not
|
|
28
|
+
* authorize: the Verification records `authorization: "not_evaluated"`.
|
|
29
|
+
*
|
|
30
|
+
* @param message - A branded Message carrying the signature.
|
|
31
|
+
* @param policy - A branded Policy from `Policy.create`.
|
|
32
|
+
* @param options - `{label, context?, representation?, digestState?}`. `representation` is a
|
|
33
|
+
* complete retained Body and needs a `"representation"` content policy. `digestState` is a
|
|
34
|
+
* DigestState of the policy's content kind that you fed with a streamed body; verify finishes
|
|
35
|
+
* it. The two are mutually exclusive.
|
|
36
|
+
* @returns `ok(verification)`, or a bounded error such as `core` `crypto.invalid_signature`,
|
|
37
|
+
* `freshness.expired`, `content.digest_mismatch`, `key.unknown_key`, or `replay.replayed`.
|
|
38
|
+
* @see [Signing and verifying guide](https://github.com/baselabs/request-seal-typescript/blob/main/docs/guides/signing-and-verifying.md),
|
|
39
|
+
* [reference](https://github.com/baselabs/request-seal-typescript/blob/main/docs/reference/sign-and-verify.md), and the
|
|
40
|
+
* [error reasons](https://github.com/baselabs/request-seal-typescript/blob/main/docs/reference/errors.md).
|
|
41
|
+
*/
|
|
24
42
|
export declare function verify(message: unknown, policy: unknown, options: unknown): Promise<Result<Verification>>;
|
|
25
43
|
/** Internal composition of the single-label pipeline; identities stay private. */
|
|
26
44
|
export declare function verifyCandidate(message: unknown, policy: Policy, options: unknown, parsed?: ParsedCandidate): Promise<Result<Readonly<{
|
package/dist/verify.js
CHANGED
|
@@ -10,7 +10,8 @@ import { isPublicKey } from "./public_key.js";
|
|
|
10
10
|
import { isKeyIdentity, KeyIdentity } from "./key_identity.js";
|
|
11
11
|
import { build } from "./signature-base/index.js";
|
|
12
12
|
import { digestField, checkDigest, isDigestState } from "./digest.js";
|
|
13
|
-
import { label, dictionaries, validInner, parameters, identities, ensure, fail, bounded, } from "./signature-fields.js";
|
|
13
|
+
import { label, dictionaries, validInner, parameters, identities, ensure, fail, bounded, envelope, } from "./signature-fields.js";
|
|
14
|
+
import { emit, monotonicMs, span } from "./telemetry.js";
|
|
14
15
|
import { completed, } from "./verification.js";
|
|
15
16
|
import { createClaim, retainUntil as retention } from "./replay/claim.js";
|
|
16
17
|
import { createReceipt } from "./replay/receipt.js";
|
|
@@ -126,6 +127,19 @@ async function replay(params, algorithm, fresh, policy, context, profile) {
|
|
|
126
127
|
}
|
|
127
128
|
/** Internal shared commit boundary; profile facts are supplied only after authentication. */
|
|
128
129
|
export async function commitReplay(facts, retainUntil, policy, context) {
|
|
130
|
+
const start = monotonicMs();
|
|
131
|
+
try {
|
|
132
|
+
const result = await commitReplaySpanned(facts, retainUntil, policy, context);
|
|
133
|
+
emit("replayClaim", monotonicMs() - start, "claimed");
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
const replayed = isRequestSealError(error) && error.kind === "core" && error.reason === "replayed";
|
|
138
|
+
emit("replayClaim", monotonicMs() - start, replayed ? "already_claimed" : "error", error);
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function commitReplaySpanned(facts, retainUntil, policy, context) {
|
|
129
143
|
const child = withDeadline({ parent: context, timeoutMs: policy.timeoutMs });
|
|
130
144
|
ensure(child.ok, "store_timeout", "replay");
|
|
131
145
|
try {
|
|
@@ -371,19 +385,47 @@ export async function verifyLabel(message, policy, options, observeIdentity, par
|
|
|
371
385
|
profile, content: contentResult.value, freshness: fresh,
|
|
372
386
|
replay: replayFacts, principal: "unattributed", authorization: "not_evaluated",
|
|
373
387
|
});
|
|
374
|
-
if (result.ok && identity)
|
|
375
|
-
|
|
388
|
+
if (result.ok && identity) {
|
|
389
|
+
// An extension pipeline step is a caller callback: its fault keeps the
|
|
390
|
+
// profile's deliberate invalid_policy classification, like a failing
|
|
391
|
+
// signer keeps signer_failed.
|
|
392
|
+
try {
|
|
393
|
+
observeIdentity(identity);
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
fail("invalid_policy", "input");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
376
399
|
return result;
|
|
377
400
|
}
|
|
378
401
|
catch (e) {
|
|
379
402
|
if (isRequestSealError(e) && e.kind === "custody" && e.reason === "deadline_exceeded")
|
|
380
403
|
return err(e);
|
|
381
|
-
return err(
|
|
404
|
+
return err(envelope(e));
|
|
382
405
|
}
|
|
383
406
|
}
|
|
384
|
-
/**
|
|
407
|
+
/**
|
|
408
|
+
* Verify one HTTP signature under an explicit branded policy.
|
|
409
|
+
*
|
|
410
|
+
* Checks exactly the named label; it never tries other labels. Success means the
|
|
411
|
+
* cryptography, coverage, freshness, content, and replay layers all passed. It does not
|
|
412
|
+
* authorize: the Verification records `authorization: "not_evaluated"`.
|
|
413
|
+
*
|
|
414
|
+
* @param message - A branded Message carrying the signature.
|
|
415
|
+
* @param policy - A branded Policy from `Policy.create`.
|
|
416
|
+
* @param options - `{label, context?, representation?, digestState?}`. `representation` is a
|
|
417
|
+
* complete retained Body and needs a `"representation"` content policy. `digestState` is a
|
|
418
|
+
* DigestState of the policy's content kind that you fed with a streamed body; verify finishes
|
|
419
|
+
* it. The two are mutually exclusive.
|
|
420
|
+
* @returns `ok(verification)`, or a bounded error such as `core` `crypto.invalid_signature`,
|
|
421
|
+
* `freshness.expired`, `content.digest_mismatch`, `key.unknown_key`, or `replay.replayed`.
|
|
422
|
+
* @see [Signing and verifying guide](https://github.com/baselabs/request-seal-typescript/blob/main/docs/guides/signing-and-verifying.md),
|
|
423
|
+
* [reference](https://github.com/baselabs/request-seal-typescript/blob/main/docs/reference/sign-and-verify.md), and the
|
|
424
|
+
* [error reasons](https://github.com/baselabs/request-seal-typescript/blob/main/docs/reference/errors.md).
|
|
425
|
+
*/
|
|
385
426
|
export function verify(message, policy, options) {
|
|
386
|
-
|
|
427
|
+
// The public entry carries the telemetry span; internal per-label calls do not.
|
|
428
|
+
return span("verify", () => verifyLabel(message, policy, options), r => r.ok ? "ok" : "error", r => r.ok ? undefined : r.error);
|
|
387
429
|
}
|
|
388
430
|
/** Internal composition of the single-label pipeline; identities stay private. */
|
|
389
431
|
export async function verifyCandidate(message, policy, options, parsed) {
|
|
@@ -10,11 +10,12 @@ import { isDiscoverySource, sourceOrigin, thumbprintId, } from "../discovery/sou
|
|
|
10
10
|
import { isKeySet, isResolution } from "../discovery/body.js";
|
|
11
11
|
import { isPublicKey } from "../public_key.js";
|
|
12
12
|
import { coreError, isRequestSealError, } from "../errors/types.js";
|
|
13
|
-
import { dictionaries, validInner, parameters, identities, ensure, fail,
|
|
13
|
+
import { dictionaries, validInner, parameters, identities, ensure, fail, envelope, } from "../signature-fields.js";
|
|
14
14
|
import { CLOCK_MAX_SECONDS } from "../constants.js";
|
|
15
15
|
import { retentionEnd } from "../replay/claim.js";
|
|
16
16
|
import { agents, identifier, originAgent, component, required, nested, schemas, } from "./support.js";
|
|
17
17
|
import { WEB_BOT_AUTH_PROFILE, completedEnvelope, } from "./verification.js";
|
|
18
|
+
import { span } from "../telemetry.js";
|
|
18
19
|
const testKeys = new Set([
|
|
19
20
|
"BHj8s0GPnMEQtkaULIM-PLgEhLBbuGUQ1vMxmBWZzEo",
|
|
20
21
|
"oD0HwocPBSfpNy5W3bpJeyFGY_IQ_YpqxSjQ3Yd-CLA",
|
|
@@ -180,7 +181,10 @@ async function resolve(agent, label, params, p, c) {
|
|
|
180
181
|
};
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
|
-
export
|
|
184
|
+
export function verifyWebBotAuth(message, policy, options = {}) {
|
|
185
|
+
return span("webBotAuthVerify", () => verifyWebBotAuthSpanned(message, policy, options), r => r.ok ? "ok" : "error", r => r.ok ? undefined : r.error);
|
|
186
|
+
}
|
|
187
|
+
async function verifyWebBotAuthSpanned(message, policy, options = {}) {
|
|
184
188
|
let owned;
|
|
185
189
|
try {
|
|
186
190
|
ensure(isWebBotAuthPolicy(policy), "invalid_policy", "input");
|
|
@@ -336,7 +340,7 @@ export async function verifyWebBotAuth(message, policy, options = {}) {
|
|
|
336
340
|
catch (e) {
|
|
337
341
|
if (isRequestSealError(e))
|
|
338
342
|
return err(e);
|
|
339
|
-
return err(
|
|
343
|
+
return err(envelope(e));
|
|
340
344
|
}
|
|
341
345
|
finally {
|
|
342
346
|
if (owned)
|
package/package.json
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@request-seal/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Standards-based HTTP message signatures and JOSE for web-standard runtimes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"http-message-signatures",
|
|
9
|
+
"rfc9421",
|
|
10
|
+
"rfc9530",
|
|
11
|
+
"content-digest",
|
|
12
|
+
"web-bot-auth",
|
|
13
|
+
"jose",
|
|
14
|
+
"jws",
|
|
15
|
+
"jwe",
|
|
16
|
+
"webcrypto",
|
|
17
|
+
"replay-protection"
|
|
18
|
+
],
|
|
7
19
|
"main": "./dist/index.js",
|
|
8
20
|
"types": "./dist/index.d.ts",
|
|
9
21
|
"exports": {
|