Commit 6139a006 authored by Kim, Hyeonseo's avatar Kim, Hyeonseo Committed by Hyeonseo Kim
Browse files

feat: add WebFingerLinkDispatcher support to handleWebFinger

parent 72f8a9d3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1280,6 +1280,7 @@ export class FederationImpl<TContextData>
          actorDispatcher: this.actorCallbacks?.dispatcher,
          actorHandleMapper: this.actorCallbacks?.handleMapper,
          actorAliasMapper: this.actorCallbacks?.aliasMapper,
          webFingerLinkDispatcher: this.webFingerDispatcher,
          onNotFound,
          tracer,
        });
+40 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ import type {
  ActorAliasMapper,
  ActorDispatcher,
  ActorHandleMapper,
  WebFingerLinkDispatcher,
} from "../federation/callback.ts";
import type { RequestContext } from "../federation/context.ts";
import { MemoryKvStore } from "../federation/kv.ts";
@@ -538,4 +539,43 @@ test("handleWebFinger()", async (t) => {
    assertEquals(response.headers.get("Access-Control-Allow-Origin"), "*");
    assertEquals(await response.json(), expectedForHostnameWithPort);
  });

  await t.step("webFingerLinkDispatcher", async () => {
    const webFingerLinkDispatcher: WebFingerLinkDispatcher<void> = (_ctx) => {
      return [
        {
          rel: "http://ostatus.org/schema/1.0/subscribe",
          template: "https://example.com/follow?acct={uri}",
        },
      ];
    };

    const u = new URL(url);
    u.searchParams.set("resource", "acct:someone@example.com");
    const context = createContext(u);
    const request = context.request;
    const response = await handleWebFinger(request, {
      context,
      actorDispatcher,
      webFingerLinkDispatcher,
      onNotFound,
    });

    assertEquals(response.status, 200);
    const result = await response.json();

    // Check that custom links are added to the existing links
    const expectedWithCustomLinks = {
      ...expected,
      links: [
        ...expected.links,
        {
          rel: "http://ostatus.org/schema/1.0/subscribe",
          template: "https://example.com/follow?acct={uri}",
        },
      ],
    };

    assertEquals(result, expectedWithCustomLinks);
  });
});
+17 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ import type {
  ActorAliasMapper,
  ActorDispatcher,
  ActorHandleMapper,
  WebFingerLinkDispatcher,
} from "../federation/callback.ts";
import type { RequestContext } from "../federation/context.ts";
import { Link as LinkObject } from "../vocab/mod.ts";
@@ -47,6 +48,11 @@ export interface WebFingerHandlerParameters<TContextData> {
   */
  actorAliasMapper?: ActorAliasMapper<TContextData>;

  /**
   * The callback for dispatching the Links of webFinger.
   */
  webFingerLinkDispatcher?: WebFingerLinkDispatcher<TContextData>;

  /**
   * The function to call when the actor is not found.
   */
@@ -112,6 +118,7 @@ async function handleWebFingerInternal<TContextData>(
    actorAliasMapper,
    onNotFound,
    span,
    webFingerLinkDispatcher,
  }: WebFingerHandlerParameters<TContextData>,
): Promise<Response> {
  if (actorDispatcher == null) {
@@ -223,6 +230,16 @@ async function handleWebFingerInternal<TContextData>(
    if (image.mediaType != null) link.type = image.mediaType;
    links.push(link);
  }

  if (webFingerLinkDispatcher != null) {
    const customLinks = await webFingerLinkDispatcher(context);
    if (customLinks != null) {
      for (const link of customLinks) {
        links.push(link);
      }
    }
  }

  const aliases: string[] = [];
  if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
    aliases.push(`acct:${actor.preferredUsername}@${host ?? context.url.host}`);