diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index d939266207..720249ef53 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -412,6 +412,13 @@ export declare function fetchMeta(): Promise /** Fetches and returns the NodeInfo (version 2.0) of a remote server. */ export declare function fetchNodeinfo(host: string): Promise +export interface Follow { + id: string + type: Activity + actor: string + object: string +} + export interface Following { id: string createdAt: DateTimeWithTimeZone @@ -425,13 +432,6 @@ export interface Following { followeeSharedInbox: string | null } -export interface FollowRelay { - id: string - type: Activity - actor: string - object: string -} - export interface FollowRequest { id: string createdAt: DateTimeWithTimeZone @@ -1265,7 +1265,9 @@ export type RelayStatus = 'accepted'| /** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */ export declare function removeOldAttestationChallenges(): Promise -export declare function renderFollowRelay(relayId: string): Promise +export declare function renderFollow(follower: UserLike, followee: UserLike, requestId?: string | undefined | null): Follow + +export declare function renderFollowRelay(relayId: string): Promise export interface RenoteMuting { id: string @@ -1537,6 +1539,12 @@ export interface UserKeypair { privateKey: string } +export interface UserLike { + id: string + host: string | null + uri: string +} + export interface UserList { id: string createdAt: DateTimeWithTimeZone diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 9ca4963455..2955ef672d 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -437,6 +437,7 @@ module.exports.PushNotificationKind = nativeBinding.PushNotificationKind module.exports.PushSubscriptionType = nativeBinding.PushSubscriptionType module.exports.RelayStatus = nativeBinding.RelayStatus module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges +module.exports.renderFollow = nativeBinding.renderFollow module.exports.renderFollowRelay = nativeBinding.renderFollowRelay module.exports.safeForSql = nativeBinding.safeForSql module.exports.sendPushNotification = nativeBinding.sendPushNotification diff --git a/packages/backend-rs/src/federation/activitypub/object/follow.rs b/packages/backend-rs/src/federation/activitypub/object/follow.rs new file mode 100644 index 0000000000..10ccbcd600 --- /dev/null +++ b/packages/backend-rs/src/federation/activitypub/object/follow.rs @@ -0,0 +1,65 @@ +use super::*; +use crate::{config::CONFIG, federation::internal_actor, misc::user}; +use serde::Serialize; + +#[macros::export(object)] +pub struct UserLike { + pub id: String, + pub host: Option, + pub uri: String, +} + +#[derive(Serialize)] +#[macros::export(object)] +pub struct Follow { + pub id: String, + pub r#type: Activity, + pub actor: String, + pub object: String, +} + +impl ActivityPubObject for Follow {} + +impl Follow { + #[allow(dead_code)] // TODO: remove this line + fn new(follower: UserLike, followee: UserLike, request_id: Option) -> Self { + Self { + id: request_id.unwrap_or_else(|| { + format!("{}/follows/{}/{}", CONFIG.url, follower.id, followee.id) + }), + r#type: Activity::Follow, + actor: match user::is_local!(follower) { + true => format!("{}/users/{}", CONFIG.url, follower.id), + false => follower.uri, + }, + object: match user::is_local!(followee) { + true => format!("{}/users/{}", CONFIG.url, followee.id), + false => followee.uri, + }, + } + } + + #[allow(dead_code)] // TODO: remove this line + async fn new_relay(relay_id: String) -> Result { + Ok(Self { + id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id), + r#type: Activity::Follow, + actor: format!( + "{}/users/{}", + CONFIG.url, + internal_actor::relay::get_id().await? + ), + object: AS_PUBLIC_URL.to_owned(), + }) + } +} + +#[macros::ts_export] +pub fn render_follow(follower: UserLike, followee: UserLike, request_id: Option) -> Follow { + Follow::new(follower, followee, request_id) +} + +#[macros::ts_export] +pub async fn render_follow_relay(relay_id: String) -> Result { + Follow::new_relay(relay_id).await +} diff --git a/packages/backend-rs/src/federation/activitypub/object/mod.rs b/packages/backend-rs/src/federation/activitypub/object/mod.rs index b245bca98a..7fbd1eebda 100644 --- a/packages/backend-rs/src/federation/activitypub/object/mod.rs +++ b/packages/backend-rs/src/federation/activitypub/object/mod.rs @@ -1,4 +1,4 @@ -pub mod relay; +pub mod follow; pub trait ActivityPubObject {} @@ -7,3 +7,5 @@ pub trait ActivityPubObject {} pub enum Activity { Follow, } + +const AS_PUBLIC_URL: &str = "https://www.w3.org/ns/activitystreams#Public"; diff --git a/packages/backend-rs/src/federation/activitypub/object/relay.rs b/packages/backend-rs/src/federation/activitypub/object/relay.rs deleted file mode 100644 index f3d7656564..0000000000 --- a/packages/backend-rs/src/federation/activitypub/object/relay.rs +++ /dev/null @@ -1,28 +0,0 @@ -use super::*; -use crate::{config::CONFIG, federation::internal_actor}; -use serde::Serialize; - -#[derive(Serialize)] -#[macros::export(object)] -pub struct FollowRelay { - pub id: String, - pub r#type: Activity, - pub actor: String, - pub object: String, -} - -impl ActivityPubObject for FollowRelay {} - -#[macros::export(js_name = "renderFollowRelay")] -pub async fn follow(relay_id: &str) -> Result { - Ok(FollowRelay { - id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id), - r#type: Activity::Follow, - actor: format!( - "{}/users/{}", - CONFIG.url, - internal_actor::relay::get_id().await? - ), - object: "https://www.w3.org/ns/activitystreams#Public".to_owned(), - }) -} diff --git a/packages/backend-rs/src/misc/user/mod.rs b/packages/backend-rs/src/misc/user/mod.rs index 16ee43aeca..059f3072c5 100644 --- a/packages/backend-rs/src/misc/user/mod.rs +++ b/packages/backend-rs/src/misc/user/mod.rs @@ -1 +1,23 @@ pub mod count; + +#[doc(hidden)] // hide the macro in the top doc page +#[macro_export] +macro_rules! is_local { + ($user_like:expr) => { + $user_like.host.is_none() + }; +} + +#[doc(inline)] // show the macro in the module doc page +pub use is_local; + +#[doc(hidden)] // hide the macro in the top doc page +#[macro_export] +macro_rules! is_remote { + ($user_like:expr) => { + $user_like.host.is_some() + }; +} + +#[doc(inline)] // show the macro in the module doc page +pub use is_remote; diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index e9c1b5bd1b..663f9be299 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -207,7 +207,7 @@ export async function createPerson( try { const data = await fetch(person.followers, { headers: { Accept: "application/json" }, - size: 1024 * 1024 + size: 1024 * 1024, }); const json_data = JSON.parse(await data.text()); @@ -223,7 +223,7 @@ export async function createPerson( try { const data = await fetch(person.following, { headers: { Accept: "application/json" }, - size: 1024 * 1024 + size: 1024 * 1024, }); const json_data = JSON.parse(await data.text()); @@ -492,7 +492,7 @@ export async function updatePerson( try { const data = await fetch(person.followers, { headers: { Accept: "application/json" }, - size: 1024 * 1024 + size: 1024 * 1024, }); const json_data = JSON.parse(await data.text()); @@ -508,7 +508,7 @@ export async function updatePerson( try { const data = await fetch(person.following, { headers: { Accept: "application/json" }, - size: 1024 * 1024 + size: 1024 * 1024, }); const json_data = JSON.parse(await data.text()); diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts deleted file mode 100644 index 30ad799507..0000000000 --- a/packages/backend/src/remote/activitypub/renderer/follow.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { config } from "@/config.js"; -import type { User } from "@/models/entities/user.js"; -import { Users } from "@/models/index.js"; - -export default ( - follower: { id: User["id"]; host: User["host"]; uri: User["host"] }, - followee: { id: User["id"]; host: User["host"]; uri: User["host"] }, - requestId?: string, -) => { - const follow = { - id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`, - type: "Follow", - actor: Users.isLocalUser(follower) - ? `${config.url}/users/${follower.id}` - : follower.uri, - object: Users.isLocalUser(followee) - ? `${config.url}/users/${followee.id}` - : followee.uri, - } as any; - - return follow; -}; diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index c9d94e9fd6..48ca3e6244 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -6,6 +6,7 @@ import { isAllowedServer, isBlockedServer, isSelfHost, + renderFollow, } from "backend-rs"; import { apGet } from "./request.js"; import type { IObject, ICollection, IOrderedCollection } from "./type.js"; @@ -24,7 +25,6 @@ import { renderPerson } from "@/remote/activitypub/renderer/person.js"; import renderQuestion from "@/remote/activitypub/renderer/question.js"; import renderCreate from "@/remote/activitypub/renderer/create.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { apLogger } from "@/remote/activitypub/logger.js"; import { IsNull, Not } from "typeorm"; diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index 81513f5d89..bc0442d381 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -9,7 +9,12 @@ import renderKey from "@/remote/activitypub/renderer/key.js"; import { renderPerson } from "@/remote/activitypub/renderer/person.js"; import renderEmoji from "@/remote/activitypub/renderer/emoji.js"; import { inbox as processInbox } from "@/queue/index.js"; -import { fetchMeta, getInstanceActor, isSelfHost } from "backend-rs"; +import { + fetchMeta, + getInstanceActor, + isSelfHost, + renderFollow, +} from "backend-rs"; import { Notes, Users, @@ -24,7 +29,6 @@ import { checkFetch, getSignatureUser, } from "@/remote/activitypub/check-fetch.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import Featured from "./activitypub/featured.js"; import Following from "./activitypub/following.js"; import Followers from "./activitypub/followers.js"; diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index 1d7b80ffbf..9bc59e70e9 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -1,5 +1,4 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { renderUndo } from "@/remote/activitypub/renderer/undo.js"; import { renderBlock } from "@/remote/activitypub/renderer/block.js"; import { deliver } from "@/queue/index.js"; @@ -20,6 +19,7 @@ import { publishToMainStream, publishToUserStream, UserEvent, + renderFollow, } from "backend-rs"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { webhookDeliver } from "@/queue/index.js"; diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 494027a37c..d0bcdd33a4 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -156,7 +156,7 @@ async function fetchFaviconUrl( // TODO //timeout: 10000, agent: getAgentByUrl, - size: 1024 * 1024 + size: 1024 * 1024, }); if (favicon.ok) { diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index aea5bd48a5..c3dc91ff9e 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -1,5 +1,4 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import renderAccept from "@/remote/activitypub/renderer/accept.js"; import renderReject from "@/remote/activitypub/renderer/reject.js"; import { deliver } from "@/queue/index.js"; @@ -23,6 +22,7 @@ import { publishToMainStream, publishToUserStream, UserEvent, + renderFollow, } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index 9d0135b81f..e46d8422db 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -3,9 +3,9 @@ import { publishToMainStream, publishToUserStream, UserEvent, + renderFollow, } from "backend-rs"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { renderUndo } from "@/remote/activitypub/renderer/undo.js"; import renderReject from "@/remote/activitypub/renderer/reject.js"; import { deliver, webhookDeliver } from "@/queue/index.js"; diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts index 1523573bf9..aaed1df3a8 100644 --- a/packages/backend/src/services/following/reject.ts +++ b/packages/backend/src/services/following/reject.ts @@ -1,5 +1,4 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import renderReject from "@/remote/activitypub/renderer/reject.js"; import { deliver, webhookDeliver } from "@/queue/index.js"; import { @@ -7,6 +6,7 @@ import { publishToMainStream, publishToUserStream, UserEvent, + renderFollow, } from "backend-rs"; import type { ILocalUser, IRemoteUser } from "@/models/entities/user.js"; import { Users, FollowRequests, Followings } from "@/models/index.js"; diff --git a/packages/backend/src/services/following/requests/accept.ts b/packages/backend/src/services/following/requests/accept.ts index bcd7d2cf4c..81484d6fba 100644 --- a/packages/backend/src/services/following/requests/accept.ts +++ b/packages/backend/src/services/following/requests/accept.ts @@ -1,8 +1,7 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import renderAccept from "@/remote/activitypub/renderer/accept.js"; import { deliver } from "@/queue/index.js"; -import { Event, publishToMainStream } from "backend-rs"; +import { Event, publishToMainStream, renderFollow } from "backend-rs"; import { insertFollowingDoc } from "../create.js"; import type { User, CacheableUser } from "@/models/entities/user.js"; import { FollowRequests, Users } from "@/models/index.js"; diff --git a/packages/backend/src/services/following/requests/cancel.ts b/packages/backend/src/services/following/requests/cancel.ts index eb1b2dcb49..435c86f19b 100644 --- a/packages/backend/src/services/following/requests/cancel.ts +++ b/packages/backend/src/services/following/requests/cancel.ts @@ -1,8 +1,7 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { renderUndo } from "@/remote/activitypub/renderer/undo.js"; import { deliver } from "@/queue/index.js"; -import { Event, publishToMainStream } from "backend-rs"; +import { Event, publishToMainStream, renderFollow } from "backend-rs"; import { IdentifiableError } from "@/misc/identifiable-error.js"; import type { User } from "@/models/entities/user.js"; import { Users, FollowRequests } from "@/models/index.js"; diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts index 40f383cfd3..cc6b4261eb 100644 --- a/packages/backend/src/services/following/requests/create.ts +++ b/packages/backend/src/services/following/requests/create.ts @@ -1,9 +1,8 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderFollow from "@/remote/activitypub/renderer/follow.js"; import { deliver } from "@/queue/index.js"; import type { User } from "@/models/entities/user.js"; import { Blockings, FollowRequests, Users } from "@/models/index.js"; -import { Event, genIdAt, publishToMainStream } from "backend-rs"; +import { Event, genIdAt, publishToMainStream, renderFollow } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import { config } from "@/config.js";