@fedify/vocab-runtime 2.4.0-dev.1599 → 2.4.0-dev.1618
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/deno.json +1 -1
- package/dist/internal/jsonld-cache.cjs +2 -2
- package/dist/internal/jsonld-cache.js +2 -2
- package/dist/mod.cjs +4 -2
- package/dist/mod.d.cts +19 -1
- package/dist/mod.d.ts +19 -1
- package/dist/mod.js +3 -3
- package/dist/tests/decimal.test.cjs +2 -2
- package/dist/tests/decimal.test.mjs +2 -2
- package/dist/tests/{docloader-CDde_fhH.mjs → docloader-CBVde8Va.mjs} +2 -2
- package/dist/tests/{docloader-BiSxywul.cjs → docloader-QmR6VOqT.cjs} +2 -2
- package/dist/tests/docloader.test.cjs +3 -3
- package/dist/tests/docloader.test.mjs +3 -3
- package/dist/tests/jsonld-cache.test.cjs +2 -2
- package/dist/tests/jsonld-cache.test.mjs +2 -2
- package/dist/tests/{request-BBw3lNNz.mjs → request-BHx0fCb5.mjs} +1 -1
- package/dist/tests/{request-C9VKqYdG.cjs → request-DxSceLvB.cjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/{url-CtKcX6ma.cjs → url-BvjYQdxL.cjs} +64 -3
- package/dist/tests/{url-D7ay_5pk.mjs → url-a2D8NAgh.mjs} +53 -4
- package/dist/tests/url.test.cjs +45 -3
- package/dist/tests/url.test.mjs +45 -3
- package/dist/{url-BMDN9GnE.cjs → url-Ck3dGEwH.cjs} +64 -3
- package/dist/{url-BlFta-Eh.js → url-m1YxGNZ0.js} +53 -4
- package/package.json +1 -1
- package/src/internal/jsonld-cache.ts +3 -2
- package/src/mod.ts +2 -0
- package/src/url.test.ts +129 -2
- package/src/url.ts +65 -3
package/deno.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_url = require("../url-
|
|
3
|
+
const require_url = require("../url-Ck3dGEwH.cjs");
|
|
4
4
|
const require_jsonld = require("../jsonld.cjs");
|
|
5
5
|
//#region src/internal/jsonld-cache.ts
|
|
6
6
|
const noJsonLdContext = Symbol("noJsonLdContext");
|
|
@@ -12,7 +12,7 @@ const noJsonLdContext = Symbol("noJsonLdContext");
|
|
|
12
12
|
* Semantic Versioning decisions.
|
|
13
13
|
*/
|
|
14
14
|
function isTrustedIriOrigin(options, left, right) {
|
|
15
|
-
return options.crossOrigin === "trust" || left == null || right != null && require_url.haveSameIriOrigin(left, right);
|
|
15
|
+
return options.crossOrigin === "trust" || left == null || right != null && (require_url.haveSameIriOrigin(left, right) || require_url.haveSameFe34Origin(left, right));
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Normalizes portable IRIs in JSON-LD cache data.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as formatIri,
|
|
2
|
+
import { a as formatIri, c as haveSameIriOrigin, s as haveSameFe34Origin } from "../url-m1YxGNZ0.js";
|
|
3
3
|
import jsonld_default from "../jsonld.js";
|
|
4
4
|
//#region src/internal/jsonld-cache.ts
|
|
5
5
|
const noJsonLdContext = Symbol("noJsonLdContext");
|
|
@@ -11,7 +11,7 @@ const noJsonLdContext = Symbol("noJsonLdContext");
|
|
|
11
11
|
* Semantic Versioning decisions.
|
|
12
12
|
*/
|
|
13
13
|
function isTrustedIriOrigin(options, left, right) {
|
|
14
|
-
return options.crossOrigin === "trust" || left == null || right != null && haveSameIriOrigin(left, right);
|
|
14
|
+
return options.crossOrigin === "trust" || left == null || right != null && (haveSameIriOrigin(left, right) || haveSameFe34Origin(left, right));
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Normalizes portable IRIs in JSON-LD cache data.
|
package/dist/mod.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("./chunk-M78iaK0I.cjs");
|
|
4
|
-
const require_url = require("./url-
|
|
4
|
+
const require_url = require("./url-Ck3dGEwH.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
6
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
7
7
|
let node_process = require("node:process");
|
|
@@ -4367,7 +4367,7 @@ const preloadedContexts = {
|
|
|
4367
4367
|
//#endregion
|
|
4368
4368
|
//#region deno.json
|
|
4369
4369
|
var name = "@fedify/vocab-runtime";
|
|
4370
|
-
var version = "2.4.0-dev.
|
|
4370
|
+
var version = "2.4.0-dev.1618+58858243";
|
|
4371
4371
|
//#endregion
|
|
4372
4372
|
//#region src/link.ts
|
|
4373
4373
|
const parametersNeedLowerCase = ["rel", "type"];
|
|
@@ -5564,8 +5564,10 @@ exports.exportMultibaseKey = exportMultibaseKey;
|
|
|
5564
5564
|
exports.exportSpki = exportSpki;
|
|
5565
5565
|
exports.formatIri = require_url.formatIri;
|
|
5566
5566
|
exports.getDocumentLoader = getDocumentLoader;
|
|
5567
|
+
exports.getFe34Origin = require_url.getFe34Origin;
|
|
5567
5568
|
exports.getRemoteDocument = getRemoteDocument;
|
|
5568
5569
|
exports.getUserAgent = getUserAgent;
|
|
5570
|
+
exports.haveSameFe34Origin = require_url.haveSameFe34Origin;
|
|
5569
5571
|
exports.haveSameIriOrigin = require_url.haveSameIriOrigin;
|
|
5570
5572
|
exports.importDidKey = importDidKey;
|
|
5571
5573
|
exports.importMultibaseKey = importMultibaseKey;
|
package/dist/mod.d.cts
CHANGED
|
@@ -353,6 +353,24 @@ declare function canonicalizePortableUri(input: string): string;
|
|
|
353
353
|
*/
|
|
354
354
|
declare function arePortableUrisEqual(left: string, right: string): boolean;
|
|
355
355
|
/**
|
|
356
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
357
|
+
*
|
|
358
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
359
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
360
|
+
*
|
|
361
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
362
|
+
* @since 2.4.0
|
|
363
|
+
*/
|
|
364
|
+
declare function getFe34Origin(input: string | URL): string;
|
|
365
|
+
/**
|
|
366
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
367
|
+
*
|
|
368
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
369
|
+
*
|
|
370
|
+
* @since 2.4.0
|
|
371
|
+
*/
|
|
372
|
+
declare function haveSameFe34Origin(left: string | URL, right: string | URL): boolean;
|
|
373
|
+
/**
|
|
356
374
|
* Checks whether two IRIs have the same origin.
|
|
357
375
|
*/
|
|
358
376
|
declare function haveSameIriOrigin(left: URL, right: URL): boolean;
|
|
@@ -364,4 +382,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
|
|
|
364
382
|
declare function isValidPublicIPv6Address(address: string): boolean;
|
|
365
383
|
declare function expandIPv6Address(address: string): string;
|
|
366
384
|
//#endregion
|
|
367
|
-
export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getRemoteDocument, getUserAgent, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
|
385
|
+
export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
package/dist/mod.d.ts
CHANGED
|
@@ -353,6 +353,24 @@ declare function canonicalizePortableUri(input: string): string;
|
|
|
353
353
|
*/
|
|
354
354
|
declare function arePortableUrisEqual(left: string, right: string): boolean;
|
|
355
355
|
/**
|
|
356
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
357
|
+
*
|
|
358
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
359
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
360
|
+
*
|
|
361
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
362
|
+
* @since 2.4.0
|
|
363
|
+
*/
|
|
364
|
+
declare function getFe34Origin(input: string | URL): string;
|
|
365
|
+
/**
|
|
366
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
367
|
+
*
|
|
368
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
369
|
+
*
|
|
370
|
+
* @since 2.4.0
|
|
371
|
+
*/
|
|
372
|
+
declare function haveSameFe34Origin(left: string | URL, right: string | URL): boolean;
|
|
373
|
+
/**
|
|
356
374
|
* Checks whether two IRIs have the same origin.
|
|
357
375
|
*/
|
|
358
376
|
declare function haveSameIriOrigin(left: URL, right: URL): boolean;
|
|
@@ -364,4 +382,4 @@ declare function isValidPublicIPv4Address(address: string): boolean;
|
|
|
364
382
|
declare function isValidPublicIPv6Address(address: string): boolean;
|
|
365
383
|
declare function expandIPv6Address(address: string): string;
|
|
366
384
|
//#endregion
|
|
367
|
-
export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getRemoteDocument, getUserAgent, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
|
385
|
+
export { type AuthenticatedDocumentLoaderFactory, type CreateRequestOptions, type Decimal, type DidKeyVerificationMethod, type DocumentLoader, type DocumentLoaderFactory, type DocumentLoaderFactoryOptions, type DocumentLoaderOptions, FetchError, type GetDocumentLoaderOptions, type GetUserAgentOptions, type Json, LanguageString, type PropertyPreprocessor, type PropertyPreprocessorContext, type RemoteDocument, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
package/dist/mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as formatIri, c as
|
|
2
|
+
import { a as formatIri, c as haveSameIriOrigin, d as parseIri, f as parseJsonLdId, i as expandIPv6Address, l as isValidPublicIPv4Address, n as arePortableUrisEqual, o as getFe34Origin, p as validatePublicUrl, r as canonicalizePortableUri, s as haveSameFe34Origin, t as UrlError, u as isValidPublicIPv6Address } from "./url-m1YxGNZ0.js";
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
4
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
5
5
|
import process from "node:process";
|
|
@@ -4363,7 +4363,7 @@ const preloadedContexts = {
|
|
|
4363
4363
|
//#endregion
|
|
4364
4364
|
//#region deno.json
|
|
4365
4365
|
var name = "@fedify/vocab-runtime";
|
|
4366
|
-
var version = "2.4.0-dev.
|
|
4366
|
+
var version = "2.4.0-dev.1618+58858243";
|
|
4367
4367
|
//#endregion
|
|
4368
4368
|
//#region src/link.ts
|
|
4369
4369
|
const parametersNeedLowerCase = ["rel", "type"];
|
|
@@ -5544,4 +5544,4 @@ LanguageString.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_d
|
|
|
5544
5544
|
return `<${this.locale.baseName}> ${inspect(this.toString(), options)}`;
|
|
5545
5545
|
};
|
|
5546
5546
|
//#endregion
|
|
5547
|
-
export { FetchError, LanguageString, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getRemoteDocument, getUserAgent, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
|
5547
|
+
export { FetchError, LanguageString, UrlError, arePortableUrisEqual, canParseDecimal, canonicalizePortableUri, createActivityPubRequest, decodeMultibase, encodeMultibase, encodingFromBaseData, expandIPv6Address, exportDidKey, exportMultibaseKey, exportSpki, formatIri, getDocumentLoader, getFe34Origin, getRemoteDocument, getUserAgent, haveSameFe34Origin, haveSameIriOrigin, importDidKey, importMultibaseKey, importPem, importPkcs1, importSpki, isDecimal, isValidPublicIPv4Address, isValidPublicIPv6Address, logRequest, parseDecimal, parseDidKeyVerificationMethod, parseIri, parseJsonLdId, preloadedContexts, validatePublicUrl };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
require("./docloader-
|
|
3
|
-
require("./url-
|
|
2
|
+
require("./docloader-QmR6VOqT.cjs");
|
|
3
|
+
require("./url-BvjYQdxL.cjs");
|
|
4
4
|
require("./key-_wXwomh_.cjs");
|
|
5
5
|
require("./multibase-Bz_UUDtL.cjs");
|
|
6
6
|
require("./langstr-CbAxaeEZ.cjs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
1
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-BHx0fCb5.mjs";
|
|
2
2
|
import { t as HttpHeaderLink } from "./link-NUUWCdnK.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { p as validatePublicUrl, t as UrlError } from "./url-a2D8NAgh.mjs";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
6
6
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-DxSceLvB.cjs");
|
|
3
3
|
const require_link = require("./link-FguCydMA.cjs");
|
|
4
|
-
const require_url = require("./url-
|
|
4
|
+
const require_url = require("./url-BvjYQdxL.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
6
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
7
7
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_docloader = require("./docloader-
|
|
3
|
-
const require_request = require("./request-
|
|
4
|
-
const require_url = require("./url-
|
|
2
|
+
const require_docloader = require("./docloader-QmR6VOqT.cjs");
|
|
3
|
+
const require_request = require("./request-DxSceLvB.cjs");
|
|
4
|
+
const require_url = require("./url-BvjYQdxL.cjs");
|
|
5
5
|
let node_assert = require("node:assert");
|
|
6
6
|
let node_test = require("node:test");
|
|
7
7
|
//#region ../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as getRemoteDocument, r as preloadedContexts, t as getDocumentLoader } from "./docloader-
|
|
2
|
-
import { t as FetchError } from "./request-
|
|
3
|
-
import { t as UrlError } from "./url-
|
|
1
|
+
import { n as getRemoteDocument, r as preloadedContexts, t as getDocumentLoader } from "./docloader-CBVde8Va.mjs";
|
|
2
|
+
import { t as FetchError } from "./request-BHx0fCb5.mjs";
|
|
3
|
+
import { t as UrlError } from "./url-a2D8NAgh.mjs";
|
|
4
4
|
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
5
5
|
import { test } from "node:test";
|
|
6
6
|
//#region \0rolldown/runtime.js
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_url = require("./url-
|
|
2
|
+
const require_url = require("./url-BvjYQdxL.cjs");
|
|
3
3
|
let node_assert = require("node:assert");
|
|
4
4
|
let node_test = require("node:test");
|
|
5
5
|
let jsonld_dist_jsonld_esm_js = require("jsonld/dist/jsonld.esm.js");
|
|
@@ -17,7 +17,7 @@ const noJsonLdContext = Symbol("noJsonLdContext");
|
|
|
17
17
|
* Semantic Versioning decisions.
|
|
18
18
|
*/
|
|
19
19
|
function isTrustedIriOrigin(options, left, right) {
|
|
20
|
-
return options.crossOrigin === "trust" || left == null || right != null && require_url.haveSameIriOrigin(left, right);
|
|
20
|
+
return options.crossOrigin === "trust" || left == null || right != null && (require_url.haveSameIriOrigin(left, right) || require_url.haveSameFe34Origin(left, right));
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Normalizes portable IRIs in JSON-LD cache data.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as formatIri,
|
|
1
|
+
import { a as formatIri, c as haveSameIriOrigin, d as parseIri, s as haveSameFe34Origin } from "./url-a2D8NAgh.mjs";
|
|
2
2
|
import { deepStrictEqual, ok, strictEqual } from "node:assert";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import jsonld from "jsonld/dist/jsonld.esm.js";
|
|
@@ -15,7 +15,7 @@ const noJsonLdContext = Symbol("noJsonLdContext");
|
|
|
15
15
|
* Semantic Versioning decisions.
|
|
16
16
|
*/
|
|
17
17
|
function isTrustedIriOrigin(options, left, right) {
|
|
18
|
-
return options.crossOrigin === "trust" || left == null || right != null && haveSameIriOrigin(left, right);
|
|
18
|
+
return options.crossOrigin === "trust" || left == null || right != null && (haveSameIriOrigin(left, right) || haveSameFe34Origin(left, right));
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Normalizes portable IRIs in JSON-LD cache data.
|
|
@@ -3,7 +3,7 @@ let node_process = require("node:process");
|
|
|
3
3
|
node_process = require_chunk.__toESM(node_process, 1);
|
|
4
4
|
//#region deno.json
|
|
5
5
|
var name = "@fedify/vocab-runtime";
|
|
6
|
-
var version = "2.4.0-dev.
|
|
6
|
+
var version = "2.4.0-dev.1618+58858243";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/request.ts
|
|
9
9
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-DxSceLvB.cjs");
|
|
3
3
|
let node_assert = require("node:assert");
|
|
4
4
|
let node_test = require("node:test");
|
|
5
5
|
let node_process = require("node:process");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as version, r as getUserAgent } from "./request-
|
|
1
|
+
import { o as version, r as getUserAgent } from "./request-BHx0fCb5.mjs";
|
|
2
2
|
import { deepStrictEqual } from "node:assert";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import process from "node:process";
|
|
@@ -63,7 +63,7 @@ function canonicalizePortableUri(input) {
|
|
|
63
63
|
const parsed = parsePortableIri(input);
|
|
64
64
|
if (parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
|
|
65
65
|
const match = input.match(PORTABLE_IRI_PATTERN);
|
|
66
|
-
return `ap+ef61://${normalizePortableAuthority(decodePortableAuthority(parsed.host)
|
|
66
|
+
return `ap+ef61://${normalizePortableAuthority(getDidUrlOrigin(decodePortableAuthority(parsed.host)))}${normalizePortableComponent(match[3])}${match[5] == null ? "" : normalizePortableComponent(match[5])}`;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Checks whether two FEP-ef61 portable ActivityPub URIs identify the same
|
|
@@ -88,6 +88,45 @@ function arePortableUrisEqual(left, right) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
92
|
+
*
|
|
93
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
94
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
95
|
+
*
|
|
96
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
97
|
+
* @since 2.4.0
|
|
98
|
+
*/
|
|
99
|
+
function getFe34Origin(input) {
|
|
100
|
+
if (input instanceof URL) {
|
|
101
|
+
const portable = normalizePortableUrl(input);
|
|
102
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
103
|
+
if (input.protocol === "did:") return getDidUrlOrigin(input.href);
|
|
104
|
+
if (input.protocol === "http:" || input.protocol === "https:") return input.origin;
|
|
105
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
106
|
+
}
|
|
107
|
+
const portable = parsePortableIri(input);
|
|
108
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
109
|
+
if (DID_SCHEME_PATTERN.test(input)) return getDidUrlOrigin(input);
|
|
110
|
+
const parsed = new URL(input);
|
|
111
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") return parsed.origin;
|
|
112
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
116
|
+
*
|
|
117
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
118
|
+
*
|
|
119
|
+
* @since 2.4.0
|
|
120
|
+
*/
|
|
121
|
+
function haveSameFe34Origin(left, right) {
|
|
122
|
+
try {
|
|
123
|
+
return getFe34Origin(left) === getFe34Origin(right);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof TypeError) return false;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
91
130
|
* Checks whether two IRIs have the same origin.
|
|
92
131
|
*/
|
|
93
132
|
function haveSameIriOrigin(left, right) {
|
|
@@ -97,15 +136,25 @@ function getComparableIriOrigin(iri) {
|
|
|
97
136
|
iri = normalizePortableUrl(iri) ?? iri;
|
|
98
137
|
if (iri.origin !== "null") return iri.origin;
|
|
99
138
|
if (iri.host !== "") {
|
|
100
|
-
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(decodePortableAuthority(iri.host)
|
|
139
|
+
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(getDidUrlOrigin(decodePortableAuthority(iri.host))) : iri.host;
|
|
101
140
|
return `${iri.protocol}//${host}`;
|
|
102
141
|
}
|
|
103
142
|
return iri.href;
|
|
104
143
|
}
|
|
144
|
+
function getPortableCryptographicOrigin(iri) {
|
|
145
|
+
return getDidUrlOrigin(decodePortableAuthority(iri.host));
|
|
146
|
+
}
|
|
147
|
+
function getDidUrlOrigin(iri) {
|
|
148
|
+
const did = iri.split(/[/?#]/, 1)[0].replace(DID_SCHEME_PATTERN, "did:");
|
|
149
|
+
if (!DID_PATTERN.test(did)) throw new TypeError("Invalid DID URL.");
|
|
150
|
+
const parts = did.split(":");
|
|
151
|
+
parts[1] = parts[1].toLowerCase();
|
|
152
|
+
return normalizePortableAuthority(parts.join(":"));
|
|
153
|
+
}
|
|
105
154
|
function parsePortableIri(iri) {
|
|
106
155
|
const match = iri.match(PORTABLE_IRI_PATTERN);
|
|
107
156
|
if (match == null) return null;
|
|
108
|
-
const authority = decodePortableAuthority(match[2]);
|
|
157
|
+
const authority = getDidUrlOrigin(decodePortableAuthority(match[2]));
|
|
109
158
|
if (!DID_PATTERN.test(authority)) throw new TypeError("Invalid portable ActivityPub IRI authority.");
|
|
110
159
|
if (match[3] === "") throw new TypeError("Invalid portable ActivityPub IRI path.");
|
|
111
160
|
return new URL(`ap+ef61://${encodeURIComponent(authority)}${match[3]}${match[4] ?? ""}${match[5] ?? ""}`);
|
|
@@ -357,6 +406,18 @@ Object.defineProperty(exports, "formatIri", {
|
|
|
357
406
|
return formatIri;
|
|
358
407
|
}
|
|
359
408
|
});
|
|
409
|
+
Object.defineProperty(exports, "getFe34Origin", {
|
|
410
|
+
enumerable: true,
|
|
411
|
+
get: function() {
|
|
412
|
+
return getFe34Origin;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
Object.defineProperty(exports, "haveSameFe34Origin", {
|
|
416
|
+
enumerable: true,
|
|
417
|
+
get: function() {
|
|
418
|
+
return haveSameFe34Origin;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
360
421
|
Object.defineProperty(exports, "haveSameIriOrigin", {
|
|
361
422
|
enumerable: true,
|
|
362
423
|
get: function() {
|
|
@@ -62,7 +62,7 @@ function canonicalizePortableUri(input) {
|
|
|
62
62
|
const parsed = parsePortableIri(input);
|
|
63
63
|
if (parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
|
|
64
64
|
const match = input.match(PORTABLE_IRI_PATTERN);
|
|
65
|
-
return `ap+ef61://${normalizePortableAuthority(decodePortableAuthority(parsed.host)
|
|
65
|
+
return `ap+ef61://${normalizePortableAuthority(getDidUrlOrigin(decodePortableAuthority(parsed.host)))}${normalizePortableComponent(match[3])}${match[5] == null ? "" : normalizePortableComponent(match[5])}`;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Checks whether two FEP-ef61 portable ActivityPub URIs identify the same
|
|
@@ -87,6 +87,45 @@ function arePortableUrisEqual(left, right) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
91
|
+
*
|
|
92
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
93
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
94
|
+
*
|
|
95
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
96
|
+
* @since 2.4.0
|
|
97
|
+
*/
|
|
98
|
+
function getFe34Origin(input) {
|
|
99
|
+
if (input instanceof URL) {
|
|
100
|
+
const portable = normalizePortableUrl(input);
|
|
101
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
102
|
+
if (input.protocol === "did:") return getDidUrlOrigin(input.href);
|
|
103
|
+
if (input.protocol === "http:" || input.protocol === "https:") return input.origin;
|
|
104
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
105
|
+
}
|
|
106
|
+
const portable = parsePortableIri(input);
|
|
107
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
108
|
+
if (DID_SCHEME_PATTERN.test(input)) return getDidUrlOrigin(input);
|
|
109
|
+
const parsed = new URL(input);
|
|
110
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") return parsed.origin;
|
|
111
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
115
|
+
*
|
|
116
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
117
|
+
*
|
|
118
|
+
* @since 2.4.0
|
|
119
|
+
*/
|
|
120
|
+
function haveSameFe34Origin(left, right) {
|
|
121
|
+
try {
|
|
122
|
+
return getFe34Origin(left) === getFe34Origin(right);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof TypeError) return false;
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
90
129
|
* Checks whether two IRIs have the same origin.
|
|
91
130
|
*/
|
|
92
131
|
function haveSameIriOrigin(left, right) {
|
|
@@ -96,15 +135,25 @@ function getComparableIriOrigin(iri) {
|
|
|
96
135
|
iri = normalizePortableUrl(iri) ?? iri;
|
|
97
136
|
if (iri.origin !== "null") return iri.origin;
|
|
98
137
|
if (iri.host !== "") {
|
|
99
|
-
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(decodePortableAuthority(iri.host)
|
|
138
|
+
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(getDidUrlOrigin(decodePortableAuthority(iri.host))) : iri.host;
|
|
100
139
|
return `${iri.protocol}//${host}`;
|
|
101
140
|
}
|
|
102
141
|
return iri.href;
|
|
103
142
|
}
|
|
143
|
+
function getPortableCryptographicOrigin(iri) {
|
|
144
|
+
return getDidUrlOrigin(decodePortableAuthority(iri.host));
|
|
145
|
+
}
|
|
146
|
+
function getDidUrlOrigin(iri) {
|
|
147
|
+
const did = iri.split(/[/?#]/, 1)[0].replace(DID_SCHEME_PATTERN, "did:");
|
|
148
|
+
if (!DID_PATTERN.test(did)) throw new TypeError("Invalid DID URL.");
|
|
149
|
+
const parts = did.split(":");
|
|
150
|
+
parts[1] = parts[1].toLowerCase();
|
|
151
|
+
return normalizePortableAuthority(parts.join(":"));
|
|
152
|
+
}
|
|
104
153
|
function parsePortableIri(iri) {
|
|
105
154
|
const match = iri.match(PORTABLE_IRI_PATTERN);
|
|
106
155
|
if (match == null) return null;
|
|
107
|
-
const authority = decodePortableAuthority(match[2]);
|
|
156
|
+
const authority = getDidUrlOrigin(decodePortableAuthority(match[2]));
|
|
108
157
|
if (!DID_PATTERN.test(authority)) throw new TypeError("Invalid portable ActivityPub IRI authority.");
|
|
109
158
|
if (match[3] === "") throw new TypeError("Invalid portable ActivityPub IRI path.");
|
|
110
159
|
return new URL(`ap+ef61://${encodeURIComponent(authority)}${match[3]}${match[4] ?? ""}${match[5] ?? ""}`);
|
|
@@ -326,4 +375,4 @@ function matchesIPv6Prefix(address, prefixWords, prefixLength) {
|
|
|
326
375
|
return true;
|
|
327
376
|
}
|
|
328
377
|
//#endregion
|
|
329
|
-
export { formatIri as a,
|
|
378
|
+
export { formatIri as a, haveSameIriOrigin as c, parseIri as d, parseJsonLdId as f, expandIPv6Address as i, isValidPublicIPv4Address as l, arePortableUrisEqual as n, getFe34Origin as o, validatePublicUrl as p, canonicalizePortableUri as r, haveSameFe34Origin as s, UrlError as t, isValidPublicIPv6Address as u };
|
package/dist/tests/url.test.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_url = require("./url-
|
|
2
|
+
const require_url = require("./url-BvjYQdxL.cjs");
|
|
3
3
|
let node_assert = require("node:assert");
|
|
4
4
|
let node_test = require("node:test");
|
|
5
5
|
//#region src/url.test.ts
|
|
@@ -12,8 +12,12 @@ let node_test = require("node:test");
|
|
|
12
12
|
"AP+EF61://did:key:z6Mkabc/actor"
|
|
13
13
|
]) (0, node_assert.deepStrictEqual)(require_url.parseIri(iri), new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"));
|
|
14
14
|
});
|
|
15
|
-
(0, node_test.test)("parseIri()
|
|
16
|
-
for (const iri of [
|
|
15
|
+
(0, node_test.test)("parseIri() normalizes DID scheme and method casing", () => {
|
|
16
|
+
for (const iri of [
|
|
17
|
+
"ap://DID:key:z6Mkabc/actor",
|
|
18
|
+
"ap://DID%3Akey%3Az6Mkabc/actor",
|
|
19
|
+
"ap://did:KEY:z6Mkabc/actor"
|
|
20
|
+
]) (0, node_assert.deepStrictEqual)(require_url.parseIri(iri), new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"));
|
|
17
21
|
});
|
|
18
22
|
(0, node_test.test)("parseIri() accepts DID method names that start with digits", () => {
|
|
19
23
|
(0, node_assert.deepStrictEqual)(require_url.parseIri("ap://did:3:abc/actor"), new URL("ap+ef61://did%3A3%3Aabc/actor"));
|
|
@@ -60,12 +64,50 @@ let node_test = require("node:test");
|
|
|
60
64
|
]) (0, node_assert.throws)(() => require_url.parseIri(iri), TypeError);
|
|
61
65
|
});
|
|
62
66
|
(0, node_test.test)("haveSameIriOrigin() compares portable IRI authorities", () => {
|
|
67
|
+
(0, node_assert.ok)(require_url.haveSameIriOrigin(new URL("ftp://example.com/pub/1"), new URL("ftp://example.com/pub/2")));
|
|
68
|
+
(0, node_assert.ok)(require_url.haveSameIriOrigin(new URL("mailto:alice@example.com"), new URL("mailto:alice@example.com")));
|
|
63
69
|
(0, node_assert.ok)(require_url.haveSameIriOrigin(require_url.parseIri("ap://did:key:z6Mkabc/actor"), require_url.parseIri("ap://did:key:z6Mkabc/outbox")));
|
|
64
70
|
(0, node_assert.ok)(require_url.haveSameIriOrigin(new URL("ap://did%3Akey%3Az6Mkabc/actor"), new URL("ap+ef61://did%3Akey%3Az6Mkabc/outbox")));
|
|
65
71
|
(0, node_assert.ok)(require_url.haveSameIriOrigin(require_url.parseIri("ap://DID:key:z6Mkabc/actor"), require_url.parseIri("ap://did:key:z6Mkabc/outbox")));
|
|
66
72
|
(0, node_assert.ok)(require_url.haveSameIriOrigin(new URL("ap+ef61://DID%3Akey%3Az6Mkabc/actor"), new URL("ap+ef61://did%3Akey%3Az6Mkabc/outbox")));
|
|
67
73
|
(0, node_assert.ok)(!require_url.haveSameIriOrigin(require_url.parseIri("ap://did:key:z6Mkabc/actor"), require_url.parseIri("ap://did:key:z6Mkdef/actor")));
|
|
68
74
|
});
|
|
75
|
+
(0, node_test.test)("getFe34Origin() computes web and cryptographic origins", () => {
|
|
76
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("https://Example.COM:443/users/alice"), "https://example.com");
|
|
77
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin(new URL("http://example.com:8080/notes/1")), "http://example.com:8080");
|
|
78
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("ap://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fa.example"), "did:key:z6Mkabc");
|
|
79
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("ap+ef61://did%3Akey%3Az6Mkabc/objects/1#fragment"), "did:key:z6Mkabc");
|
|
80
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin(new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor")), "did:key:z6Mkabc");
|
|
81
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("did:key:z6Mkabc#z6Mkabc"), "did:key:z6Mkabc");
|
|
82
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin(new URL("did:key:z6Mkabc?service=activitypub#key")), "did:key:z6Mkabc");
|
|
83
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("did:key:z6Mkabc/path/to/resource?service=activitypub#key"), "did:key:z6Mkabc");
|
|
84
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("did:KEY:z6Mkabc#z6Mkabc"), "did:key:z6Mkabc");
|
|
85
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("ap://did%3Aweb%3Afoo%2Dbar.example/actor"), "did:web:foo-bar.example");
|
|
86
|
+
(0, node_assert.deepStrictEqual)(require_url.getFe34Origin("did:web:foo%2dbar.example#key"), "did:web:foo-bar.example");
|
|
87
|
+
});
|
|
88
|
+
(0, node_test.test)("getFe34Origin() rejects unsupported or malformed identifiers", () => {
|
|
89
|
+
for (const iri of [
|
|
90
|
+
"mailto:alice@example.com",
|
|
91
|
+
"ap://not-a-did/actor",
|
|
92
|
+
"ap://did:key/actor",
|
|
93
|
+
"did:key",
|
|
94
|
+
"did:key:",
|
|
95
|
+
"did:"
|
|
96
|
+
]) (0, node_assert.throws)(() => require_url.getFe34Origin(iri), TypeError);
|
|
97
|
+
});
|
|
98
|
+
(0, node_test.test)("haveSameFe34Origin() compares web and cryptographic origins", () => {
|
|
99
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("https://example.com/users/alice", "https://example.com/notes/1"));
|
|
100
|
+
(0, node_assert.ok)(!require_url.haveSameFe34Origin("https://example.com/users/alice", "http://example.com/users/alice"));
|
|
101
|
+
(0, node_assert.ok)(!require_url.haveSameFe34Origin("https://example.com/users/alice", "https://example.com:8443/users/alice"));
|
|
102
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("ap://did:key:z6Mkabc/actor", "ap+ef61://did%3Akey%3Az6Mkabc/objects/1"));
|
|
103
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "did:key:z6Mkabc#z6Mkabc"));
|
|
104
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("ap://did:KEY:z6Mkabc/actor", "did:key:z6Mkabc#z6Mkabc"));
|
|
105
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("ap://did%3Aweb%3Afoo%2Dbar.example/actor", "ap://did:web:foo-bar.example/note"));
|
|
106
|
+
(0, node_assert.ok)(require_url.haveSameFe34Origin("ap://did%3Aexample%3Aabc%252fdef/actor", "did:example:abc%2Fdef#key"));
|
|
107
|
+
(0, node_assert.ok)(!require_url.haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "did:key:z6Mkdef#z6Mkdef"));
|
|
108
|
+
(0, node_assert.ok)(!require_url.haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "https://example.com/actor"));
|
|
109
|
+
(0, node_assert.ok)(!require_url.haveSameFe34Origin("ap://not-a-did/actor", "ap://not-a-did/actor"));
|
|
110
|
+
});
|
|
69
111
|
(0, node_test.test)("parseIri() normalizes portable URL instances", () => {
|
|
70
112
|
(0, node_assert.deepStrictEqual)(require_url.parseIri(new URL("ap+ef61://did%3Aexample%3Aabc%2Fdef/actor")), new URL("ap+ef61://did%3Aexample%3Aabc%252Fdef/actor"));
|
|
71
113
|
(0, node_assert.throws)(() => require_url.parseIri("ap+ef61://not-a-did/actor"), TypeError);
|
package/dist/tests/url.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as formatIri, c as
|
|
1
|
+
import { a as formatIri, c as haveSameIriOrigin, d as parseIri, f as parseJsonLdId, i as expandIPv6Address, l as isValidPublicIPv4Address, n as arePortableUrisEqual, o as getFe34Origin, p as validatePublicUrl, r as canonicalizePortableUri, s as haveSameFe34Origin, t as UrlError, u as isValidPublicIPv6Address } from "./url-a2D8NAgh.mjs";
|
|
2
2
|
import { deepStrictEqual, ok, rejects, throws } from "node:assert";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
//#region src/url.test.ts
|
|
@@ -11,8 +11,12 @@ test("parseIri() accepts portable ActivityPub URI schemes", () => {
|
|
|
11
11
|
"AP+EF61://did:key:z6Mkabc/actor"
|
|
12
12
|
]) deepStrictEqual(parseIri(iri), new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"));
|
|
13
13
|
});
|
|
14
|
-
test("parseIri()
|
|
15
|
-
for (const iri of [
|
|
14
|
+
test("parseIri() normalizes DID scheme and method casing", () => {
|
|
15
|
+
for (const iri of [
|
|
16
|
+
"ap://DID:key:z6Mkabc/actor",
|
|
17
|
+
"ap://DID%3Akey%3Az6Mkabc/actor",
|
|
18
|
+
"ap://did:KEY:z6Mkabc/actor"
|
|
19
|
+
]) deepStrictEqual(parseIri(iri), new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"));
|
|
16
20
|
});
|
|
17
21
|
test("parseIri() accepts DID method names that start with digits", () => {
|
|
18
22
|
deepStrictEqual(parseIri("ap://did:3:abc/actor"), new URL("ap+ef61://did%3A3%3Aabc/actor"));
|
|
@@ -59,12 +63,50 @@ test("parseIri() rejects malformed portable DID authorities", () => {
|
|
|
59
63
|
]) throws(() => parseIri(iri), TypeError);
|
|
60
64
|
});
|
|
61
65
|
test("haveSameIriOrigin() compares portable IRI authorities", () => {
|
|
66
|
+
ok(haveSameIriOrigin(new URL("ftp://example.com/pub/1"), new URL("ftp://example.com/pub/2")));
|
|
67
|
+
ok(haveSameIriOrigin(new URL("mailto:alice@example.com"), new URL("mailto:alice@example.com")));
|
|
62
68
|
ok(haveSameIriOrigin(parseIri("ap://did:key:z6Mkabc/actor"), parseIri("ap://did:key:z6Mkabc/outbox")));
|
|
63
69
|
ok(haveSameIriOrigin(new URL("ap://did%3Akey%3Az6Mkabc/actor"), new URL("ap+ef61://did%3Akey%3Az6Mkabc/outbox")));
|
|
64
70
|
ok(haveSameIriOrigin(parseIri("ap://DID:key:z6Mkabc/actor"), parseIri("ap://did:key:z6Mkabc/outbox")));
|
|
65
71
|
ok(haveSameIriOrigin(new URL("ap+ef61://DID%3Akey%3Az6Mkabc/actor"), new URL("ap+ef61://did%3Akey%3Az6Mkabc/outbox")));
|
|
66
72
|
ok(!haveSameIriOrigin(parseIri("ap://did:key:z6Mkabc/actor"), parseIri("ap://did:key:z6Mkdef/actor")));
|
|
67
73
|
});
|
|
74
|
+
test("getFe34Origin() computes web and cryptographic origins", () => {
|
|
75
|
+
deepStrictEqual(getFe34Origin("https://Example.COM:443/users/alice"), "https://example.com");
|
|
76
|
+
deepStrictEqual(getFe34Origin(new URL("http://example.com:8080/notes/1")), "http://example.com:8080");
|
|
77
|
+
deepStrictEqual(getFe34Origin("ap://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fa.example"), "did:key:z6Mkabc");
|
|
78
|
+
deepStrictEqual(getFe34Origin("ap+ef61://did%3Akey%3Az6Mkabc/objects/1#fragment"), "did:key:z6Mkabc");
|
|
79
|
+
deepStrictEqual(getFe34Origin(new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor")), "did:key:z6Mkabc");
|
|
80
|
+
deepStrictEqual(getFe34Origin("did:key:z6Mkabc#z6Mkabc"), "did:key:z6Mkabc");
|
|
81
|
+
deepStrictEqual(getFe34Origin(new URL("did:key:z6Mkabc?service=activitypub#key")), "did:key:z6Mkabc");
|
|
82
|
+
deepStrictEqual(getFe34Origin("did:key:z6Mkabc/path/to/resource?service=activitypub#key"), "did:key:z6Mkabc");
|
|
83
|
+
deepStrictEqual(getFe34Origin("did:KEY:z6Mkabc#z6Mkabc"), "did:key:z6Mkabc");
|
|
84
|
+
deepStrictEqual(getFe34Origin("ap://did%3Aweb%3Afoo%2Dbar.example/actor"), "did:web:foo-bar.example");
|
|
85
|
+
deepStrictEqual(getFe34Origin("did:web:foo%2dbar.example#key"), "did:web:foo-bar.example");
|
|
86
|
+
});
|
|
87
|
+
test("getFe34Origin() rejects unsupported or malformed identifiers", () => {
|
|
88
|
+
for (const iri of [
|
|
89
|
+
"mailto:alice@example.com",
|
|
90
|
+
"ap://not-a-did/actor",
|
|
91
|
+
"ap://did:key/actor",
|
|
92
|
+
"did:key",
|
|
93
|
+
"did:key:",
|
|
94
|
+
"did:"
|
|
95
|
+
]) throws(() => getFe34Origin(iri), TypeError);
|
|
96
|
+
});
|
|
97
|
+
test("haveSameFe34Origin() compares web and cryptographic origins", () => {
|
|
98
|
+
ok(haveSameFe34Origin("https://example.com/users/alice", "https://example.com/notes/1"));
|
|
99
|
+
ok(!haveSameFe34Origin("https://example.com/users/alice", "http://example.com/users/alice"));
|
|
100
|
+
ok(!haveSameFe34Origin("https://example.com/users/alice", "https://example.com:8443/users/alice"));
|
|
101
|
+
ok(haveSameFe34Origin("ap://did:key:z6Mkabc/actor", "ap+ef61://did%3Akey%3Az6Mkabc/objects/1"));
|
|
102
|
+
ok(haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "did:key:z6Mkabc#z6Mkabc"));
|
|
103
|
+
ok(haveSameFe34Origin("ap://did:KEY:z6Mkabc/actor", "did:key:z6Mkabc#z6Mkabc"));
|
|
104
|
+
ok(haveSameFe34Origin("ap://did%3Aweb%3Afoo%2Dbar.example/actor", "ap://did:web:foo-bar.example/note"));
|
|
105
|
+
ok(haveSameFe34Origin("ap://did%3Aexample%3Aabc%252fdef/actor", "did:example:abc%2Fdef#key"));
|
|
106
|
+
ok(!haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "did:key:z6Mkdef#z6Mkdef"));
|
|
107
|
+
ok(!haveSameFe34Origin("ap+ef61://did:key:z6Mkabc/actor", "https://example.com/actor"));
|
|
108
|
+
ok(!haveSameFe34Origin("ap://not-a-did/actor", "ap://not-a-did/actor"));
|
|
109
|
+
});
|
|
68
110
|
test("parseIri() normalizes portable URL instances", () => {
|
|
69
111
|
deepStrictEqual(parseIri(new URL("ap+ef61://did%3Aexample%3Aabc%2Fdef/actor")), new URL("ap+ef61://did%3Aexample%3Aabc%252Fdef/actor"));
|
|
70
112
|
throws(() => parseIri("ap+ef61://not-a-did/actor"), TypeError);
|
|
@@ -64,7 +64,7 @@ function canonicalizePortableUri(input) {
|
|
|
64
64
|
const parsed = parsePortableIri(input);
|
|
65
65
|
if (parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
|
|
66
66
|
const match = input.match(PORTABLE_IRI_PATTERN);
|
|
67
|
-
return `ap+ef61://${normalizePortableAuthority(decodePortableAuthority(parsed.host)
|
|
67
|
+
return `ap+ef61://${normalizePortableAuthority(getDidUrlOrigin(decodePortableAuthority(parsed.host)))}${normalizePortableComponent(match[3])}${match[5] == null ? "" : normalizePortableComponent(match[5])}`;
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Checks whether two FEP-ef61 portable ActivityPub URIs identify the same
|
|
@@ -89,6 +89,45 @@ function arePortableUrisEqual(left, right) {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
93
|
+
*
|
|
94
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
95
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
96
|
+
*
|
|
97
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
98
|
+
* @since 2.4.0
|
|
99
|
+
*/
|
|
100
|
+
function getFe34Origin(input) {
|
|
101
|
+
if (input instanceof URL) {
|
|
102
|
+
const portable = normalizePortableUrl(input);
|
|
103
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
104
|
+
if (input.protocol === "did:") return getDidUrlOrigin(input.href);
|
|
105
|
+
if (input.protocol === "http:" || input.protocol === "https:") return input.origin;
|
|
106
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
107
|
+
}
|
|
108
|
+
const portable = parsePortableIri(input);
|
|
109
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
110
|
+
if (DID_SCHEME_PATTERN.test(input)) return getDidUrlOrigin(input);
|
|
111
|
+
const parsed = new URL(input);
|
|
112
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") return parsed.origin;
|
|
113
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
117
|
+
*
|
|
118
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
119
|
+
*
|
|
120
|
+
* @since 2.4.0
|
|
121
|
+
*/
|
|
122
|
+
function haveSameFe34Origin(left, right) {
|
|
123
|
+
try {
|
|
124
|
+
return getFe34Origin(left) === getFe34Origin(right);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof TypeError) return false;
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
92
131
|
* Checks whether two IRIs have the same origin.
|
|
93
132
|
*/
|
|
94
133
|
function haveSameIriOrigin(left, right) {
|
|
@@ -98,15 +137,25 @@ function getComparableIriOrigin(iri) {
|
|
|
98
137
|
iri = normalizePortableUrl(iri) ?? iri;
|
|
99
138
|
if (iri.origin !== "null") return iri.origin;
|
|
100
139
|
if (iri.host !== "") {
|
|
101
|
-
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(decodePortableAuthority(iri.host)
|
|
140
|
+
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(getDidUrlOrigin(decodePortableAuthority(iri.host))) : iri.host;
|
|
102
141
|
return `${iri.protocol}//${host}`;
|
|
103
142
|
}
|
|
104
143
|
return iri.href;
|
|
105
144
|
}
|
|
145
|
+
function getPortableCryptographicOrigin(iri) {
|
|
146
|
+
return getDidUrlOrigin(decodePortableAuthority(iri.host));
|
|
147
|
+
}
|
|
148
|
+
function getDidUrlOrigin(iri) {
|
|
149
|
+
const did = iri.split(/[/?#]/, 1)[0].replace(DID_SCHEME_PATTERN, "did:");
|
|
150
|
+
if (!DID_PATTERN.test(did)) throw new TypeError("Invalid DID URL.");
|
|
151
|
+
const parts = did.split(":");
|
|
152
|
+
parts[1] = parts[1].toLowerCase();
|
|
153
|
+
return normalizePortableAuthority(parts.join(":"));
|
|
154
|
+
}
|
|
106
155
|
function parsePortableIri(iri) {
|
|
107
156
|
const match = iri.match(PORTABLE_IRI_PATTERN);
|
|
108
157
|
if (match == null) return null;
|
|
109
|
-
const authority = decodePortableAuthority(match[2]);
|
|
158
|
+
const authority = getDidUrlOrigin(decodePortableAuthority(match[2]));
|
|
110
159
|
if (!DID_PATTERN.test(authority)) throw new TypeError("Invalid portable ActivityPub IRI authority.");
|
|
111
160
|
if (match[3] === "") throw new TypeError("Invalid portable ActivityPub IRI path.");
|
|
112
161
|
return new URL(`ap+ef61://${encodeURIComponent(authority)}${match[3]}${match[4] ?? ""}${match[5] ?? ""}`);
|
|
@@ -358,6 +407,18 @@ Object.defineProperty(exports, "formatIri", {
|
|
|
358
407
|
return formatIri;
|
|
359
408
|
}
|
|
360
409
|
});
|
|
410
|
+
Object.defineProperty(exports, "getFe34Origin", {
|
|
411
|
+
enumerable: true,
|
|
412
|
+
get: function() {
|
|
413
|
+
return getFe34Origin;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
Object.defineProperty(exports, "haveSameFe34Origin", {
|
|
417
|
+
enumerable: true,
|
|
418
|
+
get: function() {
|
|
419
|
+
return haveSameFe34Origin;
|
|
420
|
+
}
|
|
421
|
+
});
|
|
361
422
|
Object.defineProperty(exports, "haveSameIriOrigin", {
|
|
362
423
|
enumerable: true,
|
|
363
424
|
get: function() {
|
|
@@ -63,7 +63,7 @@ function canonicalizePortableUri(input) {
|
|
|
63
63
|
const parsed = parsePortableIri(input);
|
|
64
64
|
if (parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
|
|
65
65
|
const match = input.match(PORTABLE_IRI_PATTERN);
|
|
66
|
-
return `ap+ef61://${normalizePortableAuthority(decodePortableAuthority(parsed.host)
|
|
66
|
+
return `ap+ef61://${normalizePortableAuthority(getDidUrlOrigin(decodePortableAuthority(parsed.host)))}${normalizePortableComponent(match[3])}${match[5] == null ? "" : normalizePortableComponent(match[5])}`;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Checks whether two FEP-ef61 portable ActivityPub URIs identify the same
|
|
@@ -88,6 +88,45 @@ function arePortableUrisEqual(left, right) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
92
|
+
*
|
|
93
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
94
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
95
|
+
*
|
|
96
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
97
|
+
* @since 2.4.0
|
|
98
|
+
*/
|
|
99
|
+
function getFe34Origin(input) {
|
|
100
|
+
if (input instanceof URL) {
|
|
101
|
+
const portable = normalizePortableUrl(input);
|
|
102
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
103
|
+
if (input.protocol === "did:") return getDidUrlOrigin(input.href);
|
|
104
|
+
if (input.protocol === "http:" || input.protocol === "https:") return input.origin;
|
|
105
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
106
|
+
}
|
|
107
|
+
const portable = parsePortableIri(input);
|
|
108
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
109
|
+
if (DID_SCHEME_PATTERN.test(input)) return getDidUrlOrigin(input);
|
|
110
|
+
const parsed = new URL(input);
|
|
111
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") return parsed.origin;
|
|
112
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
116
|
+
*
|
|
117
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
118
|
+
*
|
|
119
|
+
* @since 2.4.0
|
|
120
|
+
*/
|
|
121
|
+
function haveSameFe34Origin(left, right) {
|
|
122
|
+
try {
|
|
123
|
+
return getFe34Origin(left) === getFe34Origin(right);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof TypeError) return false;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
91
130
|
* Checks whether two IRIs have the same origin.
|
|
92
131
|
*/
|
|
93
132
|
function haveSameIriOrigin(left, right) {
|
|
@@ -97,15 +136,25 @@ function getComparableIriOrigin(iri) {
|
|
|
97
136
|
iri = normalizePortableUrl(iri) ?? iri;
|
|
98
137
|
if (iri.origin !== "null") return iri.origin;
|
|
99
138
|
if (iri.host !== "") {
|
|
100
|
-
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(decodePortableAuthority(iri.host)
|
|
139
|
+
const host = iri.protocol === "ap+ef61:" ? encodeURIComponent(getDidUrlOrigin(decodePortableAuthority(iri.host))) : iri.host;
|
|
101
140
|
return `${iri.protocol}//${host}`;
|
|
102
141
|
}
|
|
103
142
|
return iri.href;
|
|
104
143
|
}
|
|
144
|
+
function getPortableCryptographicOrigin(iri) {
|
|
145
|
+
return getDidUrlOrigin(decodePortableAuthority(iri.host));
|
|
146
|
+
}
|
|
147
|
+
function getDidUrlOrigin(iri) {
|
|
148
|
+
const did = iri.split(/[/?#]/, 1)[0].replace(DID_SCHEME_PATTERN, "did:");
|
|
149
|
+
if (!DID_PATTERN.test(did)) throw new TypeError("Invalid DID URL.");
|
|
150
|
+
const parts = did.split(":");
|
|
151
|
+
parts[1] = parts[1].toLowerCase();
|
|
152
|
+
return normalizePortableAuthority(parts.join(":"));
|
|
153
|
+
}
|
|
105
154
|
function parsePortableIri(iri) {
|
|
106
155
|
const match = iri.match(PORTABLE_IRI_PATTERN);
|
|
107
156
|
if (match == null) return null;
|
|
108
|
-
const authority = decodePortableAuthority(match[2]);
|
|
157
|
+
const authority = getDidUrlOrigin(decodePortableAuthority(match[2]));
|
|
109
158
|
if (!DID_PATTERN.test(authority)) throw new TypeError("Invalid portable ActivityPub IRI authority.");
|
|
110
159
|
if (match[3] === "") throw new TypeError("Invalid portable ActivityPub IRI path.");
|
|
111
160
|
return new URL(`ap+ef61://${encodeURIComponent(authority)}${match[3]}${match[4] ?? ""}${match[5] ?? ""}`);
|
|
@@ -327,4 +376,4 @@ function matchesIPv6Prefix(address, prefixWords, prefixLength) {
|
|
|
327
376
|
return true;
|
|
328
377
|
}
|
|
329
378
|
//#endregion
|
|
330
|
-
export { formatIri as a,
|
|
379
|
+
export { formatIri as a, haveSameIriOrigin as c, parseIri as d, parseJsonLdId as f, expandIPv6Address as i, isValidPublicIPv4Address as l, arePortableUrisEqual as n, getFe34Origin as o, validatePublicUrl as p, canonicalizePortableUri as r, haveSameFe34Origin as s, UrlError as t, isValidPublicIPv6Address as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DocumentLoader } from "../docloader.ts";
|
|
2
2
|
import jsonld from "../jsonld.ts";
|
|
3
|
-
import { formatIri, haveSameIriOrigin } from "../url.ts";
|
|
3
|
+
import { formatIri, haveSameFe34Origin, haveSameIriOrigin } from "../url.ts";
|
|
4
4
|
|
|
5
5
|
const noJsonLdContext = Symbol("noJsonLdContext");
|
|
6
6
|
|
|
@@ -28,7 +28,8 @@ export function isTrustedIriOrigin(
|
|
|
28
28
|
right: URL | null | undefined,
|
|
29
29
|
): boolean {
|
|
30
30
|
return options.crossOrigin === "trust" || left == null ||
|
|
31
|
-
(right != null &&
|
|
31
|
+
(right != null &&
|
|
32
|
+
(haveSameIriOrigin(left, right) || haveSameFe34Origin(left, right)));
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/**
|
package/src/mod.ts
CHANGED
package/src/url.test.ts
CHANGED
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
canonicalizePortableUri,
|
|
6
6
|
expandIPv6Address,
|
|
7
7
|
formatIri,
|
|
8
|
+
getFe34Origin,
|
|
9
|
+
haveSameFe34Origin,
|
|
8
10
|
haveSameIriOrigin,
|
|
9
11
|
isValidPublicIPv4Address,
|
|
10
12
|
isValidPublicIPv6Address,
|
|
@@ -30,15 +32,16 @@ test("parseIri() accepts portable ActivityPub URI schemes", () => {
|
|
|
30
32
|
}
|
|
31
33
|
});
|
|
32
34
|
|
|
33
|
-
test("parseIri()
|
|
35
|
+
test("parseIri() normalizes DID scheme and method casing", () => {
|
|
34
36
|
const cases = [
|
|
35
37
|
"ap://DID:key:z6Mkabc/actor",
|
|
36
38
|
"ap://DID%3Akey%3Az6Mkabc/actor",
|
|
39
|
+
"ap://did:KEY:z6Mkabc/actor",
|
|
37
40
|
];
|
|
38
41
|
for (const iri of cases) {
|
|
39
42
|
deepStrictEqual(
|
|
40
43
|
parseIri(iri),
|
|
41
|
-
new URL("ap+ef61://
|
|
44
|
+
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"),
|
|
42
45
|
);
|
|
43
46
|
}
|
|
44
47
|
});
|
|
@@ -139,6 +142,14 @@ test("parseIri() rejects malformed portable DID authorities", () => {
|
|
|
139
142
|
});
|
|
140
143
|
|
|
141
144
|
test("haveSameIriOrigin() compares portable IRI authorities", () => {
|
|
145
|
+
ok(haveSameIriOrigin(
|
|
146
|
+
new URL("ftp://example.com/pub/1"),
|
|
147
|
+
new URL("ftp://example.com/pub/2"),
|
|
148
|
+
));
|
|
149
|
+
ok(haveSameIriOrigin(
|
|
150
|
+
new URL("mailto:alice@example.com"),
|
|
151
|
+
new URL("mailto:alice@example.com"),
|
|
152
|
+
));
|
|
142
153
|
ok(haveSameIriOrigin(
|
|
143
154
|
parseIri("ap://did:key:z6Mkabc/actor"),
|
|
144
155
|
parseIri("ap://did:key:z6Mkabc/outbox"),
|
|
@@ -163,6 +174,122 @@ test("haveSameIriOrigin() compares portable IRI authorities", () => {
|
|
|
163
174
|
);
|
|
164
175
|
});
|
|
165
176
|
|
|
177
|
+
test("getFe34Origin() computes web and cryptographic origins", () => {
|
|
178
|
+
deepStrictEqual(
|
|
179
|
+
getFe34Origin("https://Example.COM:443/users/alice"),
|
|
180
|
+
"https://example.com",
|
|
181
|
+
);
|
|
182
|
+
deepStrictEqual(
|
|
183
|
+
getFe34Origin(new URL("http://example.com:8080/notes/1")),
|
|
184
|
+
"http://example.com:8080",
|
|
185
|
+
);
|
|
186
|
+
deepStrictEqual(
|
|
187
|
+
getFe34Origin(
|
|
188
|
+
"ap://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fa.example",
|
|
189
|
+
),
|
|
190
|
+
"did:key:z6Mkabc",
|
|
191
|
+
);
|
|
192
|
+
deepStrictEqual(
|
|
193
|
+
getFe34Origin("ap+ef61://did%3Akey%3Az6Mkabc/objects/1#fragment"),
|
|
194
|
+
"did:key:z6Mkabc",
|
|
195
|
+
);
|
|
196
|
+
deepStrictEqual(
|
|
197
|
+
getFe34Origin(new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor")),
|
|
198
|
+
"did:key:z6Mkabc",
|
|
199
|
+
);
|
|
200
|
+
deepStrictEqual(
|
|
201
|
+
getFe34Origin("did:key:z6Mkabc#z6Mkabc"),
|
|
202
|
+
"did:key:z6Mkabc",
|
|
203
|
+
);
|
|
204
|
+
deepStrictEqual(
|
|
205
|
+
getFe34Origin(new URL("did:key:z6Mkabc?service=activitypub#key")),
|
|
206
|
+
"did:key:z6Mkabc",
|
|
207
|
+
);
|
|
208
|
+
deepStrictEqual(
|
|
209
|
+
getFe34Origin("did:key:z6Mkabc/path/to/resource?service=activitypub#key"),
|
|
210
|
+
"did:key:z6Mkabc",
|
|
211
|
+
);
|
|
212
|
+
deepStrictEqual(
|
|
213
|
+
getFe34Origin("did:KEY:z6Mkabc#z6Mkabc"),
|
|
214
|
+
"did:key:z6Mkabc",
|
|
215
|
+
);
|
|
216
|
+
deepStrictEqual(
|
|
217
|
+
getFe34Origin("ap://did%3Aweb%3Afoo%2Dbar.example/actor"),
|
|
218
|
+
"did:web:foo-bar.example",
|
|
219
|
+
);
|
|
220
|
+
deepStrictEqual(
|
|
221
|
+
getFe34Origin("did:web:foo%2dbar.example#key"),
|
|
222
|
+
"did:web:foo-bar.example",
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("getFe34Origin() rejects unsupported or malformed identifiers", () => {
|
|
227
|
+
for (
|
|
228
|
+
const iri of [
|
|
229
|
+
"mailto:alice@example.com",
|
|
230
|
+
"ap://not-a-did/actor",
|
|
231
|
+
"ap://did:key/actor",
|
|
232
|
+
"did:key",
|
|
233
|
+
"did:key:",
|
|
234
|
+
"did:",
|
|
235
|
+
]
|
|
236
|
+
) {
|
|
237
|
+
throws(() => getFe34Origin(iri), TypeError);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("haveSameFe34Origin() compares web and cryptographic origins", () => {
|
|
242
|
+
ok(haveSameFe34Origin(
|
|
243
|
+
"https://example.com/users/alice",
|
|
244
|
+
"https://example.com/notes/1",
|
|
245
|
+
));
|
|
246
|
+
ok(
|
|
247
|
+
!haveSameFe34Origin(
|
|
248
|
+
"https://example.com/users/alice",
|
|
249
|
+
"http://example.com/users/alice",
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
ok(
|
|
253
|
+
!haveSameFe34Origin(
|
|
254
|
+
"https://example.com/users/alice",
|
|
255
|
+
"https://example.com:8443/users/alice",
|
|
256
|
+
),
|
|
257
|
+
);
|
|
258
|
+
ok(haveSameFe34Origin(
|
|
259
|
+
"ap://did:key:z6Mkabc/actor",
|
|
260
|
+
"ap+ef61://did%3Akey%3Az6Mkabc/objects/1",
|
|
261
|
+
));
|
|
262
|
+
ok(haveSameFe34Origin(
|
|
263
|
+
"ap+ef61://did:key:z6Mkabc/actor",
|
|
264
|
+
"did:key:z6Mkabc#z6Mkabc",
|
|
265
|
+
));
|
|
266
|
+
ok(haveSameFe34Origin(
|
|
267
|
+
"ap://did:KEY:z6Mkabc/actor",
|
|
268
|
+
"did:key:z6Mkabc#z6Mkabc",
|
|
269
|
+
));
|
|
270
|
+
ok(haveSameFe34Origin(
|
|
271
|
+
"ap://did%3Aweb%3Afoo%2Dbar.example/actor",
|
|
272
|
+
"ap://did:web:foo-bar.example/note",
|
|
273
|
+
));
|
|
274
|
+
ok(haveSameFe34Origin(
|
|
275
|
+
"ap://did%3Aexample%3Aabc%252fdef/actor",
|
|
276
|
+
"did:example:abc%2Fdef#key",
|
|
277
|
+
));
|
|
278
|
+
ok(
|
|
279
|
+
!haveSameFe34Origin(
|
|
280
|
+
"ap+ef61://did:key:z6Mkabc/actor",
|
|
281
|
+
"did:key:z6Mkdef#z6Mkdef",
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
ok(
|
|
285
|
+
!haveSameFe34Origin(
|
|
286
|
+
"ap+ef61://did:key:z6Mkabc/actor",
|
|
287
|
+
"https://example.com/actor",
|
|
288
|
+
),
|
|
289
|
+
);
|
|
290
|
+
ok(!haveSameFe34Origin("ap://not-a-did/actor", "ap://not-a-did/actor"));
|
|
291
|
+
});
|
|
292
|
+
|
|
166
293
|
test("parseIri() normalizes portable URL instances", () => {
|
|
167
294
|
deepStrictEqual(
|
|
168
295
|
parseIri(new URL("ap+ef61://did%3Aexample%3Aabc%2Fdef/actor")),
|
package/src/url.ts
CHANGED
|
@@ -93,7 +93,7 @@ export function canonicalizePortableUri(input: string): string {
|
|
|
93
93
|
// decodePortableAuthority() reverses the shared percent-encoded authority
|
|
94
94
|
// path here rather than the raw did:-prefixed branch.
|
|
95
95
|
const authority = normalizePortableAuthority(
|
|
96
|
-
decodePortableAuthority(parsed.host)
|
|
96
|
+
getDidUrlOrigin(decodePortableAuthority(parsed.host)),
|
|
97
97
|
);
|
|
98
98
|
// Keep path and fragment text from the raw match to avoid URL dot-segment
|
|
99
99
|
// normalization, but still encode raw characters and normalize
|
|
@@ -131,6 +131,56 @@ export function arePortableUrisEqual(
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Computes an IRI's FEP-fe34 origin.
|
|
136
|
+
*
|
|
137
|
+
* HTTP(S) IRIs use their web origin. FEP-ef61 portable ActivityPub IRIs and
|
|
138
|
+
* DID URLs use their DID as a cryptographic origin.
|
|
139
|
+
*
|
|
140
|
+
* @throws {TypeError} If the IRI does not have a supported FEP-fe34 origin.
|
|
141
|
+
* @since 2.4.0
|
|
142
|
+
*/
|
|
143
|
+
export function getFe34Origin(input: string | URL): string {
|
|
144
|
+
if (input instanceof URL) {
|
|
145
|
+
const portable = normalizePortableUrl(input);
|
|
146
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
147
|
+
if (input.protocol === "did:") return getDidUrlOrigin(input.href);
|
|
148
|
+
if (input.protocol === "http:" || input.protocol === "https:") {
|
|
149
|
+
return input.origin;
|
|
150
|
+
}
|
|
151
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const portable = parsePortableIri(input);
|
|
155
|
+
if (portable != null) return getPortableCryptographicOrigin(portable);
|
|
156
|
+
if (DID_SCHEME_PATTERN.test(input)) return getDidUrlOrigin(input);
|
|
157
|
+
|
|
158
|
+
const parsed = new URL(input);
|
|
159
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
160
|
+
return parsed.origin;
|
|
161
|
+
}
|
|
162
|
+
throw new TypeError("Unsupported FEP-fe34 origin IRI.");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Checks whether two IRIs have the same FEP-fe34 origin.
|
|
167
|
+
*
|
|
168
|
+
* Malformed or unsupported IRIs are treated as non-matching.
|
|
169
|
+
*
|
|
170
|
+
* @since 2.4.0
|
|
171
|
+
*/
|
|
172
|
+
export function haveSameFe34Origin(
|
|
173
|
+
left: string | URL,
|
|
174
|
+
right: string | URL,
|
|
175
|
+
): boolean {
|
|
176
|
+
try {
|
|
177
|
+
return getFe34Origin(left) === getFe34Origin(right);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (error instanceof TypeError) return false;
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
134
184
|
/**
|
|
135
185
|
* Checks whether two IRIs have the same origin.
|
|
136
186
|
*/
|
|
@@ -144,7 +194,7 @@ function getComparableIriOrigin(iri: URL): string {
|
|
|
144
194
|
if (iri.host !== "") {
|
|
145
195
|
const host = iri.protocol === "ap+ef61:"
|
|
146
196
|
? encodeURIComponent(
|
|
147
|
-
decodePortableAuthority(iri.host)
|
|
197
|
+
getDidUrlOrigin(decodePortableAuthority(iri.host)),
|
|
148
198
|
)
|
|
149
199
|
: iri.host;
|
|
150
200
|
return `${iri.protocol}//${host}`;
|
|
@@ -152,6 +202,18 @@ function getComparableIriOrigin(iri: URL): string {
|
|
|
152
202
|
return iri.href;
|
|
153
203
|
}
|
|
154
204
|
|
|
205
|
+
function getPortableCryptographicOrigin(iri: URL): string {
|
|
206
|
+
return getDidUrlOrigin(decodePortableAuthority(iri.host));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getDidUrlOrigin(iri: string): string {
|
|
210
|
+
const did = iri.split(/[/?#]/, 1)[0].replace(DID_SCHEME_PATTERN, "did:");
|
|
211
|
+
if (!DID_PATTERN.test(did)) throw new TypeError("Invalid DID URL.");
|
|
212
|
+
const parts = did.split(":");
|
|
213
|
+
parts[1] = parts[1].toLowerCase();
|
|
214
|
+
return normalizePortableAuthority(parts.join(":"));
|
|
215
|
+
}
|
|
216
|
+
|
|
155
217
|
function parsePortableIri(iri: string): URL | null {
|
|
156
218
|
const match = iri.match(PORTABLE_IRI_PATTERN);
|
|
157
219
|
if (match == null) return null;
|
|
@@ -160,7 +222,7 @@ function parsePortableIri(iri: string): URL | null {
|
|
|
160
222
|
// current FEP-ef61 interoperability, but normalize it to a percent-encoded
|
|
161
223
|
// URL authority internally. The ap: URI syntax may change later; see:
|
|
162
224
|
// https://bnewbold.leaflet.pub/3mph4hzvbdc2v
|
|
163
|
-
const authority = decodePortableAuthority(match[2]);
|
|
225
|
+
const authority = getDidUrlOrigin(decodePortableAuthority(match[2]));
|
|
164
226
|
if (!DID_PATTERN.test(authority)) {
|
|
165
227
|
throw new TypeError("Invalid portable ActivityPub IRI authority.");
|
|
166
228
|
}
|