@uncefact/untp-utils 0.1.0 → 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 +23 -1
- package/build/artefacts/detect-version-from-context.d.ts +46 -0
- package/build/artefacts/detect-version-from-context.js +77 -0
- package/build/artefacts/detect-version-from-context.js.map +1 -0
- package/build/artefacts/detect-version-from-context.test.d.ts +1 -0
- package/build/artefacts/detect-version-from-context.test.js +69 -0
- package/build/artefacts/detect-version-from-context.test.js.map +1 -0
- package/build/artefacts/index.d.ts +3 -0
- package/build/artefacts/index.js +4 -0
- package/build/artefacts/index.js.map +1 -0
- package/build/artefacts/urls.d.ts +79 -0
- package/build/artefacts/urls.js +133 -0
- package/build/artefacts/urls.js.map +1 -0
- package/build/artefacts/urls.test.d.ts +1 -0
- package/build/artefacts/urls.test.js +91 -0
- package/build/artefacts/urls.test.js.map +1 -0
- package/build/artefacts/version.d.ts +9 -0
- package/build/artefacts/version.js +17 -0
- package/build/artefacts/version.js.map +1 -0
- package/build/artefacts/version.test.d.ts +1 -0
- package/build/artefacts/version.test.js +16 -0
- package/build/artefacts/version.test.js.map +1 -0
- package/build/cache/in-memory-ttl-cache.d.ts +2 -0
- package/build/cache/in-memory-ttl-cache.js +76 -0
- package/build/cache/in-memory-ttl-cache.js.map +1 -0
- package/build/cache/in-memory-ttl-cache.test.d.ts +1 -0
- package/build/cache/in-memory-ttl-cache.test.js +236 -0
- package/build/cache/in-memory-ttl-cache.test.js.map +1 -0
- package/build/cache/index.d.ts +2 -0
- package/build/cache/index.js +2 -0
- package/build/cache/index.js.map +1 -0
- package/build/cache/ttl-cache.d.ts +22 -0
- package/build/cache/ttl-cache.js +2 -0
- package/build/cache/ttl-cache.js.map +1 -0
- package/build/common/as-non-empty-string.d.ts +7 -0
- package/build/common/as-non-empty-string.js +10 -0
- package/build/common/as-non-empty-string.js.map +1 -0
- package/build/common/as-non-empty-string.test.d.ts +1 -0
- package/build/common/as-non-empty-string.test.js +25 -0
- package/build/common/as-non-empty-string.test.js.map +1 -0
- package/build/common/require-string.d.ts +12 -0
- package/build/common/require-string.js +27 -0
- package/build/common/require-string.js.map +1 -0
- package/build/common/require-string.test.d.ts +1 -0
- package/build/common/require-string.test.js +53 -0
- package/build/common/require-string.test.js.map +1 -0
- package/build/conformity-vocabulary/codes.d.ts +10 -0
- package/build/conformity-vocabulary/codes.js +10 -0
- package/build/conformity-vocabulary/codes.js.map +1 -0
- package/build/conformity-vocabulary/errors.d.ts +44 -0
- package/build/conformity-vocabulary/errors.js +68 -0
- package/build/conformity-vocabulary/errors.js.map +1 -0
- package/build/conformity-vocabulary/index.d.ts +6 -0
- package/build/conformity-vocabulary/index.js +7 -0
- package/build/conformity-vocabulary/index.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.d.ts +26 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.js +106 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.d.ts +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.js +327 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.d.ts +28 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.js +47 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.d.ts +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.js +284 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.js.map +1 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.d.ts +19 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.js +219 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.js.map +1 -0
- package/build/conformity-vocabulary/types.d.ts +180 -0
- package/build/conformity-vocabulary/types.js +2 -0
- package/build/conformity-vocabulary/types.js.map +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.d.ts +26 -0
- package/build/conformity-vocabulary/validate-conformity-claim.js +165 -0
- package/build/conformity-vocabulary/validate-conformity-claim.js.map +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.d.ts +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.js +478 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.js.map +1 -0
- package/build/http-headers/index.d.ts +5 -0
- package/build/http-headers/index.js +6 -0
- package/build/http-headers/index.js.map +1 -0
- package/build/http-headers/is-safe-header-value.d.ts +10 -0
- package/build/http-headers/is-safe-header-value.js +15 -0
- package/build/http-headers/is-safe-header-value.js.map +1 -0
- package/build/http-headers/is-safe-header-value.test.d.ts +1 -0
- package/build/http-headers/is-safe-header-value.test.js +37 -0
- package/build/http-headers/is-safe-header-value.test.js.map +1 -0
- package/build/http-headers/parse-entity-tag.d.ts +9 -0
- package/build/http-headers/parse-entity-tag.js +18 -0
- package/build/http-headers/parse-entity-tag.js.map +1 -0
- package/build/http-headers/parse-entity-tag.test.d.ts +1 -0
- package/build/http-headers/parse-entity-tag.test.js +41 -0
- package/build/http-headers/parse-entity-tag.test.js.map +1 -0
- package/build/http-headers/parse-imf-date.d.ts +13 -0
- package/build/http-headers/parse-imf-date.js +23 -0
- package/build/http-headers/parse-imf-date.js.map +1 -0
- package/build/http-headers/parse-imf-date.test.d.ts +1 -0
- package/build/http-headers/parse-imf-date.test.js +31 -0
- package/build/http-headers/parse-imf-date.test.js.map +1 -0
- package/build/http-headers/parse-media-type.d.ts +8 -0
- package/build/http-headers/parse-media-type.js +21 -0
- package/build/http-headers/parse-media-type.js.map +1 -0
- package/build/http-headers/parse-media-type.test.d.ts +1 -0
- package/build/http-headers/parse-media-type.test.js +39 -0
- package/build/http-headers/parse-media-type.test.js.map +1 -0
- package/build/http-headers/user-agent.d.ts +35 -0
- package/build/http-headers/user-agent.js +45 -0
- package/build/http-headers/user-agent.js.map +1 -0
- package/build/http-headers/user-agent.test.d.ts +1 -0
- package/build/http-headers/user-agent.test.js +27 -0
- package/build/http-headers/user-agent.test.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/loaders/errors.d.ts +21 -0
- package/build/loaders/errors.js +45 -0
- package/build/loaders/errors.js.map +1 -0
- package/build/loaders/index.d.ts +3 -0
- package/build/loaders/index.js +4 -0
- package/build/loaders/index.js.map +1 -0
- package/build/loaders/jsonld-document-loader.d.ts +46 -0
- package/build/loaders/jsonld-document-loader.js +34 -0
- package/build/loaders/jsonld-document-loader.js.map +1 -0
- package/build/loaders/jsonld-document-loader.test.d.ts +1 -0
- package/build/loaders/jsonld-document-loader.test.js +71 -0
- package/build/loaders/jsonld-document-loader.test.js.map +1 -0
- package/build/loaders/schema-loader.d.ts +21 -0
- package/build/loaders/schema-loader.js +67 -0
- package/build/loaders/schema-loader.js.map +1 -0
- package/build/loaders/schema-loader.ssrf.test.d.ts +1 -0
- package/build/loaders/schema-loader.ssrf.test.js +55 -0
- package/build/loaders/schema-loader.ssrf.test.js.map +1 -0
- package/build/loaders/schema-loader.test.d.ts +1 -0
- package/build/loaders/schema-loader.test.js +162 -0
- package/build/loaders/schema-loader.test.js.map +1 -0
- package/build/multibase-digest/multibase-digest.d.ts +23 -0
- package/build/multibase-digest/multibase-digest.js +40 -0
- package/build/multibase-digest/multibase-digest.js.map +1 -1
- package/build/multibase-digest/multibase-digest.test.js +46 -0
- package/build/multibase-digest/multibase-digest.test.js.map +1 -1
- package/build/node/errors.d.ts +41 -0
- package/build/node/errors.js +80 -0
- package/build/node/errors.js.map +1 -0
- package/build/node/index.d.ts +3 -0
- package/build/node/index.js +4 -0
- package/build/node/index.js.map +1 -0
- package/build/node/is-private-ip.d.ts +41 -0
- package/build/node/is-private-ip.js +138 -0
- package/build/node/is-private-ip.js.map +1 -0
- package/build/node/is-private-ip.test.d.ts +1 -0
- package/build/node/is-private-ip.test.js +96 -0
- package/build/node/is-private-ip.test.js.map +1 -0
- package/build/node/validate-public-url.d.ts +49 -0
- package/build/node/validate-public-url.js +94 -0
- package/build/node/validate-public-url.js.map +1 -0
- package/build/node/validate-public-url.test.d.ts +1 -0
- package/build/node/validate-public-url.test.js +177 -0
- package/build/node/validate-public-url.test.js.map +1 -0
- package/build/resolvers/errors.d.ts +43 -0
- package/build/resolvers/errors.js +99 -0
- package/build/resolvers/errors.js.map +1 -0
- package/build/resolvers/index.d.ts +5 -0
- package/build/resolvers/index.js +6 -0
- package/build/resolvers/index.js.map +1 -0
- package/build/resolvers/resolve-document-if-changed.d.ts +48 -0
- package/build/resolvers/resolve-document-if-changed.js +42 -0
- package/build/resolvers/resolve-document-if-changed.js.map +1 -0
- package/build/resolvers/resolve-document-if-changed.test.d.ts +1 -0
- package/build/resolvers/resolve-document-if-changed.test.js +109 -0
- package/build/resolvers/resolve-document-if-changed.test.js.map +1 -0
- package/build/resolvers/resolve-document.d.ts +86 -0
- package/build/resolvers/resolve-document.js +239 -0
- package/build/resolvers/resolve-document.js.map +1 -0
- package/build/resolvers/resolve-document.test.d.ts +1 -0
- package/build/resolvers/resolve-document.test.js +299 -0
- package/build/resolvers/resolve-document.test.js.map +1 -0
- package/build/resolvers/resolve-json-document.d.ts +40 -0
- package/build/resolvers/resolve-json-document.js +42 -0
- package/build/resolvers/resolve-json-document.js.map +1 -0
- package/build/resolvers/resolve-json-document.test.d.ts +1 -0
- package/build/resolvers/resolve-json-document.test.js +61 -0
- package/build/resolvers/resolve-json-document.test.js.map +1 -0
- package/build/structured-error.d.ts +49 -0
- package/build/structured-error.js +17 -0
- package/build/structured-error.js.map +1 -0
- package/build/structured-error.test.d.ts +1 -0
- package/build/structured-error.test.js +112 -0
- package/build/structured-error.test.js.map +1 -0
- package/build/validation/describe-jsonld-failure.d.ts +50 -0
- package/build/validation/describe-jsonld-failure.js +104 -0
- package/build/validation/describe-jsonld-failure.js.map +1 -0
- package/build/validation/describe-jsonld-failure.test.d.ts +1 -0
- package/build/validation/describe-jsonld-failure.test.js +141 -0
- package/build/validation/describe-jsonld-failure.test.js.map +1 -0
- package/build/validation/errors.d.ts +40 -0
- package/build/validation/errors.js +75 -0
- package/build/validation/errors.js.map +1 -0
- package/build/validation/index.d.ts +4 -0
- package/build/validation/index.js +5 -0
- package/build/validation/index.js.map +1 -0
- package/build/validation/validate-against-schemas.d.ts +22 -0
- package/build/validation/validate-against-schemas.js +65 -0
- package/build/validation/validate-against-schemas.js.map +1 -0
- package/build/validation/validate-against-schemas.test.d.ts +1 -0
- package/build/validation/validate-against-schemas.test.js +169 -0
- package/build/validation/validate-against-schemas.test.js.map +1 -0
- package/build/validation/validate-jsonld.context-cache.test.d.ts +1 -0
- package/build/validation/validate-jsonld.context-cache.test.js +32 -0
- package/build/validation/validate-jsonld.context-cache.test.js.map +1 -0
- package/build/validation/validate-jsonld.d.ts +33 -0
- package/build/validation/validate-jsonld.js +99 -0
- package/build/validation/validate-jsonld.js.map +1 -0
- package/build/validation/validate-jsonld.ssrf.test.d.ts +1 -0
- package/build/validation/validate-jsonld.ssrf.test.js +108 -0
- package/build/validation/validate-jsonld.ssrf.test.js.map +1 -0
- package/build/validation/validate-jsonld.test.d.ts +1 -0
- package/build/validation/validate-jsonld.test.js +200 -0
- package/build/validation/validate-jsonld.test.js.map +1 -0
- package/package.json +64 -3
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TtlCache } from '../cache/ttl-cache.js';
|
|
2
|
+
import type { LoadedRemoteDocument } from '../loaders/jsonld-document-loader.js';
|
|
3
|
+
export interface ValidateJsonLdOptions {
|
|
4
|
+
/** Whether to use safe mode for JSON-LD expansion. Defaults to true. */
|
|
5
|
+
safe?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Optional cache, keyed by URL, for resolved remote `@context` documents.
|
|
8
|
+
* Supplying a shared cache avoids re-fetching the same contexts on every
|
|
9
|
+
* validation (e.g. the credential context on the issuance/verification
|
|
10
|
+
* hot path). Only successful fetches are cached, so a URL the SSRF guard
|
|
11
|
+
* rejects is re-checked every time. A successfully fetched and parsed
|
|
12
|
+
* document is cached even if expansion later rejects it.
|
|
13
|
+
*/
|
|
14
|
+
contextCache?: TtlCache<LoadedRemoteDocument>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Catches malformed contexts, undefined terms, and structurally invalid
|
|
18
|
+
* linked data by expanding to RDF in safe mode (unless explicitly disabled).
|
|
19
|
+
*
|
|
20
|
+
* Expansion resolves every remote `@context` through a guarded document
|
|
21
|
+
* loader ({@link createJsonLdDocumentLoader}) so `@context` fetches pass the
|
|
22
|
+
* `validatePublicUrl` SSRF guard rather than jsonld.js's default unguarded
|
|
23
|
+
* Node loader. See ADR-033 §7 and issue #707.
|
|
24
|
+
*
|
|
25
|
+
* @see https://github.com/digitalbazaar/jsonld.js#safe-mode jsonld.js safe mode (a jsonld.js option, not a W3C-defined term).
|
|
26
|
+
* @see ../../../../docs/adrs/033-cvc-architecture.md ADR-033 §7 (Security considerations).
|
|
27
|
+
* @throws {JsonLdInvalidShapeError} if `document` is not a non-null object.
|
|
28
|
+
* @throws {JsonLdExpansionFailedError} if `jsonld.toRDF` rejects (which
|
|
29
|
+
* includes a remote `@context` failing the SSRF guard; the guard's
|
|
30
|
+
* rejection is reachable via native `.cause` hops off the thrown error,
|
|
31
|
+
* see {@link rehydrateJsonLdCause}).
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateJsonLd(document: unknown, options?: ValidateJsonLdOptions): Promise<void>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { JsonLdExpansionFailedError, JsonLdInvalidShapeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* jsonld.js's own `JsonLdError` wraps a document loader's rejection in the
|
|
4
|
+
* proprietary `details.cause` and never sets native `Error.cause`
|
|
5
|
+
* (jsonld@8.3.3 `lib/JsonLdError.js`, loader wrap in
|
|
6
|
+
* `lib/ContextResolver.js`), so a plain `.cause` walk over a caught
|
|
7
|
+
* expansion failure dead-ends one hop early: the SSRF guard's rejection
|
|
8
|
+
* (see `createJsonLdDocumentLoader`) is reachable only via the non-standard
|
|
9
|
+
* `error.details.cause`, unlike the schema-fetch path (`schema-loader.ts`),
|
|
10
|
+
* which surfaces the same class of rejection on the native chain.
|
|
11
|
+
*
|
|
12
|
+
* A term's own remote `@context` (a JSON-LD 1.1 "scoped context") loses even
|
|
13
|
+
* that: jsonld.js resolves it through the same loader, but on failure its
|
|
14
|
+
* scoped-context branch (`lib/context.js`) discards the loader's error
|
|
15
|
+
* entirely and throws a fresh `JsonLdError` whose `details` carry no `cause`
|
|
16
|
+
* at all. `fallback` recovers the guard's rejection in that case: `toRDF`'s
|
|
17
|
+
* `documentLoader` is wrapped ({@link validateJsonLd}) to record the last
|
|
18
|
+
* error it threw during the call, and that call-scoped record is passed here
|
|
19
|
+
* as `fallback`. Because jsonld.js resolves `@context` documents one at a
|
|
20
|
+
* time and any loader throw immediately aborts the whole call (no later,
|
|
21
|
+
* unrelated loader call can follow one that failed), a recorded loader error
|
|
22
|
+
* is always the proximate cause of whatever expansion failure this function
|
|
23
|
+
* is asked to rehydrate, whether or not jsonld.js chose to keep its own
|
|
24
|
+
* reference to it.
|
|
25
|
+
*
|
|
26
|
+
* Rehydrates the recovered error (preferring `details.cause` when jsonld.js
|
|
27
|
+
* kept it) onto `error.cause` so a plain `.cause` walk reaches it. Mutates
|
|
28
|
+
* and returns the same object jsonld.js just threw for this call (safe:
|
|
29
|
+
* nothing else holds a reference to it), and only when there is something to
|
|
30
|
+
* recover and jsonld.js has not already set a `cause` itself, so a malformed
|
|
31
|
+
* `@context` that never reached the document loader (and so has nothing
|
|
32
|
+
* buried and no fallback recorded) does not gain a spurious one.
|
|
33
|
+
*
|
|
34
|
+
* @see https://github.com/uncefact/tests-untp/issues/773
|
|
35
|
+
*/
|
|
36
|
+
function rehydrateJsonLdCause(error, fallback) {
|
|
37
|
+
if (!(error instanceof Error) || error.cause !== undefined) {
|
|
38
|
+
return error;
|
|
39
|
+
}
|
|
40
|
+
const buried = error.details?.cause;
|
|
41
|
+
const recovered = buried !== undefined ? buried : fallback;
|
|
42
|
+
if (recovered !== undefined) {
|
|
43
|
+
error.cause = recovered;
|
|
44
|
+
}
|
|
45
|
+
return error;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Catches malformed contexts, undefined terms, and structurally invalid
|
|
49
|
+
* linked data by expanding to RDF in safe mode (unless explicitly disabled).
|
|
50
|
+
*
|
|
51
|
+
* Expansion resolves every remote `@context` through a guarded document
|
|
52
|
+
* loader ({@link createJsonLdDocumentLoader}) so `@context` fetches pass the
|
|
53
|
+
* `validatePublicUrl` SSRF guard rather than jsonld.js's default unguarded
|
|
54
|
+
* Node loader. See ADR-033 §7 and issue #707.
|
|
55
|
+
*
|
|
56
|
+
* @see https://github.com/digitalbazaar/jsonld.js#safe-mode jsonld.js safe mode (a jsonld.js option, not a W3C-defined term).
|
|
57
|
+
* @see ../../../../docs/adrs/033-cvc-architecture.md ADR-033 §7 (Security considerations).
|
|
58
|
+
* @throws {JsonLdInvalidShapeError} if `document` is not a non-null object.
|
|
59
|
+
* @throws {JsonLdExpansionFailedError} if `jsonld.toRDF` rejects (which
|
|
60
|
+
* includes a remote `@context` failing the SSRF guard; the guard's
|
|
61
|
+
* rejection is reachable via native `.cause` hops off the thrown error,
|
|
62
|
+
* see {@link rehydrateJsonLdCause}).
|
|
63
|
+
*/
|
|
64
|
+
export async function validateJsonLd(document, options) {
|
|
65
|
+
if (typeof document !== 'object' || document === null) {
|
|
66
|
+
throw new JsonLdInvalidShapeError(document);
|
|
67
|
+
}
|
|
68
|
+
// Dynamic import: jsonld pulls in undici/TextDecoder which aren't
|
|
69
|
+
// available in jsdom, so we load it lazily to allow test mocking. The
|
|
70
|
+
// guarded document loader is loaded lazily for the same reason (it depends
|
|
71
|
+
// on the resolvers/node stack, which uses undici and node:dns).
|
|
72
|
+
const jsonldModule = await import('jsonld');
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
const jsonld = ('default' in jsonldModule ? jsonldModule.default : jsonldModule);
|
|
75
|
+
const { createJsonLdDocumentLoader } = await import('../loaders/jsonld-document-loader.js');
|
|
76
|
+
const documentLoader = createJsonLdDocumentLoader({ cache: options?.contextCache });
|
|
77
|
+
// Recorded for rehydrateJsonLdCause's fallback: the last error the loader
|
|
78
|
+
// threw during this call (undefined if every fetch it made succeeded).
|
|
79
|
+
let lastLoaderError;
|
|
80
|
+
const trackedDocumentLoader = async (url) => {
|
|
81
|
+
try {
|
|
82
|
+
return await documentLoader(url);
|
|
83
|
+
}
|
|
84
|
+
catch (loaderError) {
|
|
85
|
+
lastLoaderError = loaderError;
|
|
86
|
+
throw loaderError;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
// The options cast bridges @types/jsonld, which types documentLoader with
|
|
91
|
+
// a legacy callback signature; jsonld.js itself accepts the
|
|
92
|
+
// single-argument promise-returning loader used here.
|
|
93
|
+
await jsonld.toRDF(document, { safe: options?.safe ?? true, documentLoader: trackedDocumentLoader });
|
|
94
|
+
}
|
|
95
|
+
catch (cause) {
|
|
96
|
+
throw new JsonLdExpansionFailedError(rehydrateJsonLdCause(cause, lastLoaderError));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=validate-jsonld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-jsonld.js","sourceRoot":"","sources":["../../src/validation/validate-jsonld.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAgBlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAS,oBAAoB,CAAC,KAAc,EAAE,QAAkB;IAC9D,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAI,KAAmD,CAAC,OAAO,EAAE,KAAK,CAAC;IACnF,MAAM,SAAS,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC3D,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAiB,EAAE,OAA+B;IACrF,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,MAAM,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,kEAAkE;IAClE,sEAAsE;IACtE,2EAA2E;IAC3E,gEAAgE;IAChE,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5C,8DAA8D;IAC9D,MAAM,MAAM,GAAG,CAAC,SAAS,IAAI,YAAY,CAAC,CAAC,CAAE,YAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAA4B,CAAC;IACrH,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAAC;IAC5F,MAAM,cAAc,GAAG,0BAA0B,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAEpF,0EAA0E;IAC1E,uEAAuE;IACvE,IAAI,eAAwB,CAAC;IAC7B,MAAM,qBAAqB,GAAG,KAAK,EAAE,GAAW,EAAiC,EAAE;QACjF,IAAI,CAAC;YACH,OAAO,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,WAAW,EAAE,CAAC;YACrB,eAAe,GAAG,WAAW,CAAC;YAC9B,MAAM,WAAW,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,0EAA0E;QAC1E,4DAA4D;QAC5D,sDAAsD;QACtD,MAAM,MAAM,CAAC,KAAK,CAChB,QAA0B,EAC1B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,cAAc,EAAE,qBAAqB,EAAwC,CAC7G,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,0BAA0B,CAAC,oBAAoB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { validateJsonLd } from './validate-jsonld.js';
|
|
3
|
+
import { JsonLdExpansionFailedError } from './errors.js';
|
|
4
|
+
import { UrlValidationError } from '../node/errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Walks the native `Error.cause` chain from `error`, collecting every link.
|
|
7
|
+
* jsonld.js's own `JsonLdError` buries a document loader's rejection at the
|
|
8
|
+
* non-standard `details.cause` and never sets native `Error.cause`;
|
|
9
|
+
* `validateJsonLd` rehydrates it onto `error.cause` when wrapping an
|
|
10
|
+
* expansion failure (see `validate-jsonld.ts`), so a plain `.cause` walk
|
|
11
|
+
* reaches the SSRF guard's rejection the same way it does on the
|
|
12
|
+
* schema-fetch path (`schema-loader.ssrf.test.ts`).
|
|
13
|
+
*/
|
|
14
|
+
function nativeCauseChain(error) {
|
|
15
|
+
const chain = [];
|
|
16
|
+
let current = error;
|
|
17
|
+
while (current instanceof Error && current.cause !== undefined) {
|
|
18
|
+
chain.push(current.cause);
|
|
19
|
+
current = current.cause;
|
|
20
|
+
}
|
|
21
|
+
return chain;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* End-to-end SSRF regression for JSON-LD expansion. Unlike `validate-jsonld.test.ts`,
|
|
25
|
+
* this suite does NOT mock `jsonld` or the resolver stack: it exercises the real
|
|
26
|
+
* `jsonld.toRDF` + guarded document loader against a live loopback server standing
|
|
27
|
+
* in for an internal service.
|
|
28
|
+
*
|
|
29
|
+
* The load-bearing assertion is that the canary server is NEVER contacted. A prior
|
|
30
|
+
* (unguarded) implementation would let jsonld.js's default Node loader fetch a
|
|
31
|
+
* private `@context` URL, hitting the canary. The guard rejects the URL before any
|
|
32
|
+
* connection, so `hits` stays 0 regardless of how the expansion ultimately fails.
|
|
33
|
+
*
|
|
34
|
+
* @see https://github.com/uncefact/tests-untp/issues/707
|
|
35
|
+
*/
|
|
36
|
+
describe('validateJsonLd SSRF guard (real jsonld + guarded loader)', () => {
|
|
37
|
+
let server;
|
|
38
|
+
let baseUrl;
|
|
39
|
+
let hits = 0;
|
|
40
|
+
beforeAll(async () => {
|
|
41
|
+
server = http.createServer((_req, res) => {
|
|
42
|
+
hits += 1;
|
|
43
|
+
res.setHeader('content-type', 'application/ld+json');
|
|
44
|
+
res.end(JSON.stringify({ '@context': {} }));
|
|
45
|
+
});
|
|
46
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
47
|
+
const address = server.address();
|
|
48
|
+
baseUrl = `http://127.0.0.1:${address.port}`;
|
|
49
|
+
});
|
|
50
|
+
afterAll(async () => {
|
|
51
|
+
await new Promise((resolve, reject) => server.close((err) => (err ? reject(err) : resolve())));
|
|
52
|
+
});
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
hits = 0;
|
|
55
|
+
});
|
|
56
|
+
it('never contacts a private @context URL during expansion', async () => {
|
|
57
|
+
const malicious = { '@context': `${baseUrl}/internal-context`, name: 'value' };
|
|
58
|
+
const error = await validateJsonLd(malicious).catch((e) => e);
|
|
59
|
+
expect(error).toBeInstanceOf(JsonLdExpansionFailedError);
|
|
60
|
+
// The rejection came from the SSRF guard, not an unrelated expansion failure.
|
|
61
|
+
expect(nativeCauseChain(error)).toContainEqual(expect.any(UrlValidationError));
|
|
62
|
+
// The security property: the loopback canary was never reached.
|
|
63
|
+
expect(hits).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
it('rejects a metadata-service @context literal before any connection', async () => {
|
|
66
|
+
const malicious = { '@context': 'http://169.254.169.254/latest/meta-data', name: 'value' };
|
|
67
|
+
const error = await validateJsonLd(malicious).catch((e) => e);
|
|
68
|
+
expect(error).toBeInstanceOf(JsonLdExpansionFailedError);
|
|
69
|
+
expect(nativeCauseChain(error)).toContainEqual(expect.any(UrlValidationError));
|
|
70
|
+
});
|
|
71
|
+
it('expands a document with an inline @context without any network fetch', async () => {
|
|
72
|
+
const document = { '@context': { name: 'http://schema.org/name' }, name: 'Acme' };
|
|
73
|
+
await expect(validateJsonLd(document)).resolves.toBeUndefined();
|
|
74
|
+
expect(hits).toBe(0);
|
|
75
|
+
});
|
|
76
|
+
it('reaches the UrlValidationError by plain .cause hops, matching the schema-fetch path shape', async () => {
|
|
77
|
+
const malicious = { '@context': `${baseUrl}/internal-context`, name: 'value' };
|
|
78
|
+
const error = (await validateJsonLd(malicious).catch((e) => e));
|
|
79
|
+
// First hop: jsonld.js's own JsonLdError (still carries `.details` for
|
|
80
|
+
// callers that want the raw jsonld diagnostic).
|
|
81
|
+
expect(error.cause).toBeInstanceOf(Error);
|
|
82
|
+
expect(error.cause.name).toBe('jsonld.InvalidUrl');
|
|
83
|
+
// Second hop: the guard's rejection itself, reachable without digging
|
|
84
|
+
// into jsonld.js's proprietary `details.cause`.
|
|
85
|
+
expect(error.cause.cause).toBeInstanceOf(UrlValidationError);
|
|
86
|
+
});
|
|
87
|
+
it('never contacts a private scoped (term-level) @context URL during expansion', async () => {
|
|
88
|
+
// A term can declare its own remote @context (JSON-LD 1.1 scoped contexts).
|
|
89
|
+
// jsonld.js resolves it through the same guarded loader as a top-level
|
|
90
|
+
// @context, so it must be rejected the same way.
|
|
91
|
+
const malicious = {
|
|
92
|
+
'@context': { myTerm: { '@id': 'http://schema.org/myTerm', '@context': `${baseUrl}/internal-scoped-context` } },
|
|
93
|
+
myTerm: 'value',
|
|
94
|
+
};
|
|
95
|
+
const error = await validateJsonLd(malicious).catch((e) => e);
|
|
96
|
+
expect(error).toBeInstanceOf(JsonLdExpansionFailedError);
|
|
97
|
+
// The rejection came from the SSRF guard, reachable by plain .cause hops.
|
|
98
|
+
// jsonld.js's scoped-context branch (lib/context.js) discards the loader
|
|
99
|
+
// failure entirely and throws a fresh 'invalid scoped context' JsonLdError
|
|
100
|
+
// with no `details.cause` of its own, so this can only pass if
|
|
101
|
+
// validateJsonLd recovers the guard's rejection some other way (tracking
|
|
102
|
+
// it at the document-loader call, see `validate-jsonld.ts`).
|
|
103
|
+
expect(nativeCauseChain(error)).toContainEqual(expect.any(UrlValidationError));
|
|
104
|
+
// The security property: the loopback canary was never reached.
|
|
105
|
+
expect(hits).toBe(0);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=validate-jsonld.ssrf.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-jsonld.ssrf.test.js","sourceRoot":"","sources":["../../src/validation/validate-jsonld.ssrf.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,KAAc;IACtC,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,OAAO,OAAO,YAAY,KAAK,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,QAAQ,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACxE,IAAI,MAAmB,CAAC;IACxB,IAAI,OAAe,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YACvC,IAAI,IAAI,CAAC,CAAC;YACV,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAC;QAChD,OAAO,GAAG,oBAAoB,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACvG,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,GAAG,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,SAAS,GAAG,EAAE,UAAU,EAAE,GAAG,OAAO,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAE/E,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;QACzD,8EAA8E;QAC9E,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC/E,gEAAgE;QAChE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,SAAS,GAAG,EAAE,UAAU,EAAE,yCAAyC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAE3F,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;QACzD,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,QAAQ,GAAG,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAElF,MAAM,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2FAA2F,EAAE,KAAK,IAAI,EAAE;QACzG,MAAM,SAAS,GAAG,EAAE,UAAU,EAAE,GAAG,OAAO,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAE/E,MAAM,KAAK,GAAG,CAAC,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAA+B,CAAC;QAEvG,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,CAAE,KAAK,CAAC,KAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC9D,sEAAsE;QACtE,gDAAgD;QAChD,MAAM,CAAE,KAAK,CAAC,KAAe,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,4EAA4E;QAC5E,uEAAuE;QACvE,iDAAiD;QACjD,MAAM,SAAS,GAAG;YAChB,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,UAAU,EAAE,GAAG,OAAO,0BAA0B,EAAE,EAAE;YAC/G,MAAM,EAAE,OAAO;SAChB,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;QACzD,0EAA0E;QAC1E,yEAAyE;QACzE,2EAA2E;QAC3E,+DAA+D;QAC/D,yEAAyE;QACzE,6DAA6D;QAC7D,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC/E,gEAAgE;QAChE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { createInMemoryTtlCache } from '../cache/in-memory-ttl-cache.js';
|
|
3
|
+
import { JsonLdValidationError } from './errors.js';
|
|
4
|
+
const toRDF = jest.fn();
|
|
5
|
+
const documentLoader = jest.fn();
|
|
6
|
+
const createJsonLdDocumentLoader = jest.fn(() => documentLoader);
|
|
7
|
+
jest.unstable_mockModule('jsonld', () => ({
|
|
8
|
+
default: { toRDF },
|
|
9
|
+
toRDF,
|
|
10
|
+
}));
|
|
11
|
+
// The loader factory is mocked so this suite can assert the option threading
|
|
12
|
+
// (contextCache -> cache) without invoking the real resolver stack; the
|
|
13
|
+
// factory's own behaviour is covered in loaders/jsonld-document-loader.test.ts.
|
|
14
|
+
jest.unstable_mockModule('../loaders/jsonld-document-loader.js', () => ({
|
|
15
|
+
createJsonLdDocumentLoader,
|
|
16
|
+
}));
|
|
17
|
+
const { validateJsonLd } = await import('./validate-jsonld.js');
|
|
18
|
+
describe('validateJsonLd', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
toRDF.mockReset();
|
|
21
|
+
documentLoader.mockReset();
|
|
22
|
+
createJsonLdDocumentLoader.mockClear();
|
|
23
|
+
});
|
|
24
|
+
it('returns void when JSON-LD expansion succeeds', async () => {
|
|
25
|
+
toRDF.mockResolvedValue([]);
|
|
26
|
+
await expect(validateJsonLd({ '@context': 'https://example.com' })).resolves.toBeUndefined();
|
|
27
|
+
expect(toRDF).toHaveBeenCalledWith({ '@context': 'https://example.com' }, expect.objectContaining({ safe: true, documentLoader: expect.any(Function) }));
|
|
28
|
+
});
|
|
29
|
+
it('throws JsonLdExpansionFailedError when toRDF rejects', async () => {
|
|
30
|
+
toRDF.mockRejectedValue(new Error('Invalid JSON-LD'));
|
|
31
|
+
await expect(validateJsonLd({})).rejects.toMatchObject({
|
|
32
|
+
name: 'JsonLdExpansionFailedError',
|
|
33
|
+
code: 'jsonld.expansion-failed',
|
|
34
|
+
received: 'Invalid JSON-LD',
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it('captures the original error on Error.cause', async () => {
|
|
38
|
+
const cause = new Error('Missing @context');
|
|
39
|
+
toRDF.mockRejectedValue(cause);
|
|
40
|
+
await expect(validateJsonLd({})).rejects.toMatchObject({ cause });
|
|
41
|
+
});
|
|
42
|
+
describe('rehydrating a buried jsonld.js loader error', () => {
|
|
43
|
+
// jsonld.js's own JsonLdError stores a document loader's rejection at
|
|
44
|
+
// the proprietary `details.cause` and never sets native `Error.cause`
|
|
45
|
+
// (jsonld@8.3.3 `lib/JsonLdError.js`, loader wrap in
|
|
46
|
+
// `lib/ContextResolver.js`). `validateJsonLd` rehydrates it onto the
|
|
47
|
+
// caught error's native `cause` so a plain `.cause` walk reaches it,
|
|
48
|
+
// matching the schema-fetch path (see `validate-jsonld.ssrf.test.ts`).
|
|
49
|
+
it('rehydrates the buried loader error onto the native cause chain', async () => {
|
|
50
|
+
const buried = new Error('SSRF rejected');
|
|
51
|
+
const jsonldError = Object.assign(new Error('Dereferencing a URL did not result in a valid JSON-LD object.'), {
|
|
52
|
+
name: 'jsonld.InvalidUrl',
|
|
53
|
+
details: { code: 'loading remote context failed', url: 'https://internal.example', cause: buried },
|
|
54
|
+
});
|
|
55
|
+
toRDF.mockRejectedValue(jsonldError);
|
|
56
|
+
const error = await validateJsonLd({}).catch((e) => e);
|
|
57
|
+
expect(error.cause).toBe(jsonldError);
|
|
58
|
+
// Without the rehydration, jsonldError.cause stays unset (jsonld.js
|
|
59
|
+
// never sets it), so this hop would be absent.
|
|
60
|
+
expect(jsonldError.cause).toBe(buried);
|
|
61
|
+
});
|
|
62
|
+
it('does not add a spurious cause when the jsonld error has no buried loader error', async () => {
|
|
63
|
+
// A malformed @context never reaches the document loader, so jsonld.js's
|
|
64
|
+
// details carry no `cause` to rehydrate.
|
|
65
|
+
const jsonldError = Object.assign(new Error('Invalid JSON-LD syntax; @context must be an object.'), {
|
|
66
|
+
name: 'jsonld.SyntaxError',
|
|
67
|
+
details: { code: 'invalid @context' },
|
|
68
|
+
});
|
|
69
|
+
toRDF.mockRejectedValue(jsonldError);
|
|
70
|
+
await validateJsonLd({}).catch(() => undefined);
|
|
71
|
+
// Asserts absence, not merely `undefined`: an implementation that sets
|
|
72
|
+
// `error.cause = undefined` unconditionally would pass a `toBeUndefined()`
|
|
73
|
+
// check but still fabricate a `cause` property that was never there.
|
|
74
|
+
expect('cause' in jsonldError).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
it('does not clobber an existing native cause on the jsonld error', async () => {
|
|
77
|
+
const existingCause = new Error('existing, legitimate native cause');
|
|
78
|
+
const buried = new Error('buried loader error, must not overwrite the existing cause');
|
|
79
|
+
const jsonldError = Object.assign(new Error('wrapped', { cause: existingCause }), {
|
|
80
|
+
name: 'jsonld.InvalidUrl',
|
|
81
|
+
details: { cause: buried },
|
|
82
|
+
});
|
|
83
|
+
toRDF.mockRejectedValue(jsonldError);
|
|
84
|
+
await validateJsonLd({}).catch(() => undefined);
|
|
85
|
+
expect(jsonldError.cause).toBe(existingCause);
|
|
86
|
+
});
|
|
87
|
+
// A term's own remote @context (a JSON-LD 1.1 "scoped context") is
|
|
88
|
+
// resolved through the same document loader, but on failure jsonld.js's
|
|
89
|
+
// scoped-context branch (lib/context.js) discards the loader's error
|
|
90
|
+
// entirely and throws a fresh JsonLdError with no `details.cause` at
|
|
91
|
+
// all (see validate-jsonld.ssrf.test.ts for the real-jsonld
|
|
92
|
+
// reproduction). validateJsonLd recovers it by tracking the last error
|
|
93
|
+
// the document loader threw during the call and using that as a
|
|
94
|
+
// fallback cause.
|
|
95
|
+
describe('recovering via the tracked-loader fallback', () => {
|
|
96
|
+
/** Simulates toRDF calling the documentLoader it was given, then rejecting as jsonld.js would. */
|
|
97
|
+
function rejectAfterCallingLoader(url, rejection) {
|
|
98
|
+
toRDF.mockImplementation(async (...args) => {
|
|
99
|
+
const opts = args[1];
|
|
100
|
+
await opts.documentLoader(url).catch(() => undefined);
|
|
101
|
+
throw rejection;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
it('recovers the tracked loader error when the jsonld error has no buried cause of its own', async () => {
|
|
105
|
+
const loaderError = new Error('SSRF rejected, recorded from the tracked loader');
|
|
106
|
+
documentLoader.mockRejectedValue(loaderError);
|
|
107
|
+
const scopedContextError = Object.assign(new Error('Invalid JSON-LD syntax; invalid scoped context.'), {
|
|
108
|
+
name: 'jsonld.SyntaxError',
|
|
109
|
+
details: { code: 'invalid scoped context', context: 'https://internal.example', term: 'myTerm' },
|
|
110
|
+
});
|
|
111
|
+
rejectAfterCallingLoader('https://internal.example', scopedContextError);
|
|
112
|
+
await validateJsonLd({}).catch(() => undefined);
|
|
113
|
+
// Without the fallback, this jsonld error's details carry no `cause`
|
|
114
|
+
// at all, so scopedContextError.cause would stay unset.
|
|
115
|
+
expect(scopedContextError.cause).toBe(loaderError);
|
|
116
|
+
});
|
|
117
|
+
it('prefers the buried details.cause over the fallback when jsonld.js kept both', async () => {
|
|
118
|
+
const buried = new Error('buried on details.cause, should win');
|
|
119
|
+
const fallbackLoaderError = new Error('recorded from the tracked loader, should lose');
|
|
120
|
+
documentLoader.mockRejectedValue(fallbackLoaderError);
|
|
121
|
+
const jsonldError = Object.assign(new Error('wrapped'), {
|
|
122
|
+
name: 'jsonld.InvalidUrl',
|
|
123
|
+
details: { cause: buried },
|
|
124
|
+
});
|
|
125
|
+
rejectAfterCallingLoader('https://example.com', jsonldError);
|
|
126
|
+
await validateJsonLd({}).catch(() => undefined);
|
|
127
|
+
expect(jsonldError.cause).toBe(buried);
|
|
128
|
+
});
|
|
129
|
+
it('does not fabricate a cause when the loader never threw during the call', async () => {
|
|
130
|
+
// The loader succeeds (or is never called); the eventual rejection
|
|
131
|
+
// is for an unrelated reason, so there is nothing to fall back to.
|
|
132
|
+
documentLoader.mockResolvedValue({ documentUrl: 'https://example.com', document: {} });
|
|
133
|
+
const unrelatedError = Object.assign(new Error('Invalid JSON-LD syntax; @context must be an object.'), {
|
|
134
|
+
name: 'jsonld.SyntaxError',
|
|
135
|
+
details: { code: 'invalid @context' },
|
|
136
|
+
});
|
|
137
|
+
rejectAfterCallingLoader('https://example.com', unrelatedError);
|
|
138
|
+
await validateJsonLd({}).catch(() => undefined);
|
|
139
|
+
expect('cause' in unrelatedError).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
it('throws JsonLdInvalidShapeError when the document is not an object', async () => {
|
|
144
|
+
await expect(validateJsonLd('not-an-object')).rejects.toMatchObject({
|
|
145
|
+
name: 'JsonLdInvalidShapeError',
|
|
146
|
+
code: 'jsonld.invalid-shape',
|
|
147
|
+
received: 'string',
|
|
148
|
+
expected: 'object',
|
|
149
|
+
});
|
|
150
|
+
expect(toRDF).not.toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
it('throws JsonLdInvalidShapeError for null input', async () => {
|
|
153
|
+
await expect(validateJsonLd(null)).rejects.toMatchObject({
|
|
154
|
+
name: 'JsonLdInvalidShapeError',
|
|
155
|
+
received: 'null',
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
it('passes safe: false to toRDF when options.safe is false', async () => {
|
|
159
|
+
toRDF.mockResolvedValue([]);
|
|
160
|
+
await validateJsonLd({ '@context': 'https://example.com' }, { safe: false });
|
|
161
|
+
expect(toRDF).toHaveBeenCalledWith({ '@context': 'https://example.com' }, expect.objectContaining({ safe: false, documentLoader: expect.any(Function) }));
|
|
162
|
+
});
|
|
163
|
+
it('defaults safe to true when no options provided', async () => {
|
|
164
|
+
toRDF.mockResolvedValue([]);
|
|
165
|
+
await validateJsonLd({ '@context': 'https://example.com' });
|
|
166
|
+
expect(toRDF).toHaveBeenCalledWith({ '@context': 'https://example.com' }, expect.objectContaining({ safe: true, documentLoader: expect.any(Function) }));
|
|
167
|
+
});
|
|
168
|
+
it('creates the document loader with the supplied contextCache', async () => {
|
|
169
|
+
toRDF.mockResolvedValue([]);
|
|
170
|
+
const contextCache = createInMemoryTtlCache({ ttlMs: 60_000 });
|
|
171
|
+
await validateJsonLd({ '@context': 'https://example.com' }, { contextCache });
|
|
172
|
+
expect(createJsonLdDocumentLoader).toHaveBeenCalledWith({ cache: contextCache });
|
|
173
|
+
});
|
|
174
|
+
it('passes toRDF a loader that delegates to the one createJsonLdDocumentLoader created', async () => {
|
|
175
|
+
toRDF.mockResolvedValue([]);
|
|
176
|
+
const remoteDoc = { documentUrl: 'https://example.com', document: {} };
|
|
177
|
+
documentLoader.mockResolvedValue(remoteDoc);
|
|
178
|
+
await validateJsonLd({ '@context': 'https://example.com' });
|
|
179
|
+
expect(createJsonLdDocumentLoader).toHaveBeenCalledWith({ cache: undefined });
|
|
180
|
+
// validateJsonLd wraps the created loader (to record failures for
|
|
181
|
+
// rehydrateJsonLdCause's fallback, see validate-jsonld.ts), so toRDF
|
|
182
|
+
// receives a different function reference; assert delegation instead.
|
|
183
|
+
const passedOptions = toRDF.mock.calls[0]?.[1];
|
|
184
|
+
await expect(passedOptions.documentLoader('https://example.com')).resolves.toBe(remoteDoc);
|
|
185
|
+
expect(documentLoader).toHaveBeenCalledWith('https://example.com');
|
|
186
|
+
});
|
|
187
|
+
it('handles non-Error thrown values', async () => {
|
|
188
|
+
toRDF.mockRejectedValue('string error');
|
|
189
|
+
await expect(validateJsonLd({})).rejects.toMatchObject({
|
|
190
|
+
code: 'jsonld.expansion-failed',
|
|
191
|
+
received: 'string error',
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
it('every concrete error extends JsonLdValidationError', async () => {
|
|
195
|
+
await expect(validateJsonLd(null)).rejects.toBeInstanceOf(JsonLdValidationError);
|
|
196
|
+
toRDF.mockRejectedValue(new Error('x'));
|
|
197
|
+
await expect(validateJsonLd({})).rejects.toBeInstanceOf(JsonLdValidationError);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
//# sourceMappingURL=validate-jsonld.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-jsonld.test.js","sourceRoot":"","sources":["../../src/validation/validate-jsonld.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uncefact/untp-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared utility primitives for UNTP packages and consumers.",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -9,15 +9,68 @@
|
|
|
9
9
|
"types": "./build/index.d.ts",
|
|
10
10
|
"default": "./build/index.js"
|
|
11
11
|
},
|
|
12
|
+
"./artefacts": {
|
|
13
|
+
"types": "./build/artefacts/index.d.ts",
|
|
14
|
+
"default": "./build/artefacts/index.js"
|
|
15
|
+
},
|
|
12
16
|
"./multibase-digest": {
|
|
13
17
|
"types": "./build/multibase-digest/index.d.ts",
|
|
14
18
|
"default": "./build/multibase-digest/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./conformity-vocabulary": {
|
|
21
|
+
"types": "./build/conformity-vocabulary/index.d.ts",
|
|
22
|
+
"default": "./build/conformity-vocabulary/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./validation": {
|
|
25
|
+
"types": "./build/validation/index.d.ts",
|
|
26
|
+
"default": "./build/validation/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./loaders": {
|
|
29
|
+
"types": "./build/loaders/index.d.ts",
|
|
30
|
+
"default": "./build/loaders/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./node": {
|
|
33
|
+
"types": "./build/node/index.d.ts",
|
|
34
|
+
"default": "./build/node/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./cache": {
|
|
37
|
+
"types": "./build/cache/index.d.ts",
|
|
38
|
+
"default": "./build/cache/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./resolvers": {
|
|
41
|
+
"types": "./build/resolvers/index.d.ts",
|
|
42
|
+
"default": "./build/resolvers/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./http-headers": {
|
|
45
|
+
"types": "./build/http-headers/index.d.ts",
|
|
46
|
+
"default": "./build/http-headers/index.js"
|
|
15
47
|
}
|
|
16
48
|
},
|
|
17
49
|
"typesVersions": {
|
|
18
50
|
"*": {
|
|
19
51
|
"multibase-digest": [
|
|
20
52
|
"./build/multibase-digest/index.d.ts"
|
|
53
|
+
],
|
|
54
|
+
"conformity-vocabulary": [
|
|
55
|
+
"./build/conformity-vocabulary/index.d.ts"
|
|
56
|
+
],
|
|
57
|
+
"validation": [
|
|
58
|
+
"./build/validation/index.d.ts"
|
|
59
|
+
],
|
|
60
|
+
"loaders": [
|
|
61
|
+
"./build/loaders/index.d.ts"
|
|
62
|
+
],
|
|
63
|
+
"node": [
|
|
64
|
+
"./build/node/index.d.ts"
|
|
65
|
+
],
|
|
66
|
+
"cache": [
|
|
67
|
+
"./build/cache/index.d.ts"
|
|
68
|
+
],
|
|
69
|
+
"resolvers": [
|
|
70
|
+
"./build/resolvers/index.d.ts"
|
|
71
|
+
],
|
|
72
|
+
"http-headers": [
|
|
73
|
+
"./build/http-headers/index.d.ts"
|
|
21
74
|
]
|
|
22
75
|
}
|
|
23
76
|
},
|
|
@@ -35,7 +88,8 @@
|
|
|
35
88
|
"untp",
|
|
36
89
|
"multibase",
|
|
37
90
|
"multihash",
|
|
38
|
-
"digest"
|
|
91
|
+
"digest",
|
|
92
|
+
"conformity-vocabulary"
|
|
39
93
|
],
|
|
40
94
|
"author": "",
|
|
41
95
|
"license": "Apache-2.0",
|
|
@@ -45,10 +99,17 @@
|
|
|
45
99
|
"directory": "packages/untp-utils"
|
|
46
100
|
},
|
|
47
101
|
"dependencies": {
|
|
48
|
-
"
|
|
102
|
+
"ajv": "^8.17.1",
|
|
103
|
+
"ajv-formats": "^3.0.1",
|
|
104
|
+
"ipaddr.js": "^2.4.0",
|
|
105
|
+
"jsonld": "^8.3.3",
|
|
106
|
+
"multiformats": "^13.3.1",
|
|
107
|
+
"undici": "^6.25.0"
|
|
49
108
|
},
|
|
50
109
|
"devDependencies": {
|
|
110
|
+
"@jest/globals": "29.7.0",
|
|
51
111
|
"@types/jest": "29.5.11",
|
|
112
|
+
"@types/jsonld": "^1.5.15",
|
|
52
113
|
"cross-env": "^7.0.3",
|
|
53
114
|
"jest": "29.7.0",
|
|
54
115
|
"ts-jest": "29.1.1",
|