@fedify/fedify 1.9.0-dev.1668 → 1.9.0-dev.1704
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/dist/{actor-ChSW_rBk.js → actor-B0LpLKRw.js} +7263 -2440
- package/dist/{actor-Ch5yFYFG.d.ts → actor-C1Euqngb.d.ts} +1 -1
- package/dist/{actor-BHAPrCDB.js → actor-CQzdjHs3.js} +1 -1
- package/dist/{actor-fGD4yb1K.cjs → actor-DU96UQUE.cjs} +7263 -2440
- package/dist/{actor-CHOM_AN3.d.cts → actor-Ydzhc8dj.d.cts} +1 -1
- package/dist/{authdocloader-eSrbn3wM.cjs → authdocloader-BkOerKL-.cjs} +3 -3
- package/dist/{authdocloader-CgrKtaQg.js → authdocloader-CzmsYrAn.js} +3 -3
- package/dist/{authdocloader-ChsJ9FJN.js → authdocloader-DI67R2Ku.js} +3 -3
- package/dist/{builder-DI4-Kpdg.js → builder-D2Oyy8AY.js} +14 -8
- package/dist/{client-B8gJ1cw8.js → client-BWusKCWF.js} +1 -1
- package/dist/compat/mod.d.cts +7 -7
- package/dist/compat/mod.d.ts +7 -7
- package/dist/compat/transformers.test.js +16 -16
- package/dist/{context-DFruNLny.d.ts → context-C51zGhGC.d.ts} +185 -92
- package/dist/{context-KXVF2AhH.d.cts → context-Qnv814-p.d.cts} +185 -92
- package/dist/{docloader-CSB8cAnw.cjs → docloader-NcFUThCx.cjs} +1 -1
- package/dist/{docloader-Bqh-eFNP.js → docloader-isD0ntZv.js} +1 -1
- package/dist/{esm-DTi75ew2.js → esm-BBVcrjH8.js} +1 -1
- package/dist/federation/builder.test.js +5 -5
- package/dist/federation/collection.test.js +3 -3
- package/dist/federation/handler.test.js +17 -17
- package/dist/federation/idempotency.test.d.ts +3 -0
- package/dist/federation/idempotency.test.js +202 -0
- package/dist/federation/inbox.test.js +4 -4
- package/dist/federation/keycache.test.js +4 -4
- package/dist/federation/kv.test.js +3 -3
- package/dist/federation/middleware.test.js +18 -18
- package/dist/federation/mod.cjs +10 -10
- package/dist/federation/mod.d.cts +7 -7
- package/dist/federation/mod.d.ts +7 -7
- package/dist/federation/mod.js +10 -10
- package/dist/federation/mq.test.js +3 -3
- package/dist/federation/retry.test.js +3 -3
- package/dist/federation/router.test.js +3 -3
- package/dist/federation/send.test.js +10 -10
- package/dist/fixtures/media.example.com/avatars/test-avatar.jpg.json +6 -0
- package/dist/{http-B_zBcsai.d.cts → http-B1_DzfAU.d.cts} +1 -1
- package/dist/{http-BpAVdmaR.js → http-BiKoa3o_.js} +2 -2
- package/dist/{http-BDErrXSN.cjs → http-LVXxICJn.cjs} +3 -3
- package/dist/{http-DBHpjcjo.js → http-MyYS6o7t.js} +3 -3
- package/dist/{http-D8Q4xH0d.d.ts → http-wsGR6KkT.d.ts} +1 -1
- package/dist/{inbox-BA9sYsBf.js → inbox-CzGsgKH-.js} +29 -7
- package/dist/key-BEz2ThE9.cjs +10 -0
- package/dist/{key-DSOJOcRH.js → key-C0SCHEcf.js} +3 -3
- package/dist/{key-B27QtSbc.js → key-C5cRHj8g.js} +2 -2
- package/dist/{key-sCE-TgxY.js → key-CRhmBE03.js} +2 -2
- package/dist/{key-CYpTUnwf.cjs → key-Ci8OyUTB.cjs} +2 -2
- package/dist/{key-2rIHnPaA.js → key-DWPlWnFQ.js} +4 -4
- package/dist/{keycache-CiW2SvJu.js → keycache-rO8ea311.js} +1 -1
- package/dist/{keys-5cHW76LQ.js → keys-CWdCy_3n.js} +1 -1
- package/dist/{ld-upnKn3yw.js → ld-BWADNtQr.js} +2 -2
- package/dist/{lookup-B61sZAOY.js → lookup-BBTRFcU5.js} +1 -1
- package/dist/{lookup-BrrOs_g1.cjs → lookup-CILOZed9.cjs} +1 -1
- package/dist/{lookup-CZBG-vCx.js → lookup-RINL4MOa.js} +21 -12
- package/dist/{middleware-CyUVZG3t.js → middleware-Bcv0xCjs.js} +43 -40
- package/dist/middleware-Be9qUuwL.cjs +17 -0
- package/dist/{middleware-CfP7UhQy.js → middleware-BfhSHVoJ.js} +78 -47
- package/dist/middleware-CWlljVpG.js +26 -0
- package/dist/{middleware-P3jCWk4K.cjs → middleware-DDyUhxsm.cjs} +78 -47
- package/dist/middleware-Dm7sDAVJ.js +17 -0
- package/dist/{mod-NKH_G-IY.d.cts → mod-BUbqxBev.d.cts} +19 -1
- package/dist/{mod-Cy6pkZSn.d.ts → mod-CDObsV1d.d.ts} +19 -1
- package/dist/{mod-BAuhKa9d.d.ts → mod-CIbqfZW0.d.ts} +1 -1
- package/dist/{mod-YfAcrVbP.d.cts → mod-COTXAYRl.d.cts} +2 -2
- package/dist/{mod-B7Pc0I7F.d.ts → mod-DgcYoyZK.d.ts} +2 -2
- package/dist/{mod-C3CGxYoF.d.cts → mod-Dt-G9ZOS.d.cts} +1 -1
- package/dist/{mod-COw_caPC.d.cts → mod-fjqfsrty.d.cts} +2 -2
- package/dist/{mod-CiXjux2r.d.ts → mod-o-hx_hU8.d.ts} +2 -2
- package/dist/mod.cjs +10 -10
- package/dist/mod.d.cts +10 -10
- package/dist/mod.d.ts +10 -10
- package/dist/mod.js +10 -10
- package/dist/nodeinfo/client.test.js +5 -5
- package/dist/nodeinfo/handler.test.js +16 -16
- package/dist/nodeinfo/mod.cjs +2 -2
- package/dist/nodeinfo/mod.js +2 -2
- package/dist/nodeinfo/semver.test.js +3 -3
- package/dist/nodeinfo/types.test.js +3 -3
- package/dist/{owner-C9Ry0TOI.d.cts → owner-6KSEp9eV.d.cts} +2 -2
- package/dist/{owner-D38zBIMc.d.ts → owner-BbeUDvOu.d.ts} +2 -2
- package/dist/{owner-zvsMGYzc.js → owner-QEQV9vx-.js} +2 -2
- package/dist/{proof-Bt6yHsMN.js → proof-B_9fbF3f.js} +3 -3
- package/dist/{proof-BgKYSJ00.js → proof-g2_9VhUQ.js} +2 -2
- package/dist/{proof-CC_7UV_j.cjs → proof-v3B5cJ3c.cjs} +3 -3
- package/dist/runtime/authdocloader.test.js +9 -9
- package/dist/runtime/docloader.test.js +4 -4
- package/dist/runtime/key.test.js +5 -5
- package/dist/runtime/langstr.test.js +3 -3
- package/dist/runtime/link.test.js +3 -3
- package/dist/runtime/mod.cjs +6 -6
- package/dist/runtime/mod.d.cts +3 -3
- package/dist/runtime/mod.d.ts +3 -3
- package/dist/runtime/mod.js +6 -6
- package/dist/runtime/multibase/multibase.test.js +3 -3
- package/dist/runtime/url.test.js +3 -3
- package/dist/{send-DlqdAGHP.js → send-cTLNXtTp.js} +2 -2
- package/dist/sig/http.test.js +8 -8
- package/dist/sig/key.test.js +6 -6
- package/dist/sig/ld.test.js +7 -7
- package/dist/sig/mod.cjs +6 -6
- package/dist/sig/mod.d.cts +5 -5
- package/dist/sig/mod.d.ts +5 -5
- package/dist/sig/mod.js +6 -6
- package/dist/sig/owner.test.js +7 -7
- package/dist/sig/proof.test.js +7 -7
- package/dist/testing/docloader.test.js +3 -3
- package/dist/testing/mod.d.ts +391 -86
- package/dist/testing/mod.js +3 -3
- package/dist/{testing-CAAJTPCt.js → testing-CNtyBr2m.js} +2 -2
- package/dist/{type-BRNRL3aj.js → type-C5udJemk.js} +6943 -2120
- package/dist/{types-Dz0NMslg.cjs → types-C9w81XqW.cjs} +1 -1
- package/dist/{types-C8yjtF5A.js → types-DHq9gRM4.js} +1 -1
- package/dist/vocab/actor.test.js +5 -5
- package/dist/vocab/lookup.test.js +255 -5
- package/dist/vocab/mod.cjs +4 -4
- package/dist/vocab/mod.d.cts +3 -3
- package/dist/vocab/mod.d.ts +3 -3
- package/dist/vocab/mod.js +4 -4
- package/dist/vocab/type.test.js +3 -3
- package/dist/vocab/vocab.test.js +397 -8
- package/dist/{vocab-BDMmyzZA.cjs → vocab-BoyCE2Rn.cjs} +23 -14
- package/dist/{vocab-BEEm2I6u.d.ts → vocab-CDHNj5zp.d.ts} +290 -0
- package/dist/{vocab-BzGg7ltX.d.cts → vocab-Cfs0937i.d.cts} +290 -0
- package/dist/{vocab-WpDLcZH7.js → vocab-DxoBe7PI.js} +23 -14
- package/dist/webfinger/handler.test.js +16 -16
- package/dist/webfinger/lookup.test.js +4 -4
- package/dist/webfinger/mod.cjs +2 -2
- package/dist/webfinger/mod.js +2 -2
- package/dist/x/cfworkers.test.js +3 -3
- package/dist/x/hono.d.cts +6 -6
- package/dist/x/hono.d.ts +6 -6
- package/dist/x/sveltekit.d.cts +6 -6
- package/dist/x/sveltekit.d.ts +6 -6
- package/package.json +1 -1
- package/dist/key-Ck4-GNm0.cjs +0 -10
- package/dist/middleware-D8O6iKhr.js +0 -26
- package/dist/middleware-DI4sIaI4.js +0 -17
- package/dist/middleware-lw0MLhVG.cjs +0 -17
package/dist/vocab/vocab.test.js
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { Activity, Announce, Collection, Create, CryptographicKey, Follow, Hashtag, LanguageString, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, decode, vocab_exports } from "../type-
|
|
6
|
+
import { Activity, Announce, Collection, Create, CryptographicKey, Follow, Hashtag, LanguageString, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, decode, vocab_exports } from "../type-C5udJemk.js";
|
|
7
7
|
import { assertEquals } from "../assert_equals-DSbWqCm3.js";
|
|
8
8
|
import { assert } from "../assert-MZs1qjMx.js";
|
|
9
9
|
import { assertInstanceOf } from "../assert_instance_of-DHz7EHNU.js";
|
|
10
|
-
import "../lookup-
|
|
11
|
-
import { mockDocumentLoader, test } from "../testing-
|
|
10
|
+
import "../lookup-RINL4MOa.js";
|
|
11
|
+
import { mockDocumentLoader, test } from "../testing-CNtyBr2m.js";
|
|
12
12
|
import "../std__assert-X-_kMxKM.js";
|
|
13
13
|
import { assertFalse, assertRejects } from "../assert_rejects-DiIiJbZn.js";
|
|
14
14
|
import "../assert_is_error-BPGph1Jx.js";
|
|
15
15
|
import { assertNotEquals } from "../assert_not_equals-f3m3epl3.js";
|
|
16
16
|
import { assertThrows } from "../assert_throws-BOO88avQ.js";
|
|
17
|
-
import { ed25519PublicKey, rsaPublicKey1 } from "../keys-
|
|
17
|
+
import { ed25519PublicKey, rsaPublicKey1 } from "../keys-CWdCy_3n.js";
|
|
18
18
|
import { pascalCase } from "es-toolkit";
|
|
19
19
|
import { parseLanguageTag } from "@phensley/language-tag";
|
|
20
20
|
import { Validator } from "@cfworker/json-schema";
|
|
@@ -2203,9 +2203,9 @@ const scalarTypes = {
|
|
|
2203
2203
|
dataCheck(v) {
|
|
2204
2204
|
return `typeof ${v} === "object" && "@id" in ${v}
|
|
2205
2205
|
&& typeof ${v}["@id"] === "string"
|
|
2206
|
-
&& ${v}["@id"] !== ""
|
|
2206
|
+
&& ${v}["@id"] !== ""`;
|
|
2207
2207
|
},
|
|
2208
|
-
decoder(v) {
|
|
2208
|
+
decoder(v, baseUrlVar) {
|
|
2209
2209
|
return `${v}["@id"].startsWith("at://")
|
|
2210
2210
|
? new URL("at://" +
|
|
2211
2211
|
encodeURIComponent(
|
|
@@ -2219,7 +2219,9 @@ const scalarTypes = {
|
|
|
2219
2219
|
: ""
|
|
2220
2220
|
)
|
|
2221
2221
|
)
|
|
2222
|
-
:
|
|
2222
|
+
: URL.canParse(${v}["@id"]) && ${baseUrlVar}
|
|
2223
|
+
? new URL(${v}["@id"])
|
|
2224
|
+
: new URL(${v}["@id"], ${baseUrlVar})`;
|
|
2223
2225
|
}
|
|
2224
2226
|
},
|
|
2225
2227
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString": {
|
|
@@ -2833,6 +2835,7 @@ test({
|
|
|
2833
2835
|
test("Person.fromJsonLd()", async () => {
|
|
2834
2836
|
const person = await Person.fromJsonLd({
|
|
2835
2837
|
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
2838
|
+
"id": "https://todon.eu/users/hongminhee",
|
|
2836
2839
|
"publicKey": {
|
|
2837
2840
|
"id": "https://todon.eu/users/hongminhee#main-key",
|
|
2838
2841
|
"owner": "https://todon.eu/users/hongminhee",
|
|
@@ -2840,7 +2843,8 @@ test("Person.fromJsonLd()", async () => {
|
|
|
2840
2843
|
}
|
|
2841
2844
|
}, {
|
|
2842
2845
|
documentLoader: mockDocumentLoader,
|
|
2843
|
-
contextLoader: mockDocumentLoader
|
|
2846
|
+
contextLoader: mockDocumentLoader,
|
|
2847
|
+
baseUrl: new URL("https://todon.eu/")
|
|
2844
2848
|
});
|
|
2845
2849
|
assertEquals(person.publicKeyId, new URL("https://todon.eu/users/hongminhee#main-key"));
|
|
2846
2850
|
const publicKey = await person.getPublicKey({ documentLoader: mockDocumentLoader });
|
|
@@ -3059,6 +3063,391 @@ test("Link.fromJsonLd()", async () => {
|
|
|
3059
3063
|
});
|
|
3060
3064
|
assertEquals(link3.href, new URL("at://did%3Aplc%3Aia76kvnndjutgedggx2ibrem"));
|
|
3061
3065
|
});
|
|
3066
|
+
test("Person.fromJsonLd() with relative URLs", async () => {
|
|
3067
|
+
const json = {
|
|
3068
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
3069
|
+
id: "https://example.com/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c",
|
|
3070
|
+
type: "Person",
|
|
3071
|
+
name: "Test User",
|
|
3072
|
+
icon: {
|
|
3073
|
+
type: "Image",
|
|
3074
|
+
url: "/avatars/test-avatar.jpg"
|
|
3075
|
+
}
|
|
3076
|
+
};
|
|
3077
|
+
const person = await Person.fromJsonLd(json, {
|
|
3078
|
+
documentLoader: mockDocumentLoader,
|
|
3079
|
+
contextLoader: mockDocumentLoader
|
|
3080
|
+
});
|
|
3081
|
+
const icon = await person.getIcon();
|
|
3082
|
+
assertEquals(icon?.url, new URL("https://example.com/avatars/test-avatar.jpg"));
|
|
3083
|
+
const json2 = {
|
|
3084
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
3085
|
+
id: "https://example.com/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c",
|
|
3086
|
+
type: "Person",
|
|
3087
|
+
name: "Test User",
|
|
3088
|
+
icon: {
|
|
3089
|
+
id: "https://media.example.com/avatars/test-avatar.jpg",
|
|
3090
|
+
type: "Image",
|
|
3091
|
+
url: "/avatars/test-avatar.jpg"
|
|
3092
|
+
}
|
|
3093
|
+
};
|
|
3094
|
+
const person2 = await Person.fromJsonLd(json2, {
|
|
3095
|
+
documentLoader: mockDocumentLoader,
|
|
3096
|
+
contextLoader: mockDocumentLoader
|
|
3097
|
+
});
|
|
3098
|
+
const icon2 = await person2.getIcon();
|
|
3099
|
+
assertEquals(icon2?.url, new URL("https://media.example.com/avatars/test-avatar.jpg"));
|
|
3100
|
+
});
|
|
3101
|
+
test("Person.fromJsonLd() with relative URLs and baseUrl", async () => {
|
|
3102
|
+
const json = {
|
|
3103
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
3104
|
+
"id": "https://example.com/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c",
|
|
3105
|
+
"type": "Person",
|
|
3106
|
+
"name": "Test User",
|
|
3107
|
+
"icon": {
|
|
3108
|
+
"type": "Image",
|
|
3109
|
+
"url": "/avatars/test-avatar.jpg"
|
|
3110
|
+
}
|
|
3111
|
+
};
|
|
3112
|
+
const personWithBase = await Person.fromJsonLd(json, {
|
|
3113
|
+
documentLoader: mockDocumentLoader,
|
|
3114
|
+
contextLoader: mockDocumentLoader,
|
|
3115
|
+
baseUrl: new URL("https://example.com")
|
|
3116
|
+
});
|
|
3117
|
+
const icon = await personWithBase.getIcon();
|
|
3118
|
+
assertEquals(icon?.url, new URL("https://example.com/avatars/test-avatar.jpg"));
|
|
3119
|
+
});
|
|
3120
|
+
test("FEP-fe34: Trust tracking in object construction", async () => {
|
|
3121
|
+
const note = new Note({
|
|
3122
|
+
id: new URL("https://example.com/note"),
|
|
3123
|
+
content: "Hello World"
|
|
3124
|
+
});
|
|
3125
|
+
const create = new Create({
|
|
3126
|
+
id: new URL("https://example.com/create"),
|
|
3127
|
+
actor: new URL("https://example.com/actor"),
|
|
3128
|
+
object: note
|
|
3129
|
+
});
|
|
3130
|
+
assertEquals(create.objectId, new URL("https://example.com/note"));
|
|
3131
|
+
const result = await create.getObject();
|
|
3132
|
+
assertEquals(result, note);
|
|
3133
|
+
assertEquals(result?.content, "Hello World");
|
|
3134
|
+
});
|
|
3135
|
+
test("FEP-fe34: Trust tracking in object cloning", () => {
|
|
3136
|
+
const originalNote = new Note({
|
|
3137
|
+
id: new URL("https://example.com/note"),
|
|
3138
|
+
content: "Original content"
|
|
3139
|
+
});
|
|
3140
|
+
const create = new Create({
|
|
3141
|
+
id: new URL("https://example.com/create"),
|
|
3142
|
+
actor: new URL("https://example.com/actor"),
|
|
3143
|
+
object: originalNote
|
|
3144
|
+
});
|
|
3145
|
+
const newNote = new Note({
|
|
3146
|
+
id: new URL("https://example.com/new-note"),
|
|
3147
|
+
content: "New content"
|
|
3148
|
+
});
|
|
3149
|
+
const clonedCreate = create.clone({ object: newNote });
|
|
3150
|
+
assertEquals(clonedCreate.objectId, new URL("https://example.com/new-note"));
|
|
3151
|
+
});
|
|
3152
|
+
test("FEP-fe34: crossOrigin ignore behavior (default)", async () => {
|
|
3153
|
+
const crossOriginDocumentLoader = async (url) => {
|
|
3154
|
+
if (url === "https://different-origin.com/note") return {
|
|
3155
|
+
documentUrl: url,
|
|
3156
|
+
contextUrl: null,
|
|
3157
|
+
document: {
|
|
3158
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3159
|
+
"@type": "Note",
|
|
3160
|
+
"@id": "https://malicious.com/fake-note",
|
|
3161
|
+
"content": "This is a spoofed note"
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
throw new Error("Document not found");
|
|
3165
|
+
};
|
|
3166
|
+
const create = new Create({
|
|
3167
|
+
id: new URL("https://example.com/create"),
|
|
3168
|
+
actor: new URL("https://example.com/actor"),
|
|
3169
|
+
object: new URL("https://different-origin.com/note")
|
|
3170
|
+
});
|
|
3171
|
+
const result = await create.getObject({ documentLoader: crossOriginDocumentLoader });
|
|
3172
|
+
assertEquals(result, null);
|
|
3173
|
+
});
|
|
3174
|
+
test("FEP-fe34: crossOrigin throw behavior", async () => {
|
|
3175
|
+
const crossOriginDocumentLoader = async (url) => {
|
|
3176
|
+
if (url === "https://different-origin.com/note") return {
|
|
3177
|
+
documentUrl: url,
|
|
3178
|
+
contextUrl: null,
|
|
3179
|
+
document: {
|
|
3180
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3181
|
+
"@type": "Note",
|
|
3182
|
+
"@id": "https://malicious.com/fake-note",
|
|
3183
|
+
"content": "This is a spoofed note"
|
|
3184
|
+
}
|
|
3185
|
+
};
|
|
3186
|
+
throw new Error("Document not found");
|
|
3187
|
+
};
|
|
3188
|
+
const create = new Create({
|
|
3189
|
+
id: new URL("https://example.com/create"),
|
|
3190
|
+
actor: new URL("https://example.com/actor"),
|
|
3191
|
+
object: new URL("https://different-origin.com/note")
|
|
3192
|
+
});
|
|
3193
|
+
await assertRejects(() => create.getObject({
|
|
3194
|
+
documentLoader: crossOriginDocumentLoader,
|
|
3195
|
+
crossOrigin: "throw"
|
|
3196
|
+
}), Error, "The object's @id (https://malicious.com/fake-note) has a different origin than the document URL (https://different-origin.com/note)");
|
|
3197
|
+
});
|
|
3198
|
+
test("FEP-fe34: crossOrigin trust behavior", async () => {
|
|
3199
|
+
const crossOriginDocumentLoader = async (url) => {
|
|
3200
|
+
if (url === "https://different-origin.com/note") return {
|
|
3201
|
+
documentUrl: url,
|
|
3202
|
+
contextUrl: null,
|
|
3203
|
+
document: {
|
|
3204
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3205
|
+
"@type": "Note",
|
|
3206
|
+
"@id": "https://malicious.com/fake-note",
|
|
3207
|
+
"content": "This is a spoofed note"
|
|
3208
|
+
}
|
|
3209
|
+
};
|
|
3210
|
+
throw new Error("Document not found");
|
|
3211
|
+
};
|
|
3212
|
+
const create = new Create({
|
|
3213
|
+
id: new URL("https://example.com/create"),
|
|
3214
|
+
actor: new URL("https://example.com/actor"),
|
|
3215
|
+
object: new URL("https://different-origin.com/note")
|
|
3216
|
+
});
|
|
3217
|
+
const result = await create.getObject({
|
|
3218
|
+
documentLoader: crossOriginDocumentLoader,
|
|
3219
|
+
crossOrigin: "trust"
|
|
3220
|
+
});
|
|
3221
|
+
assertInstanceOf(result, Note);
|
|
3222
|
+
assertEquals(result?.id, new URL("https://malicious.com/fake-note"));
|
|
3223
|
+
assertEquals(result?.content, "This is a spoofed note");
|
|
3224
|
+
});
|
|
3225
|
+
test("FEP-fe34: Same origin objects are trusted", async () => {
|
|
3226
|
+
const sameOriginDocumentLoader = async (url) => {
|
|
3227
|
+
if (url === "https://example.com/note") return {
|
|
3228
|
+
documentUrl: url,
|
|
3229
|
+
contextUrl: null,
|
|
3230
|
+
document: {
|
|
3231
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3232
|
+
"@type": "Note",
|
|
3233
|
+
"@id": "https://example.com/note",
|
|
3234
|
+
"content": "This is a legitimate note"
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
throw new Error("Document not found");
|
|
3238
|
+
};
|
|
3239
|
+
const create = new Create({
|
|
3240
|
+
id: new URL("https://example.com/create"),
|
|
3241
|
+
actor: new URL("https://example.com/actor"),
|
|
3242
|
+
object: new URL("https://example.com/note")
|
|
3243
|
+
});
|
|
3244
|
+
const result = await create.getObject({ documentLoader: sameOriginDocumentLoader });
|
|
3245
|
+
assertInstanceOf(result, Note);
|
|
3246
|
+
assertEquals(result?.id, new URL("https://example.com/note"));
|
|
3247
|
+
assertEquals(result?.content, "This is a legitimate note");
|
|
3248
|
+
});
|
|
3249
|
+
test("FEP-fe34: Embedded cross-origin objects from JSON-LD are ignored by default", async () => {
|
|
3250
|
+
const createDocumentLoader = async (url) => {
|
|
3251
|
+
if (url === "https://example.com/create") return {
|
|
3252
|
+
documentUrl: url,
|
|
3253
|
+
contextUrl: null,
|
|
3254
|
+
document: {
|
|
3255
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3256
|
+
"@type": "Create",
|
|
3257
|
+
"@id": "https://example.com/create",
|
|
3258
|
+
"actor": "https://example.com/actor",
|
|
3259
|
+
"object": {
|
|
3260
|
+
"@type": "Note",
|
|
3261
|
+
"@id": "https://different-origin.com/note",
|
|
3262
|
+
"content": "Embedded note from JSON-LD"
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
throw new Error("Document not found");
|
|
3267
|
+
};
|
|
3268
|
+
const create = await Create.fromJsonLd(await createDocumentLoader("https://example.com/create").then((r) => r.document), { documentLoader: createDocumentLoader });
|
|
3269
|
+
const objectDocumentLoader = async (url) => {
|
|
3270
|
+
if (url === "https://different-origin.com/note") return {
|
|
3271
|
+
documentUrl: url,
|
|
3272
|
+
contextUrl: null,
|
|
3273
|
+
document: {
|
|
3274
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3275
|
+
"@type": "Note",
|
|
3276
|
+
"@id": "https://different-origin.com/note",
|
|
3277
|
+
"content": "Legitimate note from origin"
|
|
3278
|
+
}
|
|
3279
|
+
};
|
|
3280
|
+
throw new Error("Document not found");
|
|
3281
|
+
};
|
|
3282
|
+
const result = await create.getObject({ documentLoader: objectDocumentLoader });
|
|
3283
|
+
assertInstanceOf(result, Note);
|
|
3284
|
+
assertEquals(result?.content, "Legitimate note from origin");
|
|
3285
|
+
});
|
|
3286
|
+
test("FEP-fe34: Constructor vs JSON-LD parsing trust difference", async () => {
|
|
3287
|
+
const constructorCreate = new Create({
|
|
3288
|
+
id: new URL("https://example.com/create"),
|
|
3289
|
+
actor: new URL("https://example.com/actor"),
|
|
3290
|
+
object: new Note({
|
|
3291
|
+
id: new URL("https://different-origin.com/note"),
|
|
3292
|
+
content: "Constructor embedded note"
|
|
3293
|
+
})
|
|
3294
|
+
});
|
|
3295
|
+
const constructorResult = await constructorCreate.getObject();
|
|
3296
|
+
assertEquals(constructorResult?.content, "Constructor embedded note");
|
|
3297
|
+
const jsonLdCreate = await Create.fromJsonLd({
|
|
3298
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3299
|
+
"@type": "Create",
|
|
3300
|
+
"@id": "https://example.com/create",
|
|
3301
|
+
"actor": "https://example.com/actor",
|
|
3302
|
+
"object": {
|
|
3303
|
+
"@type": "Note",
|
|
3304
|
+
"@id": "https://different-origin.com/note",
|
|
3305
|
+
"content": "JSON-LD embedded note"
|
|
3306
|
+
}
|
|
3307
|
+
});
|
|
3308
|
+
const documentLoader = async (url) => {
|
|
3309
|
+
if (url === "https://different-origin.com/note") return {
|
|
3310
|
+
documentUrl: url,
|
|
3311
|
+
contextUrl: null,
|
|
3312
|
+
document: {
|
|
3313
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3314
|
+
"@type": "Note",
|
|
3315
|
+
"@id": "https://different-origin.com/note",
|
|
3316
|
+
"content": "Fetched from origin"
|
|
3317
|
+
}
|
|
3318
|
+
};
|
|
3319
|
+
throw new Error("Document not found");
|
|
3320
|
+
};
|
|
3321
|
+
const jsonLdResult = await jsonLdCreate.getObject({ documentLoader });
|
|
3322
|
+
assertEquals(jsonLdResult?.content, "Fetched from origin");
|
|
3323
|
+
});
|
|
3324
|
+
test("FEP-fe34: Array properties respect cross-origin policy", async () => {
|
|
3325
|
+
const crossOriginDocumentLoader = async (url) => {
|
|
3326
|
+
if (url === "https://different-origin.com/note1") return {
|
|
3327
|
+
documentUrl: url,
|
|
3328
|
+
contextUrl: null,
|
|
3329
|
+
document: {
|
|
3330
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3331
|
+
"@type": "Note",
|
|
3332
|
+
"@id": "https://malicious.com/fake-note1",
|
|
3333
|
+
"content": "Fake note 1"
|
|
3334
|
+
}
|
|
3335
|
+
};
|
|
3336
|
+
else if (url === "https://example.com/note2") return {
|
|
3337
|
+
documentUrl: url,
|
|
3338
|
+
contextUrl: null,
|
|
3339
|
+
document: {
|
|
3340
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3341
|
+
"@type": "Note",
|
|
3342
|
+
"@id": "https://example.com/note2",
|
|
3343
|
+
"content": "Legitimate note 2"
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
throw new Error("Document not found");
|
|
3347
|
+
};
|
|
3348
|
+
const collection = new Collection({
|
|
3349
|
+
id: new URL("https://example.com/collection"),
|
|
3350
|
+
items: [new URL("https://different-origin.com/note1"), new URL("https://example.com/note2")]
|
|
3351
|
+
});
|
|
3352
|
+
const items = [];
|
|
3353
|
+
for await (const item of collection.getItems({ documentLoader: crossOriginDocumentLoader })) items.push(item);
|
|
3354
|
+
assertEquals(items.length, 1);
|
|
3355
|
+
assertInstanceOf(items[0], Note);
|
|
3356
|
+
assertEquals(items[0].content, "Legitimate note 2");
|
|
3357
|
+
});
|
|
3358
|
+
test("FEP-fe34: Array properties with crossOrigin trust option", async () => {
|
|
3359
|
+
const crossOriginDocumentLoader = async (url) => {
|
|
3360
|
+
if (url === "https://different-origin.com/note1") return {
|
|
3361
|
+
documentUrl: url,
|
|
3362
|
+
contextUrl: null,
|
|
3363
|
+
document: {
|
|
3364
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3365
|
+
"@type": "Note",
|
|
3366
|
+
"@id": "https://malicious.com/fake-note1",
|
|
3367
|
+
"content": "Fake note 1"
|
|
3368
|
+
}
|
|
3369
|
+
};
|
|
3370
|
+
else if (url === "https://example.com/note2") return {
|
|
3371
|
+
documentUrl: url,
|
|
3372
|
+
contextUrl: null,
|
|
3373
|
+
document: {
|
|
3374
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3375
|
+
"@type": "Note",
|
|
3376
|
+
"@id": "https://example.com/note2",
|
|
3377
|
+
"content": "Legitimate note 2"
|
|
3378
|
+
}
|
|
3379
|
+
};
|
|
3380
|
+
throw new Error("Document not found");
|
|
3381
|
+
};
|
|
3382
|
+
const collection = new Collection({
|
|
3383
|
+
id: new URL("https://example.com/collection"),
|
|
3384
|
+
items: [new URL("https://different-origin.com/note1"), new URL("https://example.com/note2")]
|
|
3385
|
+
});
|
|
3386
|
+
const items = [];
|
|
3387
|
+
for await (const item of collection.getItems({
|
|
3388
|
+
documentLoader: crossOriginDocumentLoader,
|
|
3389
|
+
crossOrigin: "trust"
|
|
3390
|
+
})) items.push(item);
|
|
3391
|
+
assertEquals(items.length, 2);
|
|
3392
|
+
assertInstanceOf(items[0], Note);
|
|
3393
|
+
assertInstanceOf(items[1], Note);
|
|
3394
|
+
assertEquals(items[0].content, "Fake note 1");
|
|
3395
|
+
assertEquals(items[1].content, "Legitimate note 2");
|
|
3396
|
+
});
|
|
3397
|
+
test("FEP-fe34: Embedded objects in arrays from JSON-LD respect cross-origin policy", async () => {
|
|
3398
|
+
const collectionDocumentLoader = async (url) => {
|
|
3399
|
+
if (url === "https://example.com/collection") return {
|
|
3400
|
+
documentUrl: url,
|
|
3401
|
+
contextUrl: null,
|
|
3402
|
+
document: {
|
|
3403
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3404
|
+
"@type": "Collection",
|
|
3405
|
+
"@id": "https://example.com/collection",
|
|
3406
|
+
"items": [{
|
|
3407
|
+
"@type": "Note",
|
|
3408
|
+
"@id": "https://example.com/trusted-note",
|
|
3409
|
+
"content": "Trusted embedded note from JSON-LD"
|
|
3410
|
+
}, {
|
|
3411
|
+
"@type": "Note",
|
|
3412
|
+
"@id": "https://different-origin.com/untrusted-note",
|
|
3413
|
+
"content": "Untrusted embedded note from JSON-LD"
|
|
3414
|
+
}]
|
|
3415
|
+
}
|
|
3416
|
+
};
|
|
3417
|
+
throw new Error("Document not found");
|
|
3418
|
+
};
|
|
3419
|
+
const collection = await Collection.fromJsonLd(await collectionDocumentLoader("https://example.com/collection").then((r) => r.document), { documentLoader: collectionDocumentLoader });
|
|
3420
|
+
const itemDocumentLoader = async (url) => {
|
|
3421
|
+
if (url === "https://example.com/trusted-note") return {
|
|
3422
|
+
documentUrl: url,
|
|
3423
|
+
contextUrl: null,
|
|
3424
|
+
document: {
|
|
3425
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3426
|
+
"@type": "Note",
|
|
3427
|
+
"@id": "https://example.com/trusted-note",
|
|
3428
|
+
"content": "Trusted note from origin"
|
|
3429
|
+
}
|
|
3430
|
+
};
|
|
3431
|
+
else if (url === "https://different-origin.com/untrusted-note") return {
|
|
3432
|
+
documentUrl: url,
|
|
3433
|
+
contextUrl: null,
|
|
3434
|
+
document: {
|
|
3435
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3436
|
+
"@type": "Note",
|
|
3437
|
+
"@id": "https://different-origin.com/untrusted-note",
|
|
3438
|
+
"content": "Legitimate note from actual origin"
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3441
|
+
throw new Error("Document not found");
|
|
3442
|
+
};
|
|
3443
|
+
const items = [];
|
|
3444
|
+
for await (const item of collection.getItems({ documentLoader: itemDocumentLoader })) items.push(item);
|
|
3445
|
+
assertEquals(items.length, 2);
|
|
3446
|
+
assertInstanceOf(items[0], Note);
|
|
3447
|
+
assertEquals(items[0].content, "Trusted embedded note from JSON-LD");
|
|
3448
|
+
assertInstanceOf(items[1], Note);
|
|
3449
|
+
assertEquals(items[1].content, "Legitimate note from actual origin");
|
|
3450
|
+
});
|
|
3062
3451
|
function getAllProperties(type, types$1) {
|
|
3063
3452
|
const props = type.properties;
|
|
3064
3453
|
if (type.extends != null) props.push(...getAllProperties(types$1[type.extends], types$1));
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
4
4
|
|
|
5
5
|
const require_chunk = require('./chunk-DqRYRqnO.cjs');
|
|
6
|
-
const require_docloader = require('./docloader-
|
|
7
|
-
const require_actor = require('./actor-
|
|
8
|
-
const require_lookup = require('./lookup-
|
|
6
|
+
const require_docloader = require('./docloader-NcFUThCx.cjs');
|
|
7
|
+
const require_actor = require('./actor-DU96UQUE.cjs');
|
|
8
|
+
const require_lookup = require('./lookup-CILOZed9.cjs');
|
|
9
9
|
const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
|
|
10
10
|
const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
|
|
11
11
|
const es_toolkit = require_chunk.__toESM(require("es-toolkit"));
|
|
@@ -153,14 +153,13 @@ async function lookupObject(identifier, options = {}) {
|
|
|
153
153
|
async function lookupObjectInternal(identifier, options = {}) {
|
|
154
154
|
const documentLoader = options.documentLoader ?? require_docloader.getDocumentLoader({ userAgent: options.userAgent });
|
|
155
155
|
if (typeof identifier === "string") identifier = toAcctUrl(identifier) ?? new URL(identifier);
|
|
156
|
-
let
|
|
156
|
+
let remoteDoc = null;
|
|
157
157
|
if (identifier.protocol === "http:" || identifier.protocol === "https:") try {
|
|
158
|
-
|
|
159
|
-
document = remoteDoc.document;
|
|
158
|
+
remoteDoc = await documentLoader(identifier.href, { signal: options.signal });
|
|
160
159
|
} catch (error) {
|
|
161
160
|
logger.debug("Failed to fetch remote document:\n{error}", { error });
|
|
162
161
|
}
|
|
163
|
-
if (
|
|
162
|
+
if (remoteDoc == null) {
|
|
164
163
|
const jrd = await require_lookup.lookupWebFinger(identifier, {
|
|
165
164
|
userAgent: options.userAgent,
|
|
166
165
|
tracerProvider: options.tracerProvider,
|
|
@@ -171,8 +170,7 @@ async function lookupObjectInternal(identifier, options = {}) {
|
|
|
171
170
|
for (const l of jrd.links) {
|
|
172
171
|
if (l.type !== "application/activity+json" && !l.type?.match(/application\/ld\+json;\s*profile="https:\/\/www.w3.org\/ns\/activitystreams"/) || l.rel !== "self" || l.href == null) continue;
|
|
173
172
|
try {
|
|
174
|
-
|
|
175
|
-
document = remoteDoc.document;
|
|
173
|
+
remoteDoc = await documentLoader(l.href, { signal: options.signal });
|
|
176
174
|
break;
|
|
177
175
|
} catch (error) {
|
|
178
176
|
logger.debug("Failed to fetch remote document:\n{error}", { error });
|
|
@@ -180,23 +178,34 @@ async function lookupObjectInternal(identifier, options = {}) {
|
|
|
180
178
|
}
|
|
181
179
|
}
|
|
182
180
|
}
|
|
183
|
-
if (
|
|
181
|
+
if (remoteDoc == null) return null;
|
|
182
|
+
let object;
|
|
184
183
|
try {
|
|
185
|
-
|
|
184
|
+
object = await require_actor.Object.fromJsonLd(remoteDoc.document, {
|
|
186
185
|
documentLoader,
|
|
187
186
|
contextLoader: options.contextLoader,
|
|
188
|
-
tracerProvider: options.tracerProvider
|
|
187
|
+
tracerProvider: options.tracerProvider,
|
|
188
|
+
baseUrl: new URL(remoteDoc.documentUrl)
|
|
189
189
|
});
|
|
190
190
|
} catch (error) {
|
|
191
191
|
if (error instanceof TypeError) {
|
|
192
192
|
logger.debug("Failed to parse JSON-LD document: {error}\n{document}", {
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
...remoteDoc,
|
|
194
|
+
error
|
|
195
195
|
});
|
|
196
196
|
return null;
|
|
197
197
|
}
|
|
198
198
|
throw error;
|
|
199
199
|
}
|
|
200
|
+
if (options.crossOrigin !== "trust" && object.id != null && object.id.origin !== new URL(remoteDoc.documentUrl).origin) {
|
|
201
|
+
if (options.crossOrigin === "throw") throw new Error(`The object's @id (${object.id.href}) has a different origin than the document URL (${remoteDoc.documentUrl}); refusing to return the object. If you want to bypass this check and are aware of the security implications, set the crossOrigin option to "trust".`);
|
|
202
|
+
logger.warn("The object's @id ({objectId}) has a different origin than the document URL ({documentUrl}); refusing to return the object. If you want to bypass this check and are aware of the security implications, set the crossOrigin option to \"trust\".", {
|
|
203
|
+
...remoteDoc,
|
|
204
|
+
objectId: object.id.href
|
|
205
|
+
});
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return object;
|
|
200
209
|
}
|
|
201
210
|
/**
|
|
202
211
|
* Traverses a collection, yielding each item in the collection.
|