Loading CHANGES.md +16 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,22 @@ Version 0.11.0 To be released. - Frequently used JSON-LD contexts are now preloaded. [[74]] - The `fetchDocumentLoader()` function now preloads the following JSON-LD contexts: - <https://www.w3.org/ns/activitystreams> - <https://w3id.org/security/v1> - <https://w3id.org/security/data-integrity/v1> - <https://www.w3.org/ns/did/v1> - <https://w3id.org/security/multikey/v1> - The default `rules` for `kvCache()` function are now 5 minutes for all URLs. [#74]: https://github.com/dahlia/fedify/issues/74 Version 0.10.0 -------------- Loading runtime/contexts.ts 0 → 100644 +635 −0 Original line number Diff line number Diff line // Preloaded context documents // https://github.com/dahlia/fedify/issues/74 // cSpell: disable const preloadedContexts: Record<string, unknown> = { "https://www.w3.org/ns/activitystreams": { "@context": { "@vocab": "_:", "xsd": "http://www.w3.org/2001/XMLSchema#", "as": "https://www.w3.org/ns/activitystreams#", "ldp": "http://www.w3.org/ns/ldp#", "vcard": "http://www.w3.org/2006/vcard/ns#", "id": "@id", "type": "@type", "Accept": "as:Accept", "Activity": "as:Activity", "IntransitiveActivity": "as:IntransitiveActivity", "Add": "as:Add", "Announce": "as:Announce", "Application": "as:Application", "Arrive": "as:Arrive", "Article": "as:Article", "Audio": "as:Audio", "Block": "as:Block", "Collection": "as:Collection", "CollectionPage": "as:CollectionPage", "Relationship": "as:Relationship", "Create": "as:Create", "Delete": "as:Delete", "Dislike": "as:Dislike", "Document": "as:Document", "Event": "as:Event", "Follow": "as:Follow", "Flag": "as:Flag", "Group": "as:Group", "Ignore": "as:Ignore", "Image": "as:Image", "Invite": "as:Invite", "Join": "as:Join", "Leave": "as:Leave", "Like": "as:Like", "Link": "as:Link", "Mention": "as:Mention", "Note": "as:Note", "Object": "as:Object", "Offer": "as:Offer", "OrderedCollection": "as:OrderedCollection", "OrderedCollectionPage": "as:OrderedCollectionPage", "Organization": "as:Organization", "Page": "as:Page", "Person": "as:Person", "Place": "as:Place", "Profile": "as:Profile", "Question": "as:Question", "Reject": "as:Reject", "Remove": "as:Remove", "Service": "as:Service", "TentativeAccept": "as:TentativeAccept", "TentativeReject": "as:TentativeReject", "Tombstone": "as:Tombstone", "Undo": "as:Undo", "Update": "as:Update", "Video": "as:Video", "View": "as:View", "Listen": "as:Listen", "Read": "as:Read", "Move": "as:Move", "Travel": "as:Travel", "IsFollowing": "as:IsFollowing", "IsFollowedBy": "as:IsFollowedBy", "IsContact": "as:IsContact", "IsMember": "as:IsMember", "subject": { "@id": "as:subject", "@type": "@id", }, "relationship": { "@id": "as:relationship", "@type": "@id", }, "actor": { "@id": "as:actor", "@type": "@id", }, "attributedTo": { "@id": "as:attributedTo", "@type": "@id", }, "attachment": { "@id": "as:attachment", "@type": "@id", }, "bcc": { "@id": "as:bcc", "@type": "@id", }, "bto": { "@id": "as:bto", "@type": "@id", }, "cc": { "@id": "as:cc", "@type": "@id", }, "context": { "@id": "as:context", "@type": "@id", }, "current": { "@id": "as:current", "@type": "@id", }, "first": { "@id": "as:first", "@type": "@id", }, "generator": { "@id": "as:generator", "@type": "@id", }, "icon": { "@id": "as:icon", "@type": "@id", }, "image": { "@id": "as:image", "@type": "@id", }, "inReplyTo": { "@id": "as:inReplyTo", "@type": "@id", }, "items": { "@id": "as:items", "@type": "@id", }, "instrument": { "@id": "as:instrument", "@type": "@id", }, "orderedItems": { "@id": "as:items", "@type": "@id", "@container": "@list", }, "last": { "@id": "as:last", "@type": "@id", }, "location": { "@id": "as:location", "@type": "@id", }, "next": { "@id": "as:next", "@type": "@id", }, "object": { "@id": "as:object", "@type": "@id", }, "oneOf": { "@id": "as:oneOf", "@type": "@id", }, "anyOf": { "@id": "as:anyOf", "@type": "@id", }, "closed": { "@id": "as:closed", "@type": "xsd:dateTime", }, "origin": { "@id": "as:origin", "@type": "@id", }, "accuracy": { "@id": "as:accuracy", "@type": "xsd:float", }, "prev": { "@id": "as:prev", "@type": "@id", }, "preview": { "@id": "as:preview", "@type": "@id", }, "replies": { "@id": "as:replies", "@type": "@id", }, "result": { "@id": "as:result", "@type": "@id", }, "audience": { "@id": "as:audience", "@type": "@id", }, "partOf": { "@id": "as:partOf", "@type": "@id", }, "tag": { "@id": "as:tag", "@type": "@id", }, "target": { "@id": "as:target", "@type": "@id", }, "to": { "@id": "as:to", "@type": "@id", }, "url": { "@id": "as:url", "@type": "@id", }, "altitude": { "@id": "as:altitude", "@type": "xsd:float", }, "content": "as:content", "contentMap": { "@id": "as:content", "@container": "@language", }, "name": "as:name", "nameMap": { "@id": "as:name", "@container": "@language", }, "duration": { "@id": "as:duration", "@type": "xsd:duration", }, "endTime": { "@id": "as:endTime", "@type": "xsd:dateTime", }, "height": { "@id": "as:height", "@type": "xsd:nonNegativeInteger", }, "href": { "@id": "as:href", "@type": "@id", }, "hreflang": "as:hreflang", "latitude": { "@id": "as:latitude", "@type": "xsd:float", }, "longitude": { "@id": "as:longitude", "@type": "xsd:float", }, "mediaType": "as:mediaType", "published": { "@id": "as:published", "@type": "xsd:dateTime", }, "radius": { "@id": "as:radius", "@type": "xsd:float", }, "rel": "as:rel", "startIndex": { "@id": "as:startIndex", "@type": "xsd:nonNegativeInteger", }, "startTime": { "@id": "as:startTime", "@type": "xsd:dateTime", }, "summary": "as:summary", "summaryMap": { "@id": "as:summary", "@container": "@language", }, "totalItems": { "@id": "as:totalItems", "@type": "xsd:nonNegativeInteger", }, "units": "as:units", "updated": { "@id": "as:updated", "@type": "xsd:dateTime", }, "width": { "@id": "as:width", "@type": "xsd:nonNegativeInteger", }, "describes": { "@id": "as:describes", "@type": "@id", }, "formerType": { "@id": "as:formerType", "@type": "@id", }, "deleted": { "@id": "as:deleted", "@type": "xsd:dateTime", }, "inbox": { "@id": "ldp:inbox", "@type": "@id", }, "outbox": { "@id": "as:outbox", "@type": "@id", }, "following": { "@id": "as:following", "@type": "@id", }, "followers": { "@id": "as:followers", "@type": "@id", }, "streams": { "@id": "as:streams", "@type": "@id", }, "preferredUsername": "as:preferredUsername", "endpoints": { "@id": "as:endpoints", "@type": "@id", }, "uploadMedia": { "@id": "as:uploadMedia", "@type": "@id", }, "proxyUrl": { "@id": "as:proxyUrl", "@type": "@id", }, "liked": { "@id": "as:liked", "@type": "@id", }, "oauthAuthorizationEndpoint": { "@id": "as:oauthAuthorizationEndpoint", "@type": "@id", }, "oauthTokenEndpoint": { "@id": "as:oauthTokenEndpoint", "@type": "@id", }, "provideClientKey": { "@id": "as:provideClientKey", "@type": "@id", }, "signClientKey": { "@id": "as:signClientKey", "@type": "@id", }, "sharedInbox": { "@id": "as:sharedInbox", "@type": "@id", }, "Public": { "@id": "as:Public", "@type": "@id", }, "source": "as:source", "likes": { "@id": "as:likes", "@type": "@id", }, "shares": { "@id": "as:shares", "@type": "@id", }, "alsoKnownAs": { "@id": "as:alsoKnownAs", "@type": "@id", }, }, }, "https://w3id.org/security/v1": { "@context": { "id": "@id", "type": "@type", "dc": "http://purl.org/dc/terms/", "sec": "https://w3id.org/security#", "xsd": "http://www.w3.org/2001/XMLSchema#", "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016", "Ed25519Signature2018": "sec:Ed25519Signature2018", "EncryptedMessage": "sec:EncryptedMessage", "GraphSignature2012": "sec:GraphSignature2012", "LinkedDataSignature2015": "sec:LinkedDataSignature2015", "LinkedDataSignature2016": "sec:LinkedDataSignature2016", "CryptographicKey": "sec:Key", "authenticationTag": "sec:authenticationTag", "canonicalizationAlgorithm": "sec:canonicalizationAlgorithm", "cipherAlgorithm": "sec:cipherAlgorithm", "cipherData": "sec:cipherData", "cipherKey": "sec:cipherKey", "created": { "@id": "dc:created", "@type": "xsd:dateTime", }, "creator": { "@id": "dc:creator", "@type": "@id", }, "digestAlgorithm": "sec:digestAlgorithm", "digestValue": "sec:digestValue", "domain": "sec:domain", "encryptionKey": "sec:encryptionKey", "expiration": { "@id": "sec:expiration", "@type": "xsd:dateTime", }, "expires": { "@id": "sec:expiration", "@type": "xsd:dateTime", }, "initializationVector": "sec:initializationVector", "iterationCount": "sec:iterationCount", "nonce": "sec:nonce", "normalizationAlgorithm": "sec:normalizationAlgorithm", "owner": { "@id": "sec:owner", "@type": "@id", }, "password": "sec:password", "privateKey": { "@id": "sec:privateKey", "@type": "@id", }, "privateKeyPem": "sec:privateKeyPem", "publicKey": { "@id": "sec:publicKey", "@type": "@id", }, "publicKeyBase58": "sec:publicKeyBase58", "publicKeyPem": "sec:publicKeyPem", "publicKeyWif": "sec:publicKeyWif", "publicKeyService": { "@id": "sec:publicKeyService", "@type": "@id", }, "revoked": { "@id": "sec:revoked", "@type": "xsd:dateTime", }, "salt": "sec:salt", "signature": "sec:signature", "signatureAlgorithm": "sec:signingAlgorithm", "signatureValue": "sec:signatureValue", }, }, "https://w3id.org/security/data-integrity/v1": { "@context": { "id": "@id", "type": "@type", "@protected": true, "digestMultibase": { "@id": "https://w3id.org/security#digestMultibase", "@type": "https://w3id.org/security#multibase", }, "proof": { "@id": "https://w3id.org/security#proof", "@type": "@id", "@container": "@graph", }, "DataIntegrityProof": { "@id": "https://w3id.org/security#DataIntegrityProof", "@context": { "@protected": true, "id": "@id", "type": "@type", "challenge": "https://w3id.org/security#challenge", "created": { "@id": "http://purl.org/dc/terms/created", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "domain": "https://w3id.org/security#domain", "expires": { "@id": "https://w3id.org/security#expiration", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "nonce": "https://w3id.org/security#nonce", "proofPurpose": { "@id": "https://w3id.org/security#proofPurpose", "@type": "@vocab", "@context": { "@protected": true, "id": "@id", "type": "@type", "assertionMethod": { "@id": "https://w3id.org/security#assertionMethod", "@type": "@id", "@container": "@set", }, "authentication": { "@id": "https://w3id.org/security#authenticationMethod", "@type": "@id", "@container": "@set", }, "capabilityInvocation": { "@id": "https://w3id.org/security#capabilityInvocationMethod", "@type": "@id", "@container": "@set", }, "capabilityDelegation": { "@id": "https://w3id.org/security#capabilityDelegationMethod", "@type": "@id", "@container": "@set", }, "keyAgreement": { "@id": "https://w3id.org/security#keyAgreementMethod", "@type": "@id", "@container": "@set", }, }, }, "cryptosuite": "https://w3id.org/security#cryptosuite", "proofValue": { "@id": "https://w3id.org/security#proofValue", "@type": "https://w3id.org/security#multibase", }, "verificationMethod": { "@id": "https://w3id.org/security#verificationMethod", "@type": "@id", }, }, }, }, }, "https://www.w3.org/ns/did/v1": { "@context": { "@protected": true, "id": "@id", "type": "@type", "alsoKnownAs": { "@id": "https://www.w3.org/ns/activitystreams#alsoKnownAs", "@type": "@id", }, "assertionMethod": { "@id": "https://w3id.org/security#assertionMethod", "@type": "@id", "@container": "@set", }, "authentication": { "@id": "https://w3id.org/security#authenticationMethod", "@type": "@id", "@container": "@set", }, "capabilityDelegation": { "@id": "https://w3id.org/security#capabilityDelegationMethod", "@type": "@id", "@container": "@set", }, "capabilityInvocation": { "@id": "https://w3id.org/security#capabilityInvocationMethod", "@type": "@id", "@container": "@set", }, "controller": { "@id": "https://w3id.org/security#controller", "@type": "@id", }, "keyAgreement": { "@id": "https://w3id.org/security#keyAgreementMethod", "@type": "@id", "@container": "@set", }, "service": { "@id": "https://www.w3.org/ns/did#service", "@type": "@id", "@context": { "@protected": true, "id": "@id", "type": "@type", "serviceEndpoint": { "@id": "https://www.w3.org/ns/did#serviceEndpoint", "@type": "@id", }, }, }, "verificationMethod": { "@id": "https://w3id.org/security#verificationMethod", "@type": "@id", }, }, }, "https://w3id.org/security/multikey/v1": { "@context": { "id": "@id", "type": "@type", "@protected": true, "Multikey": { "@id": "https://w3id.org/security#Multikey", "@context": { "@protected": true, "id": "@id", "type": "@type", "controller": { "@id": "https://w3id.org/security#controller", "@type": "@id", }, "revoked": { "@id": "https://w3id.org/security#revoked", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "expires": { "@id": "https://w3id.org/security#expiration", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "publicKeyMultibase": { "@id": "https://w3id.org/security#publicKeyMultibase", "@type": "https://w3id.org/security#multibase", }, "secretKeyMultibase": { "@id": "https://w3id.org/security#secretKeyMultibase", "@type": "https://w3id.org/security#multibase", }, }, }, }, }, }; export default preloadedContexts; runtime/docloader.test.ts +11 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import { verifyRequest } from "../sig/http.ts"; import { mockDocumentLoader } from "../testing/docloader.ts"; import { rsaPrivateKey2 } from "../testing/keys.ts"; import { test } from "../testing/mod.ts"; import preloadedContexts from "./contexts.ts"; import { fetchDocumentLoader, FetchError, Loading Loading @@ -61,6 +62,16 @@ test("fetchDocumentLoader()", async (t) => { }); mf.uninstall(); await t.step("preloaded contexts", async () => { for (const [url, document] of Object.entries(preloadedContexts)) { assertEquals(await fetchDocumentLoader(url), { contextUrl: null, documentUrl: url, document, }); } }); }); test("getAuthenticatedDocumentLoader()", async (t) => { Loading runtime/docloader.ts +18 −10 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import { getLogger } from "@logtape/logtape"; import type { KvKey, KvStore } from "../federation/kv.ts"; import { signRequest } from "../sig/http.ts"; import { validateCryptoKey } from "../sig/key.ts"; import preloadedContexts from "./contexts.ts"; const logger = getLogger(["fedify", "runtime", "docloader"]); Loading Loading @@ -113,12 +114,28 @@ async function getRemoteDocument( /** * A JSON-LD document loader that utilizes the browser's `fetch` API. * * This loader preloads the below frequently used contexts: * * - <https://www.w3.org/ns/activitystreams> * - <https://w3id.org/security/v1> * - <https://w3id.org/security/data-integrity/v1> * - <https://www.w3.org/ns/did/v1> * - <https://w3id.org/security/multikey/v1> * @param url The URL of the document to load. * @returns The remote document. */ export async function fetchDocumentLoader( url: string, ): Promise<RemoteDocument> { if (url in preloadedContexts) { logger.debug("Using preloaded context: {url}.", { url }); return { contextUrl: null, document: preloadedContexts[url], documentUrl: url, }; } const request = createRequest(url); logRequest(request); const response = await fetch(request, { Loading Loading @@ -199,11 +216,7 @@ export interface KvCacheParameters { * a {@link URLPattern} and `duration` is a {@link Temporal.Duration}. * The `duration` is allowed to be at most 30 days. * * The default rules are: * * - `https://www.w3.org/ns/activitystreams` for 30 days * - `https://w3id.org/security/v1` for 30 days * - Everything else for 5 minutes * By default, 5 minutes for all URLs. */ rules?: [string | URL | URLPattern, Temporal.Duration][]; } Loading @@ -218,11 +231,6 @@ export function kvCache( ): DocumentLoader { const keyPrefix = prefix ?? ["_fedify", "remoteDocument"]; rules ??= [ [ "https://www.w3.org/ns/activitystreams", Temporal.Duration.from({ days: 30 }), ], ["https://w3id.org/security/v1", Temporal.Duration.from({ days: 30 })], [new URLPattern({}), Temporal.Duration.from({ minutes: 5 })], ]; for (const [p, duration] of rules) { Loading Loading
CHANGES.md +16 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,22 @@ Version 0.11.0 To be released. - Frequently used JSON-LD contexts are now preloaded. [[74]] - The `fetchDocumentLoader()` function now preloads the following JSON-LD contexts: - <https://www.w3.org/ns/activitystreams> - <https://w3id.org/security/v1> - <https://w3id.org/security/data-integrity/v1> - <https://www.w3.org/ns/did/v1> - <https://w3id.org/security/multikey/v1> - The default `rules` for `kvCache()` function are now 5 minutes for all URLs. [#74]: https://github.com/dahlia/fedify/issues/74 Version 0.10.0 -------------- Loading
runtime/contexts.ts 0 → 100644 +635 −0 Original line number Diff line number Diff line // Preloaded context documents // https://github.com/dahlia/fedify/issues/74 // cSpell: disable const preloadedContexts: Record<string, unknown> = { "https://www.w3.org/ns/activitystreams": { "@context": { "@vocab": "_:", "xsd": "http://www.w3.org/2001/XMLSchema#", "as": "https://www.w3.org/ns/activitystreams#", "ldp": "http://www.w3.org/ns/ldp#", "vcard": "http://www.w3.org/2006/vcard/ns#", "id": "@id", "type": "@type", "Accept": "as:Accept", "Activity": "as:Activity", "IntransitiveActivity": "as:IntransitiveActivity", "Add": "as:Add", "Announce": "as:Announce", "Application": "as:Application", "Arrive": "as:Arrive", "Article": "as:Article", "Audio": "as:Audio", "Block": "as:Block", "Collection": "as:Collection", "CollectionPage": "as:CollectionPage", "Relationship": "as:Relationship", "Create": "as:Create", "Delete": "as:Delete", "Dislike": "as:Dislike", "Document": "as:Document", "Event": "as:Event", "Follow": "as:Follow", "Flag": "as:Flag", "Group": "as:Group", "Ignore": "as:Ignore", "Image": "as:Image", "Invite": "as:Invite", "Join": "as:Join", "Leave": "as:Leave", "Like": "as:Like", "Link": "as:Link", "Mention": "as:Mention", "Note": "as:Note", "Object": "as:Object", "Offer": "as:Offer", "OrderedCollection": "as:OrderedCollection", "OrderedCollectionPage": "as:OrderedCollectionPage", "Organization": "as:Organization", "Page": "as:Page", "Person": "as:Person", "Place": "as:Place", "Profile": "as:Profile", "Question": "as:Question", "Reject": "as:Reject", "Remove": "as:Remove", "Service": "as:Service", "TentativeAccept": "as:TentativeAccept", "TentativeReject": "as:TentativeReject", "Tombstone": "as:Tombstone", "Undo": "as:Undo", "Update": "as:Update", "Video": "as:Video", "View": "as:View", "Listen": "as:Listen", "Read": "as:Read", "Move": "as:Move", "Travel": "as:Travel", "IsFollowing": "as:IsFollowing", "IsFollowedBy": "as:IsFollowedBy", "IsContact": "as:IsContact", "IsMember": "as:IsMember", "subject": { "@id": "as:subject", "@type": "@id", }, "relationship": { "@id": "as:relationship", "@type": "@id", }, "actor": { "@id": "as:actor", "@type": "@id", }, "attributedTo": { "@id": "as:attributedTo", "@type": "@id", }, "attachment": { "@id": "as:attachment", "@type": "@id", }, "bcc": { "@id": "as:bcc", "@type": "@id", }, "bto": { "@id": "as:bto", "@type": "@id", }, "cc": { "@id": "as:cc", "@type": "@id", }, "context": { "@id": "as:context", "@type": "@id", }, "current": { "@id": "as:current", "@type": "@id", }, "first": { "@id": "as:first", "@type": "@id", }, "generator": { "@id": "as:generator", "@type": "@id", }, "icon": { "@id": "as:icon", "@type": "@id", }, "image": { "@id": "as:image", "@type": "@id", }, "inReplyTo": { "@id": "as:inReplyTo", "@type": "@id", }, "items": { "@id": "as:items", "@type": "@id", }, "instrument": { "@id": "as:instrument", "@type": "@id", }, "orderedItems": { "@id": "as:items", "@type": "@id", "@container": "@list", }, "last": { "@id": "as:last", "@type": "@id", }, "location": { "@id": "as:location", "@type": "@id", }, "next": { "@id": "as:next", "@type": "@id", }, "object": { "@id": "as:object", "@type": "@id", }, "oneOf": { "@id": "as:oneOf", "@type": "@id", }, "anyOf": { "@id": "as:anyOf", "@type": "@id", }, "closed": { "@id": "as:closed", "@type": "xsd:dateTime", }, "origin": { "@id": "as:origin", "@type": "@id", }, "accuracy": { "@id": "as:accuracy", "@type": "xsd:float", }, "prev": { "@id": "as:prev", "@type": "@id", }, "preview": { "@id": "as:preview", "@type": "@id", }, "replies": { "@id": "as:replies", "@type": "@id", }, "result": { "@id": "as:result", "@type": "@id", }, "audience": { "@id": "as:audience", "@type": "@id", }, "partOf": { "@id": "as:partOf", "@type": "@id", }, "tag": { "@id": "as:tag", "@type": "@id", }, "target": { "@id": "as:target", "@type": "@id", }, "to": { "@id": "as:to", "@type": "@id", }, "url": { "@id": "as:url", "@type": "@id", }, "altitude": { "@id": "as:altitude", "@type": "xsd:float", }, "content": "as:content", "contentMap": { "@id": "as:content", "@container": "@language", }, "name": "as:name", "nameMap": { "@id": "as:name", "@container": "@language", }, "duration": { "@id": "as:duration", "@type": "xsd:duration", }, "endTime": { "@id": "as:endTime", "@type": "xsd:dateTime", }, "height": { "@id": "as:height", "@type": "xsd:nonNegativeInteger", }, "href": { "@id": "as:href", "@type": "@id", }, "hreflang": "as:hreflang", "latitude": { "@id": "as:latitude", "@type": "xsd:float", }, "longitude": { "@id": "as:longitude", "@type": "xsd:float", }, "mediaType": "as:mediaType", "published": { "@id": "as:published", "@type": "xsd:dateTime", }, "radius": { "@id": "as:radius", "@type": "xsd:float", }, "rel": "as:rel", "startIndex": { "@id": "as:startIndex", "@type": "xsd:nonNegativeInteger", }, "startTime": { "@id": "as:startTime", "@type": "xsd:dateTime", }, "summary": "as:summary", "summaryMap": { "@id": "as:summary", "@container": "@language", }, "totalItems": { "@id": "as:totalItems", "@type": "xsd:nonNegativeInteger", }, "units": "as:units", "updated": { "@id": "as:updated", "@type": "xsd:dateTime", }, "width": { "@id": "as:width", "@type": "xsd:nonNegativeInteger", }, "describes": { "@id": "as:describes", "@type": "@id", }, "formerType": { "@id": "as:formerType", "@type": "@id", }, "deleted": { "@id": "as:deleted", "@type": "xsd:dateTime", }, "inbox": { "@id": "ldp:inbox", "@type": "@id", }, "outbox": { "@id": "as:outbox", "@type": "@id", }, "following": { "@id": "as:following", "@type": "@id", }, "followers": { "@id": "as:followers", "@type": "@id", }, "streams": { "@id": "as:streams", "@type": "@id", }, "preferredUsername": "as:preferredUsername", "endpoints": { "@id": "as:endpoints", "@type": "@id", }, "uploadMedia": { "@id": "as:uploadMedia", "@type": "@id", }, "proxyUrl": { "@id": "as:proxyUrl", "@type": "@id", }, "liked": { "@id": "as:liked", "@type": "@id", }, "oauthAuthorizationEndpoint": { "@id": "as:oauthAuthorizationEndpoint", "@type": "@id", }, "oauthTokenEndpoint": { "@id": "as:oauthTokenEndpoint", "@type": "@id", }, "provideClientKey": { "@id": "as:provideClientKey", "@type": "@id", }, "signClientKey": { "@id": "as:signClientKey", "@type": "@id", }, "sharedInbox": { "@id": "as:sharedInbox", "@type": "@id", }, "Public": { "@id": "as:Public", "@type": "@id", }, "source": "as:source", "likes": { "@id": "as:likes", "@type": "@id", }, "shares": { "@id": "as:shares", "@type": "@id", }, "alsoKnownAs": { "@id": "as:alsoKnownAs", "@type": "@id", }, }, }, "https://w3id.org/security/v1": { "@context": { "id": "@id", "type": "@type", "dc": "http://purl.org/dc/terms/", "sec": "https://w3id.org/security#", "xsd": "http://www.w3.org/2001/XMLSchema#", "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016", "Ed25519Signature2018": "sec:Ed25519Signature2018", "EncryptedMessage": "sec:EncryptedMessage", "GraphSignature2012": "sec:GraphSignature2012", "LinkedDataSignature2015": "sec:LinkedDataSignature2015", "LinkedDataSignature2016": "sec:LinkedDataSignature2016", "CryptographicKey": "sec:Key", "authenticationTag": "sec:authenticationTag", "canonicalizationAlgorithm": "sec:canonicalizationAlgorithm", "cipherAlgorithm": "sec:cipherAlgorithm", "cipherData": "sec:cipherData", "cipherKey": "sec:cipherKey", "created": { "@id": "dc:created", "@type": "xsd:dateTime", }, "creator": { "@id": "dc:creator", "@type": "@id", }, "digestAlgorithm": "sec:digestAlgorithm", "digestValue": "sec:digestValue", "domain": "sec:domain", "encryptionKey": "sec:encryptionKey", "expiration": { "@id": "sec:expiration", "@type": "xsd:dateTime", }, "expires": { "@id": "sec:expiration", "@type": "xsd:dateTime", }, "initializationVector": "sec:initializationVector", "iterationCount": "sec:iterationCount", "nonce": "sec:nonce", "normalizationAlgorithm": "sec:normalizationAlgorithm", "owner": { "@id": "sec:owner", "@type": "@id", }, "password": "sec:password", "privateKey": { "@id": "sec:privateKey", "@type": "@id", }, "privateKeyPem": "sec:privateKeyPem", "publicKey": { "@id": "sec:publicKey", "@type": "@id", }, "publicKeyBase58": "sec:publicKeyBase58", "publicKeyPem": "sec:publicKeyPem", "publicKeyWif": "sec:publicKeyWif", "publicKeyService": { "@id": "sec:publicKeyService", "@type": "@id", }, "revoked": { "@id": "sec:revoked", "@type": "xsd:dateTime", }, "salt": "sec:salt", "signature": "sec:signature", "signatureAlgorithm": "sec:signingAlgorithm", "signatureValue": "sec:signatureValue", }, }, "https://w3id.org/security/data-integrity/v1": { "@context": { "id": "@id", "type": "@type", "@protected": true, "digestMultibase": { "@id": "https://w3id.org/security#digestMultibase", "@type": "https://w3id.org/security#multibase", }, "proof": { "@id": "https://w3id.org/security#proof", "@type": "@id", "@container": "@graph", }, "DataIntegrityProof": { "@id": "https://w3id.org/security#DataIntegrityProof", "@context": { "@protected": true, "id": "@id", "type": "@type", "challenge": "https://w3id.org/security#challenge", "created": { "@id": "http://purl.org/dc/terms/created", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "domain": "https://w3id.org/security#domain", "expires": { "@id": "https://w3id.org/security#expiration", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "nonce": "https://w3id.org/security#nonce", "proofPurpose": { "@id": "https://w3id.org/security#proofPurpose", "@type": "@vocab", "@context": { "@protected": true, "id": "@id", "type": "@type", "assertionMethod": { "@id": "https://w3id.org/security#assertionMethod", "@type": "@id", "@container": "@set", }, "authentication": { "@id": "https://w3id.org/security#authenticationMethod", "@type": "@id", "@container": "@set", }, "capabilityInvocation": { "@id": "https://w3id.org/security#capabilityInvocationMethod", "@type": "@id", "@container": "@set", }, "capabilityDelegation": { "@id": "https://w3id.org/security#capabilityDelegationMethod", "@type": "@id", "@container": "@set", }, "keyAgreement": { "@id": "https://w3id.org/security#keyAgreementMethod", "@type": "@id", "@container": "@set", }, }, }, "cryptosuite": "https://w3id.org/security#cryptosuite", "proofValue": { "@id": "https://w3id.org/security#proofValue", "@type": "https://w3id.org/security#multibase", }, "verificationMethod": { "@id": "https://w3id.org/security#verificationMethod", "@type": "@id", }, }, }, }, }, "https://www.w3.org/ns/did/v1": { "@context": { "@protected": true, "id": "@id", "type": "@type", "alsoKnownAs": { "@id": "https://www.w3.org/ns/activitystreams#alsoKnownAs", "@type": "@id", }, "assertionMethod": { "@id": "https://w3id.org/security#assertionMethod", "@type": "@id", "@container": "@set", }, "authentication": { "@id": "https://w3id.org/security#authenticationMethod", "@type": "@id", "@container": "@set", }, "capabilityDelegation": { "@id": "https://w3id.org/security#capabilityDelegationMethod", "@type": "@id", "@container": "@set", }, "capabilityInvocation": { "@id": "https://w3id.org/security#capabilityInvocationMethod", "@type": "@id", "@container": "@set", }, "controller": { "@id": "https://w3id.org/security#controller", "@type": "@id", }, "keyAgreement": { "@id": "https://w3id.org/security#keyAgreementMethod", "@type": "@id", "@container": "@set", }, "service": { "@id": "https://www.w3.org/ns/did#service", "@type": "@id", "@context": { "@protected": true, "id": "@id", "type": "@type", "serviceEndpoint": { "@id": "https://www.w3.org/ns/did#serviceEndpoint", "@type": "@id", }, }, }, "verificationMethod": { "@id": "https://w3id.org/security#verificationMethod", "@type": "@id", }, }, }, "https://w3id.org/security/multikey/v1": { "@context": { "id": "@id", "type": "@type", "@protected": true, "Multikey": { "@id": "https://w3id.org/security#Multikey", "@context": { "@protected": true, "id": "@id", "type": "@type", "controller": { "@id": "https://w3id.org/security#controller", "@type": "@id", }, "revoked": { "@id": "https://w3id.org/security#revoked", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "expires": { "@id": "https://w3id.org/security#expiration", "@type": "http://www.w3.org/2001/XMLSchema#dateTime", }, "publicKeyMultibase": { "@id": "https://w3id.org/security#publicKeyMultibase", "@type": "https://w3id.org/security#multibase", }, "secretKeyMultibase": { "@id": "https://w3id.org/security#secretKeyMultibase", "@type": "https://w3id.org/security#multibase", }, }, }, }, }, }; export default preloadedContexts;
runtime/docloader.test.ts +11 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import { verifyRequest } from "../sig/http.ts"; import { mockDocumentLoader } from "../testing/docloader.ts"; import { rsaPrivateKey2 } from "../testing/keys.ts"; import { test } from "../testing/mod.ts"; import preloadedContexts from "./contexts.ts"; import { fetchDocumentLoader, FetchError, Loading Loading @@ -61,6 +62,16 @@ test("fetchDocumentLoader()", async (t) => { }); mf.uninstall(); await t.step("preloaded contexts", async () => { for (const [url, document] of Object.entries(preloadedContexts)) { assertEquals(await fetchDocumentLoader(url), { contextUrl: null, documentUrl: url, document, }); } }); }); test("getAuthenticatedDocumentLoader()", async (t) => { Loading
runtime/docloader.ts +18 −10 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import { getLogger } from "@logtape/logtape"; import type { KvKey, KvStore } from "../federation/kv.ts"; import { signRequest } from "../sig/http.ts"; import { validateCryptoKey } from "../sig/key.ts"; import preloadedContexts from "./contexts.ts"; const logger = getLogger(["fedify", "runtime", "docloader"]); Loading Loading @@ -113,12 +114,28 @@ async function getRemoteDocument( /** * A JSON-LD document loader that utilizes the browser's `fetch` API. * * This loader preloads the below frequently used contexts: * * - <https://www.w3.org/ns/activitystreams> * - <https://w3id.org/security/v1> * - <https://w3id.org/security/data-integrity/v1> * - <https://www.w3.org/ns/did/v1> * - <https://w3id.org/security/multikey/v1> * @param url The URL of the document to load. * @returns The remote document. */ export async function fetchDocumentLoader( url: string, ): Promise<RemoteDocument> { if (url in preloadedContexts) { logger.debug("Using preloaded context: {url}.", { url }); return { contextUrl: null, document: preloadedContexts[url], documentUrl: url, }; } const request = createRequest(url); logRequest(request); const response = await fetch(request, { Loading Loading @@ -199,11 +216,7 @@ export interface KvCacheParameters { * a {@link URLPattern} and `duration` is a {@link Temporal.Duration}. * The `duration` is allowed to be at most 30 days. * * The default rules are: * * - `https://www.w3.org/ns/activitystreams` for 30 days * - `https://w3id.org/security/v1` for 30 days * - Everything else for 5 minutes * By default, 5 minutes for all URLs. */ rules?: [string | URL | URLPattern, Temporal.Duration][]; } Loading @@ -218,11 +231,6 @@ export function kvCache( ): DocumentLoader { const keyPrefix = prefix ?? ["_fedify", "remoteDocument"]; rules ??= [ [ "https://www.w3.org/ns/activitystreams", Temporal.Duration.from({ days: 30 }), ], ["https://w3id.org/security/v1", Temporal.Duration.from({ days: 30 })], [new URLPattern({}), Temporal.Duration.from({ minutes: 5 })], ]; for (const [p, duration] of rules) { Loading