Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ To be released.
incorrectly handled dependencies with registry prefixes (e.g., `npm:`),
creating invalid specifiers in *deno.json*. [[#460], [#496] by Hyeonseo Kim]

- Added `fedify relay` command to run an ephemeral ActivityPub relay server.
[[#510], [#518] by Jiwon Kwon]

- Supports both Mastodon and LitePub relay protocols via `--protocol`
option.
- Provides optional persistent storage via `--persistent` option with
SQLite database.
- Allows configuring subscription approval/rejection via `--accept-follow`
and `--reject-follow` options.
- Tunnels the relay server to the public internet by default for external
access, with `--no-tunnel` option to run locally only.

[Elysia]: https://elysiajs.com/
[#374]: https://github.com/fedify-dev/fedify/issues/374
[#397]: https://github.com/fedify-dev/fedify/issues/397
Expand All @@ -154,11 +166,13 @@ To be released.
[#458]: https://github.com/fedify-dev/fedify/pull/458
[#460]: https://github.com/fedify-dev/fedify/issues/460
[#496]: https://github.com/fedify-dev/fedify/pull/496
[#510]: https://github.com/fedify-dev/fedify/issues/510
[#518]: https://github.com/fedify-dev/fedify/pull/518

### @fedify/relay

- Created ActivityPub relay integration as the *@fedify/relay* package.
[[#359], [#459], [#471], [#490] by Jiwon Kwon]
[[#359], [#459], [#471], [#490], [#510], [#518] by Jiwon Kwon]

- Added `Relay` interface defining the common contract for relay
implementations.
Expand All @@ -176,6 +190,8 @@ To be released.
[#459]: https://github.com/fedify-dev/fedify/pull/459
[#471]: https://github.com/fedify-dev/fedify/pull/471
[#490]: https://github.com/fedify-dev/fedify/pull/490
[#510]: https://github.com/fedify-dev/fedify/issues/510
[#518]: https://github.com/fedify-dev/fedify/pull/518

### @fedify/vocab-tools

Expand Down
28 changes: 14 additions & 14 deletions docs/manual/relay.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import { MemoryKvStore } from "@fedify/fedify";

const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
name: "My ActivityPub Relay",
subscriptionHandler: async (ctx, actor) => {
// Approve all subscriptions
Expand All @@ -74,7 +74,7 @@ import { MemoryKvStore } from "@fedify/fedify";

const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
name: "My ActivityPub Relay",
subscriptionHandler: async (ctx, actor) => {
// Approve all subscriptions
Expand All @@ -97,7 +97,7 @@ import { serve } from "@hono/node-server";

const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
name: "My ActivityPub Relay",
subscriptionHandler: async (ctx, actor) => {
// Approve all subscriptions
Expand Down Expand Up @@ -130,8 +130,8 @@ Configuration options
: A [`KvStore`](./kv.md) for storing subscriber information and cryptographic
keys.

`domain`
: The domain name where the relay is hosted. Defaults to `"localhost"`.
`origin` (required)
: The origin URL where the relay is hosted (e.g., `"https://relay.example.com"`).

`name`
: Display name for the relay actor. Defaults to `"ActivityPub Relay"`.
Expand All @@ -146,7 +146,7 @@ Configuration options
// ---cut-before---
const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
queue: new InProcessMessageQueue(),
subscriptionHandler: async (ctx, actor) => true,
});
Expand Down Expand Up @@ -207,7 +207,7 @@ import { MemoryKvStore } from "@fedify/fedify";
// ---cut-before---
const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => true,
});
~~~~
Expand All @@ -225,7 +225,7 @@ import { MemoryKvStore } from "@fedify/fedify";
// ---cut-before---
const relay = createRelay("litepub", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => true,
});
~~~~
Expand All @@ -243,8 +243,8 @@ The subscription URL differs between Mastodon-style and LitePub-style relays:

| Relay type | Subscription URL | Example |
|--------------|----------------------------------------|-----------------------------------|
| `"mastodon"` | Inbox URL: `https://{domain}/inbox` | `https://relay.example.com/inbox` |
| `"litepub"` | Actor URL: `https://{domain}/actor` | `https://relay.example.com/actor` |
| `"mastodon"` | Inbox URL: `{origin}/inbox` | `https://relay.example.com/inbox` |
| `"litepub"` | Actor URL: `{origin}/actor` | `https://relay.example.com/actor` |

For more details on the protocol differences, see [FEP-ae0c].

Expand Down Expand Up @@ -295,7 +295,7 @@ import { MemoryKvStore } from "@fedify/fedify";
// ---cut-before---
const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => true, // Accept all
});
~~~~
Expand All @@ -310,7 +310,7 @@ const blockedDomains = ["spam.example", "blocked.example"];

const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => {
const domain = new URL(actor.id!).hostname;
if (blockedDomains.includes(domain)) {
Expand Down Expand Up @@ -345,7 +345,7 @@ import { createRelay } from "@fedify/relay";
import { MemoryKvStore } from "@fedify/fedify";
const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => true,
});
// ---cut-before---
Expand All @@ -365,7 +365,7 @@ import { createRelay } from "@fedify/relay";
import { MemoryKvStore } from "@fedify/fedify";
const relay = createRelay("mastodon", {
kv: new MemoryKvStore(),
domain: "relay.example.com",
origin: "https://relay.example.com",
subscriptionHandler: async (ctx, actor) => true,
});
// ---cut-before---
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
},
"dependencies": {
"@fedify/fedify": "workspace:*",
"@fedify/relay": "workspace:*",
"@fedify/sqlite": "workspace:*",
"@fedify/vocab-runtime": "workspace:*",
"@fedify/vocab-tools": "workspace:*",
Expand Down Expand Up @@ -84,7 +85,7 @@
},
"scripts": {
"codegen": "deno task -f @fedify/fedify codegen",
"build": "pnpm run codegen && pnpm run --filter fedify build && pnpm run --filter sqlite build && tsdown",
"build": "pnpm run codegen && pnpm run --filter fedify build && pnpm run --filter relay build && pnpm run --filter sqlite build && tsdown",
"prepack": "pnpm run build",
"prepublish": "pnpm run build",
"test": "pnpm build && node --test --experimental-transform-types 'src/**/*.test.ts' '!src/init/test/**'",
Expand Down
21 changes: 2 additions & 19 deletions packages/cli/src/inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Endpoints,
Follow,
generateCryptoKeyPair,
getActorHandle,
Image,
isActor,
lookupObject,
Expand Down Expand Up @@ -46,7 +45,7 @@ import { ActivityEntryPage, ActivityListPage } from "./inbox/view.tsx";
import { recordingSink } from "./log.ts";
import { tableStyle } from "./table.ts";
import { spawnTemporaryServer, type TemporaryServer } from "./tempserver.ts";
import { colors } from "./utils.ts";
import { colors, matchesActor } from "./utils.ts";

/**
* Context data for the ephemeral ActivityPub inbox server.
Expand Down Expand Up @@ -256,22 +255,6 @@ const activities: ActivityEntry[] = [];

const acceptFollows: string[] = [];

async function acceptsFollowFrom(actor: Actor): Promise<boolean> {
const actorUri = actor.id;
let actorHandle: string | undefined = undefined;
if (actorUri == null) return false;
for (let uri of acceptFollows) {
if (uri === "*") return true;
if (uri.startsWith("http:") || uri.startsWith("https:")) {
uri = new URL(uri).href; // normalize
if (uri === actorUri.href) return true;
}
if (actorHandle == null) actorHandle = await getActorHandle(actor);
if (actorHandle === uri) return true;
}
return false;
}

const peers: Record<string, Actor> = {};

function createSendDeleteToPeers(
Expand Down Expand Up @@ -329,7 +312,7 @@ federation
const { identifier } = parsed;
const follower = await activity.getActor();
if (!isActor(follower)) return;
const accepts = await acceptsFollowFrom(follower);
const accepts = await matchesActor(follower, acceptFollows);
if (!accepts || activity.id == null) {
logger.debug("Does not accept follow from {actor}.", {
actor: follower.id?.href,
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { lookupCommand, runLookup } from "./lookup.ts";
import { nodeInfoCommand, runNodeInfo } from "./nodeinfo.ts";
import { runTunnel, tunnelCommand } from "./tunnel.ts";
import { runWebFinger, webFingerCommand } from "./webfinger/mod.ts";
import { relayCommand, runRelay } from "./relay.ts";

const command = or(
initCommand,
Expand All @@ -20,6 +21,7 @@ const command = or(
nodeInfoCommand,
tunnelCommand,
generateVocabCommand,
relayCommand,
);

async function main() {
Expand Down Expand Up @@ -48,6 +50,9 @@ async function main() {
if (result.command === "generate-vocab") {
await runGenerateVocab(result);
}
if (result.command === "relay") {
await runRelay(result);
}
}

await main();
Loading
Loading