Unverified Commit 276c412a authored by Hong Minhee's avatar Hong Minhee
Browse files

Rename `handle` to `identifier` for consistency

parent 448c7c52
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -8,6 +8,72 @@ Version 1.0.0

To be released.

 -  The term `handle` for dispatching actors is deprecated in favor of
    `identifier`.

     -  The URI template for the following methods now accepts variable
        `{identifier}` instead of `{handle}`:

         -  `Federation.setActorDispatcher()`
         -  `Federation.setInboxDispatcher()`
         -  `Federation.setOutboxDispatcher()`
         -  `Federation.setFollowingDispatcher()`
         -  `Federation.setFollowersDispatcher()`
         -  `Federation.setLikedDispatcher()`
         -  `Federation.setFeaturedDispatcher()`
         -  `Federation.setFeaturedTagsDispatcher()`
         -  `Federation.setInboxListeners()`

        The `{handle}` variable is deprecated, and it will be removed in
        the future.
     -  The type of `Federation.setActorDispatcher()` method's first parameter
        became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setInboxDispatcher()` method's first parameter
        became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setOutboxDispatcher()` method's first parameter
        became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setFollowingDispatcher()` method's first
        parameter became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setFollowersDispatcher()` method's first
        parameter became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setLikedDispatcher()` method's first parameter
        became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setFeaturedDispatcher()` method's first
        parameter became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setFeaturedTagsDispatcher()` method's first
        parameter became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Federation.setInboxListeners()` method's first parameter
        became ```${string}{identifier}${string}` |
        `${string}{handle}${string}``` (was ```${string}{handle}${string}```).
     -  The type of `Context.getDocumentLoader()` method's first parameter
        became `{ identifier: string } | { username: string } | { handle:
        string } | { keyId: URL; privateKey: CryptoKey }` (was `{ handle:
        string } | { keyId: URL; privateKey: CryptoKey }`).
     -  Passing `{ handle: string }` to `Context.getDocumentLoader()` method is
        deprecated in favor of `{ username: string }`.
     -  The type of `Context.sendActivity()` method's first parameter became
        `SenderKeyPair | SenderKeyPair[] | { identifier: string } | {
        username: string } | { handle: string }` (was `SenderKeyPair | SenderKeyPair[] | { handle: string }`).
     -  All properties of `ParseUriResult` type became readonly.
     -  Added `identifier` properties next to `handle` properties in
        `ParseUriResult` type.
     -  The `handle` properties of `ParseUriResult` type are deprecated in favor
        of `identifier` properties.
     -  The return type of `SharedInboxKeyDispatcher` callback type became
        `SenderKeyPair | { identifier: string } | { username: string } |
        { handle: string } | null | Promise<SenderKeyPair | { identifier:
        string } | { username: string } | { handle: string } | null>`
        (was `SenderKeyPair | { handle: string } | null |
        Promise<SenderKeyPair | { handle: string } | null>`).

 -  Fedify now supports [Linked Data Signatures], which is outdated but still
    widely used in the fediverse.

+35 −30
Original line number Diff line number Diff line
@@ -96,7 +96,9 @@ export const command = new Command()
    }
    if (options.follow != null && options.follow.length > 0) {
      spinner.text = "Following actors...";
      const documentLoader = await fedCtx.getDocumentLoader({ handle: "i" });
      const documentLoader = await fedCtx.getDocumentLoader({
        identifier: "i",
      });
      for (const uri of options.follow) {
        spinner.text = `Following ${colors.green(uri)}...`;
        const actor = await lookupObject(uri, { documentLoader });
@@ -107,7 +109,7 @@ export const command = new Command()
        }
        if (actor.id != null) peers[actor.id?.href] = actor;
        await fedCtx.sendActivity(
          { handle: "i" },
          { identifier: "i" },
          actor,
          new Follow({
            id: new URL(`#follows/${actor.id?.href}`, fedCtx.getActorUri("i")),
@@ -132,34 +134,34 @@ const time = Temporal.Now.instant();
let actorKeyPairs: CryptoKeyPair[] | undefined = undefined;

federation
  .setActorDispatcher("/{handle}", async (ctx, handle) => {
    if (handle !== "i") return null;
  .setActorDispatcher("/{identifier}", async (ctx, identifier) => {
    if (identifier !== "i") return null;
    return new Application({
      id: ctx.getActorUri(handle),
      preferredUsername: handle,
      id: ctx.getActorUri(identifier),
      preferredUsername: identifier,
      name: "Fedify Ephemeral Inbox",
      summary: "An ephemeral ActivityPub inbox for testing purposes.",
      inbox: ctx.getInboxUri(handle),
      inbox: ctx.getInboxUri(identifier),
      endpoints: new Endpoints({
        sharedInbox: ctx.getInboxUri(),
      }),
      followers: ctx.getFollowersUri(handle),
      following: ctx.getFollowingUri(handle),
      outbox: ctx.getOutboxUri(handle),
      followers: ctx.getFollowersUri(identifier),
      following: ctx.getFollowingUri(identifier),
      outbox: ctx.getOutboxUri(identifier),
      manuallyApprovesFollowers: true,
      published: time,
      icon: new Image({
        url: new URL("https://fedify.dev/logo.png"),
        mediaType: "image/png",
      }),
      publicKey: (await ctx.getActorKeyPairs(handle))[0].cryptographicKey,
      assertionMethods: (await ctx.getActorKeyPairs(handle))
      publicKey: (await ctx.getActorKeyPairs(identifier))[0].cryptographicKey,
      assertionMethods: (await ctx.getActorKeyPairs(identifier))
        .map((pair) => pair.multikey),
      url: ctx.getActorUri(handle),
      url: ctx.getActorUri(identifier),
    });
  })
  .setKeyPairsDispatcher(async (_ctxData, handle) => {
    if (handle !== "i") return [];
  .setKeyPairsDispatcher(async (_ctxData, identifier) => {
    if (identifier !== "i") return [];
    if (actorKeyPairs == null) {
      actorKeyPairs = [
        await generateCryptoKeyPair("RSASSA-PKCS1-v1_5"),
@@ -195,7 +197,7 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> {
  const ctx = federation.createContext(server.url, -1);
  const actorId = ctx.getActorUri("i");
  await ctx.sendActivity(
    { handle: "i" },
    { identifier: "i" },
    Object.values(peers),
    new Delete({
      id: new URL(`#delete`, actorId),
@@ -209,8 +211,8 @@ async function sendDeleteToPeers(server: TemporaryServer): Promise<void> {
const followers: Record<string, Actor> = {};

federation
  .setInboxListeners("/{handle}/inbox", "/inbox")
  .setSharedKeyDispatcher((_) => ({ handle: "i" }))
  .setInboxListeners("/{identifier}/inbox", "/inbox")
  .setSharedKeyDispatcher((_) => ({ identifier: "i" }))
  .on(Activity, async (ctx, activity) => {
    activities[ctx.data].activity = activity;
    for await (const actor of activity.getActors()) {
@@ -224,8 +226,8 @@ federation
      const objectId = activity.objectId;
      if (objectId == null) return;
      const parsed = ctx.parseUri(objectId);
      if (parsed?.type !== "actor" || parsed.handle !== "i") return;
      const { handle } = parsed;
      if (parsed?.type !== "actor" || parsed.identifier !== "i") return;
      const { identifier } = parsed;
      const follower = await activity.getActor();
      if (!isActor(follower)) return;
      const accepts = await acceptsFollowFrom(follower);
@@ -240,11 +242,11 @@ federation
      });
      followers[activity.id.href] = follower;
      await ctx.sendActivity(
        { handle },
        { identifier },
        follower,
        new Accept({
          id: new URL(`#accepts/${follower.id?.href}`, ctx.getActorUri("i")),
          actor: ctx.getActorUri(handle),
          actor: ctx.getActorUri(identifier),
          object: activity.id,
        }),
      );
@@ -252,8 +254,8 @@ federation
  });

federation
  .setFollowersDispatcher("/{handle}/followers", (_ctx, handle) => {
    if (handle !== "i") return null;
  .setFollowersDispatcher("/{identifier}/followers", (_ctx, identifier) => {
    if (identifier !== "i") return null;
    const items: Recipient[] = [];
    for (const follower of Object.values(followers)) {
      if (follower.id == null) continue;
@@ -261,18 +263,21 @@ federation
    }
    return { items };
  })
  .setCounter((_ctx, handle) => {
    if (handle !== "i") return null;
  .setCounter((_ctx, identifier) => {
    if (identifier !== "i") return null;
    return Object.keys(followers).length;
  });

federation
  .setFollowingDispatcher("/{handle}/following", (_ctx, _handle) => null)
  .setCounter((_ctx, _handle) => 0);
  .setFollowingDispatcher(
    "/{identifier}/following",
    (_ctx, _identifier) => null,
  )
  .setCounter((_ctx, _identifier) => 0);

federation
  .setOutboxDispatcher("/{handle}/outbox", (_ctx, _handle) => null)
  .setCounter((_ctx, _handle) => 0);
  .setOutboxDispatcher("/{identifier}/outbox", (_ctx, _identifier) => null)
  .setCounter((_ctx, _identifier) => 0);

federation.setNodeInfoDispatcher("/nodeinfo/2.1", (_ctx) => {
  return {
+4 −4
Original line number Diff line number Diff line
@@ -845,11 +845,11 @@ const federation = createFederation({
  queue: ${mqDesc.object},
});

federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => {
federation.setActorDispatcher("/users/{identifier}", async (ctx, identifier) => {
  return new Person({
    id: ctx.getActorUri(handle),
    preferredUsername: handle,
    name: handle,
    id: ctx.getActorUri(identifier),
    preferredUsername: identifier,
    name: identifier,
  });
});

+16 −14
Original line number Diff line number Diff line
@@ -42,11 +42,11 @@ import type { Actor, Federation } from "@fedify/fedify";
const federation = null as unknown as Federation<void>;
/**
 * A hypothetical function that checks if the user blocks the actor.
 * @param handle The handle of the user to check if the actor is blocked.
 * @param userId The ID of the user to check if the actor is blocked.
 * @param signedKeyOwner The actor who signed the request.
 * @returns `true` if the actor is blocked; otherwise, `false`.
 */
async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> {
async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> {
  return false;
}
// ---cut-before---
@@ -54,12 +54,12 @@ import { federation } from "./your-federation.ts";
import { isBlocked } from "./your-blocklist.ts";

federation
  .setActorDispatcher("/users/{handle}", async (ctx, handle) => {
  .setActorDispatcher("/users/{identifier}", async (ctx, identifier) => {
    // Omitted for brevity; see the related section for details.
  })
  .authorize(async (ctx, handle, signedKey, signedKeyOwner) => {
  .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => {
    if (signedKeyOwner == null) return false;
    return !await isBlocked(handle, signedKeyOwner);
    return !await isBlocked(identifier, signedKeyOwner);
  });
~~~~

@@ -74,11 +74,11 @@ import type { Actor, Federation } from "@fedify/fedify";
const federation = null as unknown as Federation<void>;
/**
 * A hypothetical function that checks if the user blocks the actor.
 * @param handle The handle of the user to check if the actor is blocked.
 * @param userId The ID of the user to check if the actor is blocked.
 * @param signedKeyOwner The actor who signed the request.
 * @returns `true` if the actor is blocked; otherwise, `false`.
 */
async function isBlocked(handle: string, signedKeyOwner: Actor): Promise<boolean> {
async function isBlocked(userId: string, signedKeyOwner: Actor): Promise<boolean> {
  return false;
}
// ---cut-before---
@@ -86,12 +86,12 @@ import { federation } from "./your-federation.ts";
import { isBlocked } from "./your-blocklist.ts";

federation
  .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => {
  .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => {
    // Omitted for brevity; see the related section for details.
  })
  .authorize(async (ctx, handle, signedKey, signedKeyOwner) => {
  .authorize(async (ctx, identifier, signedKey, signedKeyOwner) => {
    if (signedKeyOwner == null) return false;
    return !await isBlocked(handle, signedKeyOwner);
    return !await isBlocked(identifier, signedKeyOwner);
  });
~~~~

@@ -126,10 +126,10 @@ interface Post {
}
/**
 * A hypothetical function that gets posts from the database.
 * @param handle The handle of the user to get posts.
 * @param userId The ID of the user to get posts.
 * @returns The posts of the user.
 */
async function getPosts(handle: string): Promise<Post[]> {
async function getPosts(userId: string): Promise<Post[]> {
  return [];
}
/**
@@ -145,8 +145,8 @@ import { federation } from "./your-federation.ts";
import { getPosts, toCreate } from "./your-model.ts";

federation
  .setOutboxDispatcher("/users/{handle}/outbox", async (ctx, handle) => {
    const posts = await getPosts(handle);  // Get posts from the database
  .setOutboxDispatcher("/users/{identifier}/outbox", async (ctx, identifier) => {
    const posts = await getPosts(identifier);  // Get posts from the database
    const keyOwner = await ctx.getSignedKeyOwner();  // Get the actor who signed the request
    if (keyOwner == null) return { items: [] };  // Return an empty array if the actor is not found
    const items = posts
@@ -155,3 +155,5 @@ federation
    return { items };
  });
~~~~

<!-- cSpell: ignore blocklist -->
+107 −42

File changed.

Preview size limit exceeded, changes collapsed.

Loading