Unverified Commit 81ebffcc authored by Hong Minhee's avatar Hong Minhee
Browse files

Workaround invalid AT protocol URIs from BridgyFed

BridgyFed generates AT protocol URIs like at://did:plc:... that violate
RFC 3986 URL syntax due to colons in the authority part. This causes
parsing failures in Link.fromJsonLd() and other vocabulary methods.

Added temporary fix to URL-encode colons in did:plc DIDs to make them
valid URLs (at://did%3Aplc%3A...) until upstream issue is resolved.

Fixes https://github.com/fedify-dev/fedify/issues/436
parent bd1a202e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -8,6 +8,13 @@ Version 1.0.29

To be released.

 -  Added a temporary workaround for invalid AT Protocol URIs from BridgyFed.
    URIs like `at://did:plc:...` that violate RFC 3986 URI syntax are now
    automatically URL-encoded to `at://did%3Aplc%3A...` to prevent parsing
    failures when processing bridged Bluesky content.  [[#436]]

[#436]: https://github.com/fedify-dev/fedify/issues/436


Version 1.0.28
--------------
+27 −9
Original line number Diff line number Diff line
@@ -5645,7 +5645,9 @@ get urls(): ((URL | Link))[] {
      const decoded =
      typeof v === \\"object\\" && \\"@id\\" in v
        && typeof v[\\"@id\\"] === \\"string\\"
        && v[\\"@id\\"] !== \\"\\" && v[\\"@id\\"] !== \\"/\\" ? new URL(v[\\"@id\\"]) : typeof v === \\"object\\" && \\"@type\\" in v
        && v[\\"@id\\"] !== \\"\\" && v[\\"@id\\"] !== \\"/\\" ? v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]) : typeof v === \\"object\\" && \\"@type\\" in v
      && Array.isArray(v[\\"@type\\"])&& [\\"https://www.w3.org/ns/activitystreams#Link\\",\\"https://www.w3.org/ns/activitystreams#Hashtag\\",\\"https://www.w3.org/ns/activitystreams#Mention\\"].some(
            t => v[\\"@type\\"].includes(t)) ? await Link.fromJsonLd(
      v, options) : undefined
@@ -21904,7 +21906,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _2JCYDbSxEHCCLdBYed33cCETfGyR_proxyUrl__array
    ) {
      if (v == null) continue;
    _2JCYDbSxEHCCLdBYed33cCETfGyR_proxyUrl.push(new URL(v[\\"@id\\"]))
    _2JCYDbSxEHCCLdBYed33cCETfGyR_proxyUrl.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_2JCYDbSxEHCCLdBYed33cCETfGyR_proxyUrl = _2JCYDbSxEHCCLdBYed33cCETfGyR_proxyUrl;
    const _25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint: (URL)[] = [];
@@ -21919,7 +21923,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint__array
    ) {
      if (v == null) continue;
    _25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint.push(new URL(v[\\"@id\\"]))
    _25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint = _25S6UmgzDead8hxL5sQFezZTAusd_oauthAuthorizationEndpoint;
    const _iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint: (URL)[] = [];
@@ -21934,7 +21940,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint__array
    ) {
      if (v == null) continue;
    _iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint.push(new URL(v[\\"@id\\"]))
    _iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint = _iAMxqrSba7yBCRB1FZ5kEVdKEZ3_oauthTokenEndpoint;
    const _8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey: (URL)[] = [];
@@ -21949,7 +21957,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey__array
    ) {
      if (v == null) continue;
    _8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey.push(new URL(v[\\"@id\\"]))
    _8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey = _8Bx9qN8oU7Bpt2xi6khaxWp1gMr_provideClientKey;
    const _3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey: (URL)[] = [];
@@ -21964,7 +21974,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey__array
    ) {
      if (v == null) continue;
    _3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey.push(new URL(v[\\"@id\\"]))
    _3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey = _3dU7PMVQZJpsCpo2F4RQXxBXdPmS_signClientKey;
    const _3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox: (URL)[] = [];
@@ -21979,7 +21991,9 @@ proxyUrl?: URL | null;oauthAuthorizationEndpoint?: URL | null;oauthTokenEndpoint
        : _3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox__array
    ) {
      if (v == null) continue;
    _3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox.push(new URL(v[\\"@id\\"]))
    _3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox = _3JprUSDLVqqX4dwHRi37qGZZCRCc_sharedInbox;
    
@@ -27570,7 +27584,9 @@ get names(): ((string | LanguageString))[] {
        : _pVjLsybKQdmkjuU7MHjiVmNnuj7_href__array
    ) {
      if (v == null) continue;
    _pVjLsybKQdmkjuU7MHjiVmNnuj7_href.push(new URL(v[\\"@id\\"]))
    _pVjLsybKQdmkjuU7MHjiVmNnuj7_href.push(v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]))
    }
    instance.#_pVjLsybKQdmkjuU7MHjiVmNnuj7_href = _pVjLsybKQdmkjuU7MHjiVmNnuj7_href;
    const _2a1c5GkfkQsnyyLybF8UXBQfFuHZ_rel: (string)[] = [];
@@ -40325,7 +40341,9 @@ proofs?: (DataIntegrityProof | URL)[];accuracy?: number | null;altitude?: number
      typeof v === \\"object\\" && \\"@value\\" in v
      && (v[\\"@value\\"] == \\"cm\\" || v[\\"@value\\"] == \\"feet\\" || v[\\"@value\\"] == \\"inches\\" || v[\\"@value\\"] == \\"km\\" || v[\\"@value\\"] == \\"m\\" || v[\\"@value\\"] == \\"miles\\") ? v[\\"@value\\"] : typeof v === \\"object\\" && \\"@id\\" in v
        && typeof v[\\"@id\\"] === \\"string\\"
        && v[\\"@id\\"] !== \\"\\" && v[\\"@id\\"] !== \\"/\\" ? new URL(v[\\"@id\\"]) : undefined
        && v[\\"@id\\"] !== \\"\\" && v[\\"@id\\"] !== \\"/\\" ? v[\\"@id\\"].startsWith(\\"at://did:plc:\\")
        ? new URL(\\"at://did%3Aplc%3A\\" + v[\\"@id\\"].slice(13))
        : new URL(v[\\"@id\\"]) : undefined
      ;
      if (typeof decoded === \\"undefined\\") continue;
      _oKrwxU4V8wiKhMW1QEYQibcJh8c_units.push(decoded);
+3 −1
Original line number Diff line number Diff line
@@ -144,7 +144,9 @@ const scalarTypes: Record<string, ScalarType> = {
        && ${v}["@id"] !== "" && ${v}["@id"] !== "/"`;
    },
    decoder(v) {
      return `new URL(${v}["@id"])`;
      return `${v}["@id"].startsWith("at://did:plc:")
        ? new URL("at://did%3Aplc%3A" + ${v}["@id"].slice(13))
        : new URL(${v}["@id"])`;
    },
  },
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString": {
+18 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import {
  type DataIntegrityProof,
  Follow,
  Hashtag,
  Link,
  Note,
  Object,
  OrderedCollectionPage,
@@ -782,6 +783,23 @@ test("Actor.getOutbox()", async () => {
  assertEquals(outbox.totalItems, 1);
});

test("Link.fromJsonLd()", async () => {
  const link = await Link.fromJsonLd({
    "@context": "https://www.w3.org/ns/activitystreams",
    "type": "Link",
    "rel": "canonical",
    "href":
      "at://did:plc:ia76kvnndjutgedggx2ibrem/app.bsky.feed.post/3lyxjjs27jkqg",
  });
  assertEquals(link.rel, "canonical");
  assertEquals(
    link.href,
    new URL(
      "at://did%3Aplc%3Aia76kvnndjutgedggx2ibrem/app.bsky.feed.post/3lyxjjs27jkqg",
    ),
  );
});

function getAllProperties(
  type: TypeSchema,
  types: Record<string, TypeSchema>,