diff --git a/docs/activitypub/ACTIVITYPUB_IMPLEMENTATION.md b/docs/activitypub/ACTIVITYPUB_IMPLEMENTATION.md deleted file mode 100644 index 607131c3..00000000 --- a/docs/activitypub/ACTIVITYPUB_IMPLEMENTATION.md +++ /dev/null @@ -1,287 +0,0 @@ -# ActivityPub Implementation for Solar Network - -## Overview - -This document outlines the initial implementation of ActivityPub federation for the Solar Network (DysonNetwork), following the plan outlined in `ACTIVITYPUB_PLAN.md`. - -## What Has Been Created - -### 1. Database Models (DysonNetwork.Shared/Models) - -All ActivityPub-related models are shared across projects and located in `DysonNetwork.Shared/Models/`: - -#### FediverseInstance.cs -- Tracks ActivityPub instances (servers) in the fediverse -- Stores instance metadata, blocking status, and activity tracking -- Links to actors and content from that instance - -#### FediverseActor.cs -- Represents remote actors (users/accounts) from other instances -- Stores actor information including keys, inbox/outbox URLs -- Links to instance and manages relationships -- Tracks whether the actor is a bot, locked, or discoverable - -#### FediverseContent.cs -- Stores content (posts, notes, etc.) received from the fediverse -- Supports multiple content types (Note, Article, Image, Video, etc.) -- Includes attachments, mentions, tags, and emojis -- Links to local posts for unified display - -#### FediverseActivity.cs -- Tracks ActivityPub activities (Create, Follow, Like, Announce, etc.) -- Stores raw activity data and processing status -- Links to actors, content, and local entities -- Supports both incoming and outgoing activities - -#### FediverseRelationship.cs -- Manages follow relationships between local and remote actors -- Tracks relationship state (Pending, Accepted, Rejected) -- Supports muting and blocking -- Links to local accounts/publishers - -#### FediverseReaction.cs -- Stores reactions (likes, emoji) from both local and remote actors -- Links to content and actor -- Supports federation of reactions - -### 2. Database Migration - -**File**: `DysonNetwork.Sphere/Migrations/20251228120000_AddActivityPubModels.cs` - -This migration creates the following tables: -- `fediverse_instances` - Instance tracking -- `fediverse_actors` - Remote actor profiles -- `fediverse_contents` - Federated content storage -- `fediverse_activities` - Activity tracking and processing -- `fediverse_relationships` - Follow relationships -- `fediverse_reactions` - Reactions from fediverse - -### 3. API Controllers (DysonNetwork.Sphere/ActivityPub) - -#### WebFingerController.cs -- **Endpoint**: `GET /.well-known/webfinger?resource=acct:@` -- **Purpose**: Allows other instances to discover actors via WebFinger protocol -- **Response**: Returns actor's inbox/outbox URLs and profile page links -- Maps local Publishers to ActivityPub actors - -#### ActivityPubController.cs -Provides three main endpoints: - -1. **GET /activitypub/actors/{username}** - - Returns ActivityPub actor profile in JSON-LD format - - Includes actor's keys, inbox, outbox, followers, and following URLs - - Maps SnPublisher to ActivityPub Person type - -2. **GET /activitypub/actors/{username}/outbox** - - Returns actor's outbox collection - - Lists public posts as ActivityPub activities - - Supports pagination - -3. **POST /activitypub/actors/{username}/inbox** - - Receives incoming ActivityPub activities - - Supports Create, Follow, Like, Announce activities - - Placeholder for activity processing logic - -## Architecture - -### Data Flow - -``` -Remote Instance Solar Network (Sphere) - │ │ - │ ───WebFinger─────> │ - │ │ - │ <───Actor JSON──── │ - │ │ - │ ───Activity─────> │ → Inbox Processing - │ │ - │ <───Activity────── │ ← Outbox Distribution -``` - -### Model Relationships - -- `SnFediverseInstance` has many `SnFediverseActor` -- `SnFediverseInstance` has many `SnFediverseContent` -- `SnFediverseActor` has many `SnFediverseContent` -- `SnFediverseActor` has many `SnFediverseActivity` -- `SnFediverseActor` has many `SnFediverseRelationship` (as follower and following) -- `SnFediverseContent` has many `SnFediverseActivity` -- `SnFediverseContent` has many `SnFediverseReaction` -- `SnFediverseContent` optionally links to `SnPost` (local copy) - -### Local to Fediverse Mapping - -| Solar Network Model | ActivityPub Type | -|-------------------|-----------------| -| SnPublisher | Person (Actor) | -| SnPost | Note / Article | -| SnPostReaction | Like / EmojiReact | -| Follow | Follow Activity | -| SnPublisherSubscription | Follow Relationship | - -## Next Steps - -### Stage 1: Core Infrastructure ✅ (COMPLETED) -- ✅ Create database models for ActivityPub entities -- ✅ Create database migration -- ✅ Implement basic WebFinger endpoint -- ✅ Implement basic Actor endpoint -- ✅ Implement Inbox/Outbox endpoints - -### Stage 2: Activity Processing ✅ (COMPLETED) -- ✅ Implement HTTP Signature verification (ActivityPubSignatureService) -- ✅ Process incoming activities: - - Follow/Accept/Reject - - Create (incoming posts) - - Like/Announce - - Delete/Update - - Undo -- ✅ Generate outgoing activities (ActivityPubDeliveryService) -- ✅ Queue and retry failed deliveries (basic implementation) - -### Stage 3: Key Management ✅ (COMPLETED) -- ✅ Generate RSA key pairs for each Publisher (ActivityPubKeyService) -- ✅ Store public/private keys in Publisher.Meta -- ✅ Sign outgoing HTTP requests -- ✅ Verify incoming HTTP signatures - -### Stage 4: Content Federation (IN PROGRESS) -- ✅ Convert between SnPost and ActivityPub Note/Article (basic mapping) -- ✅ Handle content attachments and media -- ✅ Support content warnings and sensitive content -- ✅ Handle replies, boosts, and mentions -- ⏳ Add local post reference for federated content -- ⏳ Handle media attachments in federated content - -### Stage 5: Relationship Management ✅ (COMPLETED) -- ✅ Handle follow/unfollow logic -- ✅ Update followers/following collections -- ✅ Block/mute functionality (data model ready) -- ✅ Relationship state machine (Pending, Accepted, Rejected) - -### Stage 6: Testing & Interop (NEXT) -- ⏳ Test with Mastodon instances -- ⏳ Test with Pleroma/Akkoma instances -- ⏳ Test with Lemmy instances -- ⏳ Verify WebFinger and actor discovery -- ⏳ Test activity delivery and processing - -## Implementation Details - -### Core Services - -#### 1. ActivityPubKeyService -- Generates RSA 2048-bit key pairs for ActivityPub -- Signs data with private key -- Verifies signatures with public key -- Key stored in `SnPublisher.Meta["private_key"]` and `["public_key"]` - -#### 2. ActivityPubSignatureService -- Verifies incoming HTTP Signature headers -- Signs outgoing HTTP requests -- Manages key retrieval and storage -- Builds signing strings according to ActivityPub spec - -#### 3. ActivityPubActivityProcessor -- Processes all incoming activity types -- Follow: Creates relationship, sends Accept -- Accept: Updates relationship to accepted state -- Reject: Updates relationship to rejected state -- Create: Stores federated content -- Like: Records like reaction -- Announce: Increments boost count -- Undo: Reverts previous actions -- Delete: Soft-deletes federated content -- Update: Marks content as edited - -#### 4. ActivityPubDeliveryService -- Sends Follow activities to remote instances -- Sends Accept activities in response to follows -- Sends Create activities (posts) to followers -- Sends Like activities to remote instances -- Sends Undo activities -- Fetches remote actor profiles on-demand - -### Data Flow - -#### Incoming Activity Flow -``` -Remote Server → HTTP Signature Verification → Activity Type → Specific Handler - ↓ - Database Update & Response -``` - -#### Outgoing Activity Flow -``` -Local Action → Create Activity → Sign with Key → Send to Followers' Inboxes - ↓ - Track Status & Retry -``` - -## Configuration - -Add to `appsettings.json`: - -```json -{ - "ActivityPub": { - "Domain": "your-domain.com", - "EnableFederation": true - } -} -``` - -## Database Migration - -To apply the migration: - -```bash -cd DysonNetwork.Sphere -dotnet ef database update -``` - -## Testing - -### WebFinger -```bash -curl "https://your-domain.com/.well-known/webfinger?resource=acct:username@your-domain.com" -``` - -### Actor Profile -```bash -curl -H "Accept: application/activity+json" https://your-domain.com/activitypub/actors/username -``` - -### Outbox -```bash -curl -H "Accept: application/activity+json" https://your-domain.com/activitypub/actors/username/outbox -``` - -## Notes - -- All models follow the existing Solar Network patterns (ModelBase, NodaTime, JSON columns) -- Controllers use standard ASP.NET Core patterns with dependency injection -- Database uses PostgreSQL with JSONB for flexible metadata storage -- Migration follows existing naming conventions -- Soft delete is enabled on all models - -## References - -- [ActivityPub W3C Recommendation](https://www.w3.org/TR/activitypub/) -- [ActivityStreams 2.0](https://www.w3.org/TR/activitystreams-core/) -- [WebFinger RFC 7033](https://tools.ietf.org/html/rfc7033) -- [Mastodon Federation Documentation](https://docs.joinmastodon.org/spec/activitypub/) - -## TODOs - -- [ ] Implement HTTP Signature verification middleware -- [ ] Create activity processor service -- [ ] Implement activity queue and retry logic -- [ ] Add key generation for Publishers -- [ ] Implement content conversion between formats -- [ ] Add inbox background worker -- [ ] Add outbox delivery worker -- [ ] Implement relationship management logic -- [ ] Add moderation tools for federated content -- [ ] Add federation metrics and monitoring -- [ ] Write comprehensive tests diff --git a/docs/activitypub/ACTIVITYPUB_PLAN.md b/docs/activitypub/ACTIVITYPUB_PLAN.md deleted file mode 100644 index b66d81d8..00000000 --- a/docs/activitypub/ACTIVITYPUB_PLAN.md +++ /dev/null @@ -1,197 +0,0 @@ -🛠️ ActivityPub 接入 Solar Network 的分步清单 - -⸻ - -🧱 1. 准备 & 设计阶段 - -1.1 理解 ActivityPub 的核心概念 -• Actor / Object / Activity / Collection -• Outbox / Inbox / Followers 列表 -ActivityPub 是使用 JSON-LD + ActivityStreams 2.0 来描述社交行为的规范。  - -1.2 映射你现有的 Solar Domain 结构 - -把你现在 Solar Network 的用户、帖子、关注、点赞等: -• 映射为 ActivityPub 的 Actor / Note / Follow / Like 等 -• 明确本地模型与 ActivityStreams 对应关系 - -比如: -• Solar User → ActivityPub Actor -• Post → ActivityPub Note/Object -• Like → ActivityPub Like Activity -这一步是关键的领域建模设计。 - -⸻ - -🚪 2. Actor 发现与必要入口 - -2.1 实现 WebFinger - -为每个用户提供 WebFinger endpoint: - -GET /.well-known/webfinger?resource=acct:@ - -用来让远端服务器查出 actor 细节(包括 inbox/outbox URL)。 - -2.2 Actor 资源 URL - -确保每个用户有一个全局可访问的 URL,例如: - -https://solar.io/users/alice - -并在其 JSON-LD 中包含: -• inbox -• outbox -• followers -• following -这些是 ActivityPub 基础通信的入口。  - -⸻ - -📮 3. 核心协议实现 - -3.1 Inbox / Outbox 接口 - -Inbox(接收来自其他实例的 Activity) -Outbox(本地用户发布 Activity 的出口) - -Outbox 需要: -• 生成 activity JSON(Create、Follow、Like 等) -• 存储至本地数据库 -• 推送到各 follower 的 Inbox - -Inbox 需要: -• 接收并 parse Activity -• 验证签名 -• 处理活动(如接受 Follow,记录远程 Post 等) - -注意: -• 请求需要验证 HTTP Signatures(远端服务器签名)。  -• 必须满足 ActivityPub 规范对字段的要求。 - -⸻ - -🔐 4. 安全与签名 - -4.1 Actor Keys - -每个 Actor 对应一对 RSA / Ed25519 密钥: -• 私钥用于签名发送到其它服务器的请求 -• 公钥发布在 Actor JSON 中供对方验证 - -远端服务器发送到你的 Inbox 时,需要: -• 使用对方的公钥验证签名 - -HTTP Signatures 是服务器间通信安全的一部分,防止伪造请求。  - -⸻ - -🌐 5. 实现联邦逻辑 - -5.1 关注逻辑 - -处理: -• Follow Activity -• Accept / Reject Activity -• 更新本地 followers / following 数据 - -实现流程参考:1. 本地用户发起 Follow 2. 推送 Follow 到远端 Inbox 3. 等待远端发送 Accept 或 Reject - -5.2 推送 content(联邦同步) - -当本地用户发布内容时: -• 从 Outbox 取出 Create Activity -• 发送到所有远端 followers 的 Inbox -注意:你可以缓存远端 followers 数据表来减少重复请求。 - -⸻ - -📡 6. 消息处理与存储 - -6.1 本地对象缓存 - -对于接收到的远端内容(Post / Note / Like 等): -• 需要保存到 Solar 的数据库 -• 供 UI / API 生成用户时间线 -这使得 Solar 能把远端联邦内容与本地内容统一展示。 - -6.2 处理 Collections - -ActivityPub 定义了 Collection 类型用于: -• followers 列表 -• liked 列表 -• outbox、inbox - -你需要实现这些集合的获取与分页逻辑。 - -⸻ - -🔁 7. 与现有 Solar Network API 协调 - -你可能已经有本地的帖子、用户 API。那么: -• 把这套 API 与 ActivityPub 同步层绑定 -• 决定哪些内容对外发布 -• 决定哪些 Activity 类型需要响应 - -比如: - -Solar Post Create -> 生成 ActivityPub Create Note -> 发往联邦 - -⸻ - -📦 8. 测试与兼容性 - -8.1 与现存联邦测试 - -用已存在的 ActivityPub 实例测试兼容性: -• Mastodon -• Pleroma -• Lemmy 等 - -检查: -• 对方是否能关注 Solar 用户 -• Solar 是否能接收远端内容 - -ActivityPub 规范(W3C Recommendation)有详细规范流包括: -• Server to Server API -你最重要的目标是与现存实例互操作。  - -⸻ - -🧪 9. UX & 监控支持 - -9.1 用户显示远端内容 - -从 Inbox 收到内容后: -• 如何展示在 Solar UI -• 链接远端用户的展示名 / 头像 - -9.2 监控 & 审计 -• 失败的推送 -• 无法验证签名的请求 -• 阻止 spam / 恶意 Activity - -⸻ - -🏁 10. 逐步推进 - -建议按阶段 rollout: - -阶段 目标 -Stage 1 实现 Actor / WebFinger / Outbox / Inbox 基本框架 -Stage 2 支持 Follow / Accept / Reject Activity -Stage 3 支持 Create / Like / Announce -Stage 4 与远端实例互联测试 -Stage 5 UI & Feed 统一显示本地 + 联邦内容 - -⸻ - -📌 小结 - -核心步骤总结:1. 映射 Solar Network 数据模型到 ActivityPub 2. 实现 WebFinger + Actor JSON-LD 3. 实现 Inbox 和 Outbox endpoints 4. 管理 Actor Keys 与 HTTP Signatures 5. 处理关注/发帖/点赞等 Activity 6. 推送到远端 / 接收远端同步 7. 将远端内容存入 Solar 并展示 8. 测试与现有 Fediverse 实例互通 - -这套步骤覆盖了 ActivityPub 协议必须实现的点和实际联邦要处理的逻辑。  - -⸻ - -如果你想,我可以进一步展开 Solar Network 对应的具体 API 设计模板(包括 Inbox / Outbox 的 REST 定义与 JSON 输出示例),甚至帮你写 可运行的 Go / .NET 样例代码。你希望从哪一部分开始深入? diff --git a/docs/activitypub/ACTIVITYPUB_SUMMARY.md b/docs/activitypub/ACTIVITYPUB_SUMMARY.md deleted file mode 100644 index 4f29d9bd..00000000 --- a/docs/activitypub/ACTIVITYPUB_SUMMARY.md +++ /dev/null @@ -1,273 +0,0 @@ -# ActivityPub Implementation Summary - -## What Has Been Implemented - -### 1. Database Models ✅ -All models located in `DysonNetwork.Shared/Models/`: - -| Model | Purpose | Key Features | -|--------|---------|--------------| -| `SnFediverseInstance` | Track fediverse servers | Domain blocking, metadata, activity tracking | -| `SnFediverseActor` | Remote user profiles | Keys, inbox/outbox URLs, relationships | -| `SnFediverseContent` | Federated posts/notes | Multiple content types, attachments, mentions, tags | -| `SnFediverseActivity` | Activity tracking | All activity types, processing status, raw data | -| `SnFediverseRelationship` | Follow relationships | State machine, muting/blocking | -| `SnFediverseReaction` | Federated reactions | Likes, emoji reactions | - -### 2. Database Migrations ✅ -- `20251228120000_AddActivityPubModels.cs` - Core ActivityPub tables -- `20251228130000_AddPublisherMetaForActivityPubKeys.cs` - Publisher metadata for keys - -### 3. Core Services ✅ - -#### ActivityPubKeyService -- **Location**: `DysonNetwork.Sphere/ActivityPub/ActivityPubKeyService.cs` -- **Responsibilities**: - - Generate RSA 2048-bit key pairs - - Sign data with private key - - Verify signatures with public key -- **Key Storage**: Keys stored in `SnPublisher.Meta` - -#### ActivityPubSignatureService -- **Location**: `DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs` -- **Responsibilities**: - - Verify incoming HTTP Signature headers - - Sign outgoing HTTP requests - - Build signing strings per ActivityPub spec - - Manage key retrieval for actors -- **Signature Algorithm**: RSA-SHA256 - -#### ActivityPubActivityProcessor -- **Location**: `DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs` -- **Supported Activities**: - - ✅ Follow - Creates relationship, sends Accept - - ✅ Accept - Updates relationship to accepted - - ✅ Reject - Updates relationship to rejected - - ✅ Create - Stores federated content - - ✅ Like - Records like reaction - - ✅ Announce - Increments boost count - - ✅ Undo - Reverts previous actions - - ✅ Delete - Soft-deletes federated content - - ✅ Update - Marks content as edited - -#### ActivityPubDeliveryService -- **Location**: `DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs` -- **Outgoing Activities**: - - ✅ Follow - Send to remote actors - - ✅ Accept - Respond to follow requests - - ✅ Create - Send new posts to followers - - ✅ Like - Send to remote instances - - ✅ Undo - Undo previous actions -- **Features**: - - HTTP signature signing - - Remote actor fetching - - Follower discovery - -### 4. API Controllers ✅ - -#### WebFingerController -- **Location**: `DysonNetwork.Sphere/ActivityPub/WebFingerController.cs` -- **Endpoints**: - - `GET /.well-known/webfinger?resource=acct:@` -- **Purpose**: Allow remote instances to discover local actors - -#### ActivityPubController -- **Location**: `DysonNetwork.Sphere/ActivityPub/ActivityPubController.cs` -- **Endpoints**: - - `GET /activitypub/actors/{username}` - Actor profile in JSON-LD - - `GET /activitypub/actors/{username}/outbox` - Public posts - - `POST /activitypub/actors/{username}/inbox` - Receive activities -- **Features**: - - Public key in actor profile - - ActivityPub JSON-LD responses - - HTTP signature verification on inbox - - Activity processing pipeline - -### 5. Model Updates ✅ -- Added `Meta` field to `SnPublisher` for storing ActivityPub keys -- All models follow existing Solar Network patterns - -## How It Works - -### Incoming Activity Flow -``` -1. Remote server sends POST to /inbox -2. HTTP Signature is verified -3. Activity type is identified -4. Specific handler processes activity: - - Follow: Create relationship, send Accept - - Create: Store content - - Like: Record reaction - - etc. -5. Database is updated -6. Response sent -``` - -### Outgoing Activity Flow -``` -1. Local action occurs (post, like, follow) -2. Activity is created in ActivityPub format -3. Remote followers are discovered -4. HTTP request is signed with publisher's private key -5. Activity sent to each follower's inbox -6. Status logged -``` - -### Key Management -``` -1. Publisher creates post/follows -2. Check if keys exist in Publisher.Meta -3. If not, generate RSA 2048-bit key pair -4. Store keys in Publisher.Meta -5. Use keys for signing -``` - -## Configuration - -Add to `appsettings.json`: -```json -{ - "ActivityPub": { - "Domain": "your-domain.com", - "EnableFederation": true - } -} -``` - -## API Endpoints - -### WebFinger -```bash -GET /.well-known/webfinger?resource=acct:username@domain.com -Accept: application/jrd+json -``` - -### Actor Profile -```bash -GET /activitypub/actors/username -Accept: application/activity+json -``` - -### Outbox -```bash -GET /activitypub/actors/username/outbox -Accept: application/activity+json -``` - -### Inbox -```bash -POST /activitypub/actors/username/inbox -Content-Type: application/activity+json -Signature: keyId="...",algorithm="...",headers="...",signature="..." -``` - -## Database Schema - -### Fediverse Tables -- `fediverse_instances` - Server metadata and blocking -- `fediverse_actors` - Remote actor profiles -- `fediverse_contents` - Federated posts/notes -- `fediverse_activities` - Activity tracking -- `fediverse_relationships` - Follow relationships -- `fediverse_reactions` - Federated reactions - -### Publisher Enhancement -- Added `publishers.meta` JSONB column for key storage - -## Next Steps - -### Immediate (Ready for Testing) -- Apply database migrations -- Test WebFinger with a Mastodon instance -- Test follow/unfollow with another instance -- Test receiving posts from federated timeline - -### Short Term -- Add HTTP Signature verification middleware -- Implement activity queue with retry logic -- Add background worker for processing queued activities -- Add metrics and monitoring -- Implement local content display in timelines - -### Long Term -- Add Media support for federated content -- Implement content filtering -- Add moderation tools for federated content -- Support more activity types -- Implement instance block list management - -## Compatibility - -The implementation follows: -- ✅ [ActivityPub W3C Recommendation](https://www.w3.org/TR/activitypub/) -- ✅ [ActivityStreams 2.0](https://www.w3.org/TR/activitystreams-core/) -- ✅ [WebFinger RFC 7033](https://tools.ietf.org/html/rfc7033) -- ✅ [HTTP Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) - -## Testing - -### Local Testing -```bash -# 1. Apply migrations -cd DysonNetwork.Sphere -dotnet ef database update - -# 2. Test WebFinger -curl "http://localhost:5000/.well-known/webfinger?resource=acct:username@localhost" - -# 3. Test Actor -curl -H "Accept: application/activity+json" http://localhost:5000/activitypub/actors/username -``` - -### Federation Testing -1. Set up a Mastodon instance (or use a public one) -2. Follow a Mastodon user from Solar Network -3. Create a post on Solar Network -4. Verify it appears on Mastodon timeline - -## Architecture Decisions - -1. **Key Storage**: Using `SnPublisher.Meta` JSONB field for flexibility -2. **Content Storage**: Federated content stored separately from local posts -3. **Relationship State**: Implemented with explicit states (Pending, Accepted, Rejected) -4. **Signature Algorithm**: RSA-SHA256 for compatibility -5. **Activity Processing**: Synchronous for now, can be made async with queue -6. **Content Types**: Support for Note, Article initially (can expand) - -## Notes - -- All ActivityPub communication uses HTTP Signatures -- Private keys never leave the server -- Public keys are published in actor profiles -- Soft delete is enabled on all federated models -- Failed activity deliveries are logged but not retried (future enhancement) -- Content is federated only when visibility is Public - -## Files Created/Modified - -### New Files -- `DysonNetwork.Shared/Models/FediverseInstance.cs` -- `DysonNetwork.Shared/Models/FediverseActor.cs` -- `DysonNetwork.Shared/Models/FediverseContent.cs` -- `DysonNetwork.Shared/Models/FediverseActivity.cs` -- `DysonNetwork.Shared/Models/FediverseRelationship.cs` -- `DysonNetwork.Shared/Models/FediverseReaction.cs` -- `DysonNetwork.Sphere/ActivityPub/WebFingerController.cs` -- `DysonNetwork.Sphere/ActivityPub/ActivityPubController.cs` -- `DysonNetwork.Sphere/ActivityPub/ActivityPubKeyService.cs` -- `DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs` -- `DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs` -- `DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs` -- `DysonNetwork.Sphere/Migrations/20251228120000_AddActivityPubModels.cs` -- `DysonNetwork.Sphere/Migrations/20251228130000_AddPublisherMetaForActivityPubKeys.cs` - -### Modified Files -- `DysonNetwork.Shared/Models/Publisher.cs` - Added Meta field -- `DysonNetwork.Sphere/AppDatabase.cs` - Added DbSets for ActivityPub -- `DysonNetwork.Sphere/Startup/ServiceCollectionExtensions.cs` - Registered ActivityPub services - -## References - -- [ActivityPub Implementation Guide](./ACTIVITYPUB_IMPLEMENTATION.md) -- [ActivityPub Plan](./ACTIVITYPUB_PLAN.md) -- [Solar Network Architecture](./README.md) diff --git a/docs/activitypub/ACTIVITYPUB_TESTING_GUIDE.md b/docs/activitypub/ACTIVITYPUB_TESTING_GUIDE.md deleted file mode 100644 index ea94bb23..00000000 --- a/docs/activitypub/ACTIVITYPUB_TESTING_GUIDE.md +++ /dev/null @@ -1,820 +0,0 @@ -# ActivityPub Testing Guide for Solar Network - -This guide will help you test the ActivityPub implementation in Solar Network, starting with a self-hosted instance and then moving to a real instance. - -## Prerequisites - -- ✅ Solar Network codebase with ActivityPub implementation -- ✅ Docker installed (for running Mastodon/Fediverse instances) -- ✅ PostgreSQL database running -- ✅ `.NET 10` SDK - -## Part 1: Set Up a Self-Hosted Test Instance - -### Option A: Using Mastodon (Recommended for Compatibility) - -#### 1. Create a Docker Compose File - -Create `docker-compose.mastodon-test.yml`: - -```yaml -version: '3' - -services: - db: - restart: always - image: postgres:14-alpine - environment: - POSTGRES_USER: mastodon - POSTGRES_PASSWORD: mastodon_password - POSTGRES_DB: mastodon - networks: - - mastodon_network - healthcheck: - test: ["CMD", "pg_isready", "-U", "mastodon"] - interval: 5s - retries: 5 - - redis: - restart: always - image: redis:7-alpine - networks: - - mastodon_network - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 5s - retries: 5 - - es: - restart: always - image: docker.elastic.co/elasticsearch:8.10.2 - environment: - - "discovery.type=single-node" - - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - - "xpack.security.enabled=false" - networks: - - mastodon_network - healthcheck: - test: ["CMD-SHELL", "curl -silent http://localhost:9200/_cluster/health || exit 1"] - interval: 10s - retries: 10 - - web: - restart: always - image: tootsuite/mastodon:latest - env_file: .env.mastodon - command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" - ports: - - "3001:3000" - depends_on: - - db - - redis - - es - networks: - - mastodon_network - volumes: - - ./mastodon-data/public:/mastodon/public/system - - streaming: - restart: always - image: tootsuite/mastodon:latest - env_file: .env.mastodon - command: node ./streaming - ports: - - "4000:4000" - depends_on: - - db - - redis - networks: - - mastodon_network - - sidekiq: - restart: always - image: tootsuite/mastodon:latest - env_file: .env.mastodon - command: bundle exec sidekiq - depends_on: - - db - - redis - networks: - - mastodon_network - -networks: - mastodon_network: - driver: bridge -``` - -#### 2. Create Environment File - -Create `.env.mastodon`: - -```bash -# Federation -LOCAL_DOMAIN=mastodon.local -LOCAL_HTTPS=false - -# Database -DB_HOST=db -DB_PORT=5432 -DB_USER=mastodon -DB_NAME=mastodon -DB_PASS=mastodon_password - -# Redis -REDIS_HOST=redis -REDIS_PORT=6379 - -# Elasticsearch -ES_ENABLED=true -ES_HOST=es -ES_PORT=9200 - -# Secrets (generate these!) -SECRET_KEY_BASE=change_me_to_a_random_string_at_least_32_chars -OTP_SECRET=change_me_to_another_random_string - -# Defaults -SINGLE_USER_MODE=false -DEFAULT_LOCALE=en -``` - -**Generate secrets:** -```bash -# Run these to generate random secrets -openssl rand -base64 32 -``` - -#### 3. Start Mastodon - -```bash -docker-compose -f docker-compose.mastodon-test.yml up -d - -# Check logs -docker-compose -f docker-compose.mastodon-test.yml logs -f web -``` - -Wait for the web service to be healthy (may take 2-5 minutes). - -#### 4. Create a Mastodon Account - -```bash -# Run this command to create an admin account -docker-compose -f docker-compose.mastodon-test.yml exec web \ - bin/tootctl accounts create \ - testuser \ - testuser@mastodon.local \ - --email=test@example.com \ - --confirmed \ - --role=admin \ - --approve -``` - -Set password: `TestPassword123!` - -#### 5. Update Your /etc/hosts - -```bash -sudo nano /etc/hosts -``` - -Add: -``` -127.0.0.1 mastodon.local -127.0.0.1 solar.local -``` - -### Option B: Using GoToSocial (Lightweight Alternative) - -Create `docker-compose.gotosocial.yml`: - -```yaml -version: '3' - -services: - gotosocial: - image: superseriousbusiness/gotosocial:latest - environment: - - GTS_HOST=gotosocial.local - - GTS_ACCOUNT_DOMAIN=gotosocial.local - - GTS_PROTOCOL=http - - GTS_DB_TYPE=sqlite - - GTS_DB_ADDRESS=/gotosocial/data/sqlite.db - - GTS_STORAGE_LOCAL_BASE_PATH=/gotosocial/data/storage - ports: - - "3002:8080" - volumes: - - ./gotosocial-data:/gotosocial/data - -networks: - default: -``` - -Start it: -```bash -docker-compose -f docker-compose.gotosocial.yml up -d -``` - -Create account: -```bash -docker-compose -f docker-compose.gotosocial.yml exec gotosocial \ - /gotosocial/gotosocial admin account create \ - --username testuser \ - --email test@example.com \ - --password TestPassword123! -``` - -## Part 2: Configure Solar Network for Federation - -### 1. Update appsettings.json - -Edit `DysonNetwork.Sphere/appsettings.json`: - -```json -{ - "ActivityPub": { - "Domain": "solar.local", - "EnableFederation": true - }, - "Kestrel": { - "Endpoints": { - "Http": { - "Url": "http://solar.local:5000" - } - } - } -} -``` - -### 2. Update /etc/hosts - -Add both instances: -``` -127.0.0.1 mastodon.local -127.0.0.1 solar.local -127.0.0.1 gotosocial.local -``` - -### 3. Apply Database Migrations - -```bash -cd DysonNetwork.Sphere -dotnet ef database update -``` - -### 4. Start Solar Network - -```bash -dotnet run --project DysonNetwork.Sphere -``` - -Solar Network should now be running on `http://solar.local:5000` - -## Part 3: Create Test Users - -### In Solar Network - -1. Open http://solar.local:5000 (or your web interface) -2. Create a new account/publisher named `solaruser` -3. Note down the publisher ID for later - -**Or via API** (if you have an existing account): - -```bash -# First, create a publisher in Solar Network -curl -X POST http://solar.local:5000/api/publishers \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{ - "name": "solaruser", - "nick": "Solar User", - "bio": "Testing ActivityPub federation!", - "type": 0 - }' -``` - -### In Mastodon - -Open http://mastodon.local:3001 and log in with: -- Username: `testuser` -- Password: `TestPassword123!` - -## Part 4: Test Federation Scenarios - -### Test 1: WebFinger Discovery - -**Goal**: Verify Solar Network is discoverable - -```bash -# Query Solar Network's WebFinger endpoint -curl -v "http://solar.local:5000/.well-known/webfinger?resource=acct:solaruser@solar.local" - -# Expected response (200 OK): -{ - "subject": "acct:solaruser@solar.local", - "links": [ - { - "rel": "self", - "type": "application/activity+json", - "href": "https://solar.local:5000/activitypub/actors/solaruser" - }, - { - "rel": "http://webfinger.net/rel/profile-page", - "type": "text/html", - "href": "https://solar.local:5000/users/solaruser" - } - ] -} -``` - -### Test 2: Fetch Actor Profile - -**Goal**: Get ActivityPub actor JSON - -```bash -# Fetch Solar Network actor from Mastodon -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/solaruser - -# Expected response includes: -{ - "@context": ["https://www.w3.org/ns/activitystreams"], - "id": "https://solar.local:5000/activitypub/actors/solaruser", - "type": "Person", - "preferredUsername": "solaruser", - "inbox": "https://solar.local:5000/activitypub/actors/solaruser/inbox", - "outbox": "https://solar.local:5000/activitypub/actors/solaruser/outbox", - "followers": "https://solar.local:5000/activitypub/actors/solaruser/followers", - "publicKey": { - "id": "https://solar.local:5000/activitypub/actors/solaruser#main-key", - "owner": "https://solar.local:5000/activitypub/actors/solaruser", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n..." - } -} -``` - -### Test 3: Follow from Mastodon to Solar Network - -**Goal**: Mastodon user follows Solar Network user - -1. **In Mastodon**: - - Go to http://mastodon.local:3001 - - In search bar, type: `@solaruser@solar.local` - - Click the follow button - -2. **Verify in Solar Network**: -```bash -# Check database for relationship -psql -d dyson_network -c \ - "SELECT * FROM fediverse_relationships WHERE is_local_actor = true;" -``` - -3. **Check Solar Network logs**: - Should see: - ``` - Processing activity type: Follow from actor: ... - Processed follow from ... to ... - ``` - -4. **Verify Mastodon receives Accept**: - - Check Mastodon logs for Accept activity - - Verify follow appears as accepted in Mastodon - -### Test 4: Follow from Solar Network to Mastodon - -**Goal**: Solar Network user follows Mastodon user - -You'll need to call the ActivityPub delivery service: - -```bash -# Via API (you'll need to implement this endpoint): -curl -X POST http://solar.local:5000/api/activitypub/follow \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{ - "targetActorUri": "http://mastodon.local:3001/users/testuser" - }' -``` - -**Or test directly with curl** (simulating a Follow activity): - -```bash -# Create a Follow activity -curl -X POST http://solar.local:5000/activitypub/actors/solaruser/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{ - "@context": "https://www.w3.org/ns/activitystreams", - "id": "http://mastodon.local:3001/test-follow-activity", - "type": "Follow", - "actor": "http://mastodon.local:3001/users/testuser", - "object": "https://solar.local:5000/activitypub/actors/solaruser" - }' -``` - -### Test 5: Create a Post in Solar Network - -**Goal**: Post federates to Mastodon - -1. **Create a post via Solar Network API**: -```bash -curl -X POST http://solar.local:5000/api/posts \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{ - "content": "Hello fediverse! Testing ActivityPub from Solar Network! 🚀", - "visibility": 0, - "publisherId": "PUBLISHER_ID" - }' -``` - -2. **Wait a few seconds** - -3. **Check in Mastodon**: - - Go to http://mastodon.local:3001 - - The post should appear in the federated timeline - - It should show `@solaruser@solar.local` as the author - -4. **Verify Solar Network logs**: - ``` - Successfully sent activity to http://mastodon.local:3001/inbox - ``` - -### Test 6: Like from Mastodon - -**Goal**: Mastodon user likes a Solar Network post - -1. **In Mastodon**: - - Find the Solar Network post - - Click the favorite/like button - -2. **Verify in Solar Network**: -```bash -psql -d dyson_network -c \ - "SELECT * FROM fediverse_reactions;" -``` - -3. **Check Solar Network logs**: - ``` - Processing activity type: Like from actor: ... - Processed like from ... - ``` - -### Test 7: Reply from Mastodon - -**Goal**: Reply federates to Solar Network - -1. **In Mastodon**: - - Reply to the Solar Network post - - Write: "@solaruser Nice to meet you!" - -2. **Verify in Solar Network**: -```bash -psql -d dyson_network -c \ - "SELECT * FROM fediverse_contents WHERE in_reply_to IS NOT NULL;" -``` - -## Part 5: Debugging and Troubleshooting - -### Enable Detailed Logging - -Edit `appsettings.json`: - -```json -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "DysonNetwork.Sphere.ActivityPub": "Trace" - } - } -} -``` - -### Check Database State - -```bash -# Check actors -psql -d dyson_network -c \ - "SELECT uri, username, display_name FROM fediverse_actors;" - -# Check contents -psql -d dyson_network -c \ - "SELECT uri, type, content FROM fediverse_contents;" - -# Check relationships -psql -d dyson_network -c \ - "SELECT * FROM fediverse_relationships;" - -# Check activities -psql -d dyson_network -c \ - "SELECT type, status, error_message FROM fediverse_activities;" - -# Check failed activities -psql -d dyson_network -c \ - "SELECT * FROM fediverse_activities WHERE status = 3;" # 3 = Failed -``` - -### Common Issues - -#### Issue: "Failed to verify signature" - -**Cause**: HTTP Signature verification failed - -**Solutions**: -1. Check the signature header format -2. Verify public key matches actor's keyId -3. Ensure Date header is within 5 minutes -4. Check host header matches request URL - -#### Issue: "Target actor or inbox not found" - -**Cause**: Remote actor not fetched yet - -**Solutions**: -1. Manually fetch the actor first -2. Check actor URL is correct -3. Verify remote instance is accessible - -#### Issue: "Content already exists" - -**Cause**: Duplicate activity received - -**Solutions**: -1. This is normal - deduplication is working -2. Check if content appears correctly - -#### Issue: CORS errors when testing from browser - -**Cause**: Browser blocking cross-origin requests - -**Solutions**: -1. Use curl for API testing -2. Or disable CORS in development -3. Test directly from Mastodon interface - -### View HTTP Signatures - -For debugging, you can inspect the signature: - -```bash -# From Mastodon to Solar Network -curl -v -X POST http://solar.local:5000/activitypub/actors/solaruser/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{"type":"Follow",...}' -``` - -Look for the `Signature` header in the output. - -### Test HTTP Signature Verification Manually - -Create a test script `test-signature.js`: - -```javascript -const crypto = require('crypto'); - -// Test signature verification -const publicKey = `-----BEGIN PUBLIC KEY----- -... ------END PUBLIC KEY-----`; - -const signingString = `(request-target): post /activitypub/actors/solaruser/inbox -host: solar.local:5000 -date: ${new Date().toUTCString()} -content-length: ...`; - -const signature = '...'; - -const verify = crypto.createVerify('SHA256'); -verify.update(signingString); -const isValid = verify.verify(publicKey, signature, 'base64'); - -console.log('Signature valid:', isValid); -``` - -## Part 6: Test with a Real Instance - -### Preparing for Public Federation - -1. **Get a real domain** (e.g., via ngrok or a VPS) - -```bash -# Using ngrok for testing -ngrok http 5000 - -# This gives you: https://random-id.ngrok-free.app -``` - -2. **Update Solar Network config**: - -```json -{ - "ActivityPub": { - "Domain": "your-domain.com", - "EnableFederation": true - } -} -``` - -3. **Update DNS** (if using real domain): - - Add A record pointing to your server - - Configure HTTPS (required for production federation) - -4. **Test WebFinger with your domain**: - -```bash -curl "https://your-domain.com/.well-known/webfinger?resource=acct:username@your-domain.com" -``` - -### Test with Mastodon.social - -1. **Create a Mastodon.social account** - - Go to https://mastodon.social - - Sign up for a test account - -2. **Search for your Solar Network user**: - - In Mastodon.social search: `@username@your-domain.com` - - Click follow - -3. **Create a post in Solar Network** - - Should appear in Mastodon.social - -4. **Reply from Mastodon.social** - - Should appear in Solar Network - -### Test with Other Instances - -- **Pleroma**: Similar to Mastodon, good for testing -- **Lemmy**: For testing community features (later) -- **Pixelfed**: For testing media posts -- **PeerTube**: For testing video content (later) - -## Part 7: Verification Checklist - -### Self-Hosted Instance Tests - -- [ ] WebFinger returns correct actor links -- [ ] Actor profile has all required fields -- [ ] Follow from Mastodon to Solar Network works -- [ ] Follow from Solar Network to Mastodon works -- [ ] Accept activity sent back to Mastodon -- [ ] Posts from Solar Network appear in Mastodon timeline -- [ ] Posts from Mastodon appear in Solar Network database -- [ ] Likes from Mastodon appear in Solar Network -- [ ] Replies from Mastodon appear in Solar Network -- [ ] Keys are properly generated and stored -- [ ] HTTP signatures are correctly verified -- [ ] Outbox returns public posts - -### Real Instance Tests - -- [ ] Domain is publicly accessible -- [ ] HTTPS is working (or HTTP for local testing) -- [ ] WebFinger works with your domain -- [ ] Actor is discoverable from other instances -- [ ] Posts federate to public instances -- [ ] Users can follow across instances -- [ ] Timelines show federated content - -## Part 8: Monitoring During Tests - -### Check Solar Network Logs - -```bash -# Follow logs in real-time -dotnet run --project DysonNetwork.Sphere | grep -i activitypub -``` - -### Check Mastodon Logs - -```bash -docker-compose -f docker-compose.mastodon-test.yml logs -f web | grep -i federation -``` - -### Monitor Database Activity - -```bash -# Watch activity table -watch -n 2 'psql -d dyson_network -c "SELECT type, status, created_at FROM fediverse_activities ORDER BY created_at DESC LIMIT 10;"' -``` - -### Check Network Traffic - -```bash -# Monitor HTTP requests -tcpdump -i lo port 5000 or port 3001 -A -``` - -## Part 9: Advanced Testing - -### Test HTTP Signature Fallbacks - -Test with various signature headers: - -```bash -# With Date header -curl -H "Date: $(date -u +%a,\ %d\ %b\ %Y\ %T\ GMT)" ... - -# With Digest header -curl -H "Digest: SHA-256=$(echo -n '{}' | openssl dgst -sha256 -binary | base64)" ... - -# Multiple signed headers -curl -H "Signature: keyId=\"...\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest\",signature=\"...\"" ... -``` - -### Test Rate Limiting - -Send multiple requests quickly: - -```bash -for i in {1..10}; do - curl -X POST http://solar.local:5000/activitypub/actors/solaruser/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{"type":"Create",...}' -done -``` - -### Test Large Posts - -Send post with attachments: - -```bash -curl -X POST http://solar.local:5000/api/posts \ - -H "Content-Type: application/json" \ - -d '{ - "content": "A post with an image", - "attachments": [{"id": "file-id"}], - "visibility": 0 - }' -``` - -## Part 10: Cleanup - -### Stop Test Instances - -```bash -# Stop Mastodon -docker-compose -f docker-compose.mastodon-test.yml down - -# Stop GoToSocial -docker-compose -f docker-compose.gotosocial.yml down - -# Remove data volumes -docker-compose -f docker-compose.mastodon-test.yml down -v -``` - -### Reset Solar Network Database - -```bash -# Warning: This deletes all data! -cd DysonNetwork.Sphere -dotnet ef database drop -dotnet ef database update -``` - -### Remove /etc/hosts Entries - -```bash -sudo nano /etc/hosts - -# Remove these lines: -# 127.0.0.1 mastodon.local -# 127.0.0.1 solar.local -# 127.0.0.1 gotosocial.local -``` - -## Next Steps After Testing - -1. **Fix any issues found during testing** -2. **Add retry logic for failed deliveries** -3. **Implement activity queue for async processing** -4. **Add monitoring and metrics** -5. **Test with more instances (Pleroma, Pixelfed, etc.)** -6. **Add support for more activity types** -7. **Improve error handling and logging** -8. **Add admin interface for managing federation** - -## Useful Tools - -### ActivityPub Testing Tools -- [ActivityPub Playground](https://swicth.github.io/activity-pub-playground/) -- [FediTest](https://feditest.com/) -- [FediVerse.net](https://fedi.net/) - -### HTTP Testing -- [curl](https://curl.se/) -- [httpie](https://httpie.io/) -- [Postman](https://www.postman.com/) - -### JSON Inspection -- [jq](https://stedolan.github.io/jq/) -- [jsonpath.com](https://jsonpath.com/) - -### Network Debugging -- [Wireshark](https://www.wireshark.org/) -- [tcpdump](https://www.tcpdump.org/) - -## References - -- [ActivityPub W3C Spec](https://www.w3.org/TR/activitypub/) -- [HTTP Signatures Draft](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) -- [WebFinger RFC 7033](https://tools.ietf.org/html/rfc7033) -- [Mastodon Federation Documentation](https://docs.joinmastodon.org/admin/federation/) diff --git a/docs/activitypub/ACTIVITYPUB_TESTING_HELPER_API.md b/docs/activitypub/ACTIVITYPUB_TESTING_HELPER_API.md deleted file mode 100644 index 78e7acca..00000000 --- a/docs/activitypub/ACTIVITYPUB_TESTING_HELPER_API.md +++ /dev/null @@ -1,506 +0,0 @@ -# ActivityPub Testing Helper API - -This document describes helper endpoints for testing ActivityPub federation. - -## Purpose - -These endpoints allow you to manually trigger ActivityPub activities for testing purposes without implementing the full UI federation integration yet. - -## Helper Endpoints - -### 1. Send Follow Activity - -**Endpoint**: `POST /api/activitypub/test/follow` - -**Description**: Sends a Follow activity to a remote actor - -**Request Body**: -```json -{ - "targetActorUri": "http://mastodon.local:3001/users/testuser" -} -``` - -**Response**: -```json -{ - "success": true, - "activityId": "http://solar.local:5000/activitypub/activities/...", - "targetActor": "http://mastodon.local:3001/users/testuser" -} -``` - -### 2. Send Like Activity - -**Endpoint**: `POST /api/activitypub/test/like` - -**Description**: Sends a Like activity for a post (can be local or remote) - -**Request Body**: -```json -{ - "postId": "POST_ID", - "targetActorUri": "http://mastodon.local:3001/users/testuser" -} -``` - -**Response**: -```json -{ - "success": true, - "activityId": "http://solar.local:5000/activitypub/activities/..." -} -``` - -### 3. Send Announce (Boost) Activity - -**Endpoint**: `POST /api/activitypub/test/announce` - -**Description**: Boosts a post to followers - -**Request Body**: -```json -{ - "postId": "POST_ID" -} -``` - -### 4. Send Undo Activity - -**Endpoint**: `POST /api/activitypub/test/undo` - -**Description**: Undoes a previous activity - -**Request Body**: -```json -{ - "activityType": "Like", // or "Follow", "Announce" - "objectUri": "http://solar.local:5000/activitypub/objects/POST_ID" -} -``` - -### 5. Get Federation Status - -**Endpoint**: `GET /api/activitypub/test/status` - -**Description**: Returns current federation statistics - -**Response**: -```json -{ - "actors": { - "total": 5, - "local": 1, - "remote": 4 - }, - "contents": { - "total": 25, - "byType": { - "Note": 20, - "Article": 5 - } - }, - "relationships": { - "total": 8, - "accepted": 6, - "pending": 1, - "rejected": 1 - }, - "activities": { - "total": 45, - "byStatus": { - "Completed": 40, - "Pending": 3, - "Failed": 2 - }, - "byType": { - "Create": 20, - "Follow": 8, - "Accept": 6, - "Like": 5, - "Announce": 3, - "Undo": 2, - "Delete": 1 - } - } -} -``` - -### 6. Get Recent Activities - -**Endpoint**: `GET /api/activitypub/test/activities` - -**Query Parameters**: -- `limit`: Number of activities to return (default: 20) -- `type`: Filter by activity type (optional) - -**Response**: -```json -{ - "activities": [ - { - "id": "ACTIVITY_ID", - "type": "Follow", - "status": "Completed", - "actorUri": "http://mastodon.local:3001/users/testuser", - "objectUri": "http://solar.local:5000/activitypub/actors/solaruser", - "createdAt": "2024-01-15T10:30:00Z", - "errorMessage": null - } - ] -} -``` - -### 7. Get Actor Keys - -**Endpoint**: `GET /api/activitypub/test/actors/{username}/keys` - -**Description**: Returns the public/private key pair for a publisher - -**Response**: -```json -{ - "username": "solaruser", - "hasKeys": true, - "actorUri": "http://solar.local:5000/activitypub/actors/solaruser", - "publicKeyId": "http://solar.local:5000/activitypub/actors/solaruser#main-key", - "publicKey": "-----BEGIN PUBLIC KEY-----\n...", - "privateKeyStored": true -} -``` - -### 8. Test HTTP Signature - -**Endpoint**: `POST /api/activitypub/test/sign` - -**Description**: Test if a signature string is valid for a given public key - -**Request Body**: -```json -{ - "publicKey": "-----BEGIN PUBLIC KEY-----\n...", - "signingString": "(request-target): post /inbox\nhost: example.com\ndate: ...", - "signature": "..." -} -``` - -**Response**: -```json -{ - "valid": true, - "message": "Signature is valid" -} -``` - -## Controller Implementation - -Create `DysonNetwork.Sphere/ActivityPub/ActivityPubTestController.cs`: - -```csharp -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace DysonNetwork.Sphere.ActivityPub; - -[ApiController] -[Route("api/activitypub/test")] -[Authorize] // Require auth for testing -public class ActivityPubTestController( - AppDatabase db, - ActivityPubDeliveryService deliveryService, - ActivityPubKeyService keyService, - ActivityPubSignatureService signatureService, - IConfiguration configuration, - ILogger logger -) : ControllerBase -{ - [HttpPost("follow")] - public async Task TestFollow([FromBody] TestFollowRequest request) - { - var currentUser = GetCurrentUser(); - var publisher = await GetPublisherForUser(currentUser.Id); - - if (publisher == null) - return BadRequest("Publisher not found"); - - var success = await deliveryService.SendFollowActivityAsync( - publisher.Id, - request.TargetActorUri - ); - - return Ok(new - { - success, - targetActorUri = request.TargetActorUri, - publisherId = publisher.Id - }); - } - - [HttpPost("like")] - public async Task TestLike([FromBody] TestLikeRequest request) - { - var currentUser = GetCurrentUser(); - var publisher = await GetPublisherForUser(currentUser.Id); - - var success = await deliveryService.SendLikeActivityAsync( - request.PostId, - currentUser.Id, - request.TargetActorUri - ); - - return Ok(new { success, postId = request.PostId }); - } - - [HttpPost("announce")] - public async Task TestAnnounce([FromBody] TestAnnounceRequest request) - { - var post = await db.Posts.FindAsync(request.PostId); - if (post == null) - return NotFound(); - - var success = await deliveryService.SendCreateActivityAsync(post); - - return Ok(new { success, postId = request.PostId }); - } - - [HttpPost("undo")] - public async Task TestUndo([FromBody] TestUndoRequest request) - { - var currentUser = GetCurrentUser(); - var publisher = await GetPublisherForUser(currentUser.Id); - - if (publisher == null) - return BadRequest("Publisher not found"); - - var success = await deliveryService.SendUndoActivityAsync( - request.ActivityType, - request.ObjectUri, - publisher.Id - ); - - return Ok(new { success, activityType = request.ActivityType }); - } - - [HttpGet("status")] - public async Task GetStatus() - { - var totalActors = await db.FediverseActors.CountAsync(); - var localActors = await db.FediverseActors - .CountAsync(a => a.Uri.Contains("solar.local")); - - var totalContents = await db.FediverseContents.CountAsync(); - - var relationships = await db.FediverseRelationships - .GroupBy(r => r.State) - .Select(g => new { State = g.Key, Count = g.Count() }) - .ToListAsync(); - - var activitiesByStatus = await db.FediverseActivities - .GroupBy(a => a.Status) - .Select(g => new { Status = g.Key, Count = g.Count() }) - .ToListAsync(); - - var activitiesByType = await db.FediverseActivities - .GroupBy(a => a.Type) - .Select(g => new { Type = g.Key, Count = g.Count() }) - .ToListAsync(); - - return Ok(new - { - actors = new - { - total = totalActors, - local = localActors, - remote = totalActors - localActors - }, - contents = new - { - total = totalContents - }, - relationships = relationships.ToDictionary(r => r.State.ToString(), r => r.Count), - activities = new - { - byStatus = activitiesByStatus.ToDictionary(a => a.Status.ToString(), a => a.Count), - byType = activitiesByType.ToDictionary(a => a.Type.ToString(), a => a.Count) - } - }); - } - - [HttpGet("activities")] - public async Task GetActivities([FromQuery] int limit = 20, [FromQuery] string? type = null) - { - var query = db.FediverseActivities - .OrderByDescending(a => a.CreatedAt); - - if (!string.IsNullOrEmpty(type)) - { - query = query.Where(a => a.Type.ToString() == type); - } - - var activities = await query - .Take(limit) - .Select(a => new - { - a.Id, - a.Type, - a.Status, - ActorUri = a.Actor.Uri, - ObjectUri = a.ObjectUri, - a.CreatedAt, - a.ErrorMessage - }) - .ToListAsync(); - - return Ok(new { activities }); - } - - [HttpGet("actors/{username}/keys")] - public async Task GetActorKeys(string username) - { - var publisher = await db.Publishers - .FirstOrDefaultAsync(p => p.Name == username); - - if (publisher == null) - return NotFound(); - - var actorUrl = $"http://solar.local:5000/activitypub/actors/{username}"; - - var (privateKey, publicKey) = keyService.GenerateKeyPair(); - - return Ok(new - { - username, - hasKeys = publisher.Meta != null, - actorUri, - publicKeyId = $"{actorUrl}#main-key", - publicKey = publicKey, - privateKeyStored = publisher.Meta != null - }); - } - - [HttpPost("sign")] - public ActionResult TestSignature([FromBody] TestSignatureRequest request) - { - var isValid = keyService.Verify( - request.PublicKey, - request.SigningString, - request.Signature - ); - - return Ok(new - { - valid = isValid, - message = isValid ? "Signature is valid" : "Signature is invalid" - }); - } - - private async Task GetPublisherForUser(Guid accountId) - { - return await db.Publishers - .Include(p => p.Members) - .Where(p => p.Members.Any(m => m.AccountId == accountId)) - .FirstOrDefaultAsync(); - } - - private Guid GetCurrentUser() - { - // Implement based on your auth system - return Guid.Empty; - } -} - -public class TestFollowRequest -{ - public string TargetActorUri { get; set; } = string.Empty; -} - -public class TestLikeRequest -{ - public Guid PostId { get; set; } - public string TargetActorUri { get; set; } = string.Empty; -} - -public class TestAnnounceRequest -{ - public Guid PostId { get; set; } -} - -public class TestUndoRequest -{ - public string ActivityType { get; set; } = string.Empty; - public string ObjectUri { get; set; } = string.Empty; -} - -public class TestSignatureRequest -{ - public string PublicKey { get; set; } = string.Empty; - public string SigningString { get; set; } = string.Empty; - public string Signature { get; set; } = string.Empty; -} -``` - -## Testing with Helper Endpoints - -### 1. Test Follow -```bash -curl -X POST http://solar.local:5000/api/activitypub/test/follow \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{ - "targetActorUri": "http://mastodon.local:3001/users/testuser" - }' -``` - -### 2. Test Like -```bash -curl -X POST http://solar.local:5000/api/activitypub/test/like \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{ - "postId": "YOUR_POST_ID", - "targetActorUri": "http://mastodon.local:5000/activitypub/actors/mastodonuser" - }' -``` - -### 3. Check Status -```bash -curl http://solar.local:5000/api/activitypub/test/status \ - -H "Authorization: Bearer YOUR_TOKEN" -``` - -### 4. Get Recent Activities -```bash -curl "http://solar.local:5000/api/activitypub/test/activities?limit=10" \ - -H "Authorization: Bearer YOUR_TOKEN" -``` - -## Integration with Main Flow - -These helper endpoints can be used to: - -1. **Quickly test federation** without full UI integration -2. **Debug specific activity types** in isolation -3. **Verify HTTP signatures** are correct -4. **Test error handling** for various scenarios -5. **Monitor federation status** during development - -## Security Notes - -- All test endpoints require authentication -- Use only in development/staging environments -- Remove or disable in production -- Rate limiting recommended if exposing to public - -## Cleanup - -After testing, you can: - -1. Remove the test controller (optional) -2. Disable test endpoints -3. Clear test activities from database -4. Reset test relationships - -```sql --- Clear test data -DELETE FROM fediverse_activities WHERE created_at < NOW() - INTERVAL '1 day'; -``` diff --git a/docs/activitypub/ACTIVITYPUB_TESTING_INDEX.md b/docs/activitypub/ACTIVITYPUB_TESTING_INDEX.md deleted file mode 100644 index fec85d7c..00000000 --- a/docs/activitypub/ACTIVITYPUB_TESTING_INDEX.md +++ /dev/null @@ -1,448 +0,0 @@ -# ActivityPub Testing - Complete Guide - -This is the complete guide for testing ActivityPub federation in Solar Network. - -## 📁 File Overview - -| File | Purpose | When to Use | -|------|---------|--------------| -| `setup-activitypub-test.sh` | One-command setup of test environment | First time setup | -| `test-activitypub.sh` | Quick validation of basic functionality | After setup, before detailed tests | -| `ACTIVITYPUB_TESTING_QUICKSTART.md` | Quick start reference | Getting started quickly | -| `ACTIVITYPUB_TESTING_GUIDE.md` | Comprehensive testing scenarios | Full testing workflow | -| `ACTIVITYPUB_TESTING_QUICKREF.md` | Command and query reference | Daily testing | -| `ACTIVITYPUB_TESTING_HELPER_API.md` | Helper API for testing | Programmatic testing | -| `ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md` | Track test results | During testing | -| `ACTIVITYPUB_IMPLEMENTATION.md` | Implementation details | Understanding the code | -| `ACTIVITYPUB_SUMMARY.md` | Feature summary | Reviewing what's implemented | - -## 🚀 Quick Start (5 Minutes) - -### 1. Setup Test Environment - -```bash -./setup-activitypub-test.sh -``` - -This will: -- ✅ Configure `/etc/hosts` -- ✅ Start Mastodon via Docker -- ✅ Create test Mastodon account -- ✅ Apply database migrations - -### 2. Validate Setup - -```bash -./test-activitypub.sh -``` - -This checks: -- ✅ WebFinger endpoint -- ✅ Actor profile -- ✅ Public keys -- ✅ Database tables - -### 3. Start Solar Network - -```bash -cd DysonNetwork.Sphere -dotnet run -``` - -### 4. Test Federation - -1. Open http://mastodon.local:3001 -2. Search for `@solaruser@solar.local` -3. Click Follow -4. Create a post in Solar Network -5. Verify it appears in Mastodon - -## 📖 Recommended Reading Order - -### For First-Time Testing - -1. **Start Here**: `ACTIVITYPUB_TESTING_QUICKSTART.md` - - Overview of the setup - - Quick command reference - - Common commands - -2. **Then**: `ACTIVITYPUB_TESTING_GUIDE.md` - - Detailed test scenarios - - Step-by-step instructions - - Troubleshooting - -3. **Reference**: `ACTIVITYPUB_TESTING_QUICKREF.md` - - Command snippets - - Database queries - - Response codes - -### During Testing - -1. **Track Progress**: `ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md` - - Checklists for each test - - Results tracking - - Issue logging - -2. **Helper API**: `ACTIVITYPUB_TESTING_HELPER_API.md` - - Manual testing endpoints - - Debugging tools - - Status monitoring - -### For Understanding - -1. **Implementation**: `ACTIVITYPUB_IMPLEMENTATION.md` - - Architecture details - - Service descriptions - - Data flow diagrams - -2. **Features**: `ACTIVITYPUB_SUMMARY.md` - - What's implemented - - Model relationships - - API endpoints - -## 🔍 Test Scenarios Summary - -### Basic Functionality (All instances must pass) - -- [ ] WebFinger discovery works -- [ ] Actor profile is valid JSON-LD -- [ ] Public key is present -- [ ] Outbox returns public posts -- [ ] Inbox accepts activities - -### Federation - Follow - -- [ ] Remote user can follow local user -- [ ] Local user can follow remote user -- [ ] Accept activity is sent/received -- [ ] Relationship state is correct -- [ ] Unfollow works correctly - -### Federation - Content - -- [ ] Local posts federate to remote instances -- [ ] Remote posts appear in local database -- [ ] Post content is preserved -- [ ] Timestamps are correct -- [ ] Attachments are handled -- [ ] Content warnings are respected - -### Federation - Interactions - -- [ ] Likes federate correctly -- [ ] Likes appear in both instances -- [ ] Replies federate correctly -- [ ] Reply threading works -- [ ] Boosts/Announces work -- [ ] Undo activities work - -### Security - -- [ ] HTTP signatures are verified -- [ ] Invalid signatures are rejected -- [ ] Keys are properly stored -- [ ] Private keys never exposed - -## 🐛 Common Issues & Solutions - -### Issue: "Failed to verify signature" - -**Causes**: -1. Signature header format is wrong -2. Public key doesn't match keyId -3. Date header is too old (>5 minutes) -4. Request body doesn't match digest - -**Solutions**: -1. Check signature format: `keyId="...",algorithm="...",headers="...",signature="..."` -2. Verify keyId in actor profile -3. Ensure Date header is recent -4. Check body is exactly what was signed - -### Issue: "Target actor or inbox not found" - -**Causes**: -1. Actor hasn't been fetched yet -2. Actor URL is incorrect -3. Remote instance is inaccessible - -**Solutions**: -1. Manually fetch actor first -2. Verify actor URL is correct -3. Test accessibility with curl - -### Issue: Activities not arriving - -**Causes**: -1. Network connectivity issue -2. Remote instance is down -3. Activity wasn't queued properly - -**Solutions**: -1. Check network connectivity -2. Verify remote instance is running -3. Check fediverse_activities table for status - -## 📊 Monitoring During Tests - -### Check Logs - -```bash -# Solar Network ActivityPub logs -dotnet run --project DysonNetwork.Sphere 2>&1 | grep -i activitypub - -# Mastodon federation logs -docker compose -f docker-compose.mastodon-test.yml logs -f web | grep -i federation -``` - -### Monitor Database - -```bash -# Watch activity table -watch -n 2 'psql -d dyson_network -c \ - "SELECT type, status, created_at FROM fediverse_activities ORDER BY created_at DESC LIMIT 5;"' -``` - -### Test Network - -```bash -# Test connectivity between instances -curl -v http://mastodon.local:3001 -curl -v http://solar.local:5000 - -# Test with traceroute (if available) -traceroute mastodon.local -traceroute solar.local -``` - -## 🎯 Success Criteria - -### Minimal Viable Federation - -To consider ActivityPub implementation "working", all of these must pass: - -- ✅ WebFinger returns actor links -- ✅ Actor profile has all required fields -- ✅ Follow relationships work bidirectionally -- ✅ Public posts federate to followers -- ✅ Incoming posts are stored correctly -- ✅ HTTP signatures are verified -- ✅ Basic interaction types work (Like, Reply) - -### Full Production Ready - -For production, also need: - -- ✅ Activity queue with retry logic -- ✅ Rate limiting on outgoing deliveries -- ✅ Monitoring and alerting -- ✅ Admin interface for federation management -- ✅ Content filtering and moderation -- ✅ Instance blocking capabilities -- ✅ Performance optimization for high volume - -## 🔐 Security Checklist - -During testing, verify: - -- [ ] Private keys are never logged -- [ ] Private keys are never returned in API responses -- [ ] Only public keys are in actor profiles -- [ ] All incoming activities are signature-verified -- [ ] Invalid signatures are rejected with 401 -- [ ] TLS is used in production -- [ ] Host header is verified against request URL - -## 📈 Performance Metrics - -Track these during testing: - -| Metric | Target | Actual | -|--------|--------|--------| -| WebFinger response time | <500ms | ___ ms | -| Actor fetch time | <1s | ___ ms | -| Signature verification time | <100ms | ___ ms | -| Activity processing time | <500ms | ___ ms | -| Outgoing delivery success rate | >95% | ___% | -| Outgoing delivery time | <5s | ___ ms | - -## 🧪 Testing Checklist - -### Self-Hosted Instance Tests - -**Setup**: -- [ ] Setup script completed -- [ ] Mast containers running -- [ ] Solar Network running -- [ ] /etc/hosts configured -- [ ] Database migrations applied - -**Basic Federation**: -- [ ] WebFinger works -- [ ] Actor profile valid -- [ ] Public key present -- [ ] Outbox accessible - -**Follow Flow**: -- [ ] Mastodon → Solar follow works -- [ ] Solar → Mastodon follow works -- [ ] Accept activity sent -- [ ] Relationship state correct - -**Content Flow**: -- [ ] Solar posts appear in Mastodon -- [ ] Mastodon posts appear in Solar -- [ ] Content preserved correctly -- [ ] Timestamps correct - -**Interactions**: -- [ ] Likes work both ways -- [ ] Replies work both ways -- [ ] Boosts work both ways -- [ ] Undo works - -**Security**: -- [ ] HTTP signatures verified -- [ ] Invalid signatures rejected -- [ ] Keys properly managed - -### Real Instance Tests - -**Discovery**: -- [ ] Domain publicly accessible -- [ ] WebFinger works from public internet -- [ ] Actor discoverable from public instances - -**Federation**: -- [ ] Posts federate to public instances -- [ ] Follows work with public instances -- [ ] Interactions work with public instances - -## 📝 Testing Notes - -### What Worked Well -1. _____________________ -2. _____________________ -3. _____________________ - -### What Needs Improvement -1. _____________________ -2. _____________________ -3. _____________________ - -### Bugs Found -| # | Description | Severity | Status | -|---|-------------|----------|--------| -| 1 | _____________________ | Low/Medium/High | ☐ Open/☐ Fixed | -| 2 | _____________________ | Low/Medium/High | ☐ Open/☐ Fixed | -| 3 | _____________________ | Low/Medium/High | ☐ Open/☐ Fixed | - -## 🎓 Learning Resources - -### ActivityPub Specification -- [W3C ActivityPub Recommendation](https://www.w3.org/TR/activitypub/) -- [ActivityStreams 2.0](https://www.w3.org/TR/activitystreams-core/) -- [HTTP Signatures Draft](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) - -### Implementation Guides -- [Mastodon Federation Guide](https://docs.joinmastodon.org/admin/federation/) -- [ActivityPub Testing Best Practices](https://blog.joinmastodon.org/2018/06/27/how-to-implement-a-basic-activitypub-server/) -- [Federation Testing Checklist](https://docs.joinmastodon.org/spec/activitypub/) - -### Tools -- [ActivityPub Playground](https://swicth.github.io/activity-pub-playground/) -- [FediTest](https://feditest.com/) -- [JSONPath Online Evaluator](https://jsonpath.com/) - -## 🔄 Next Steps After Testing - -### Phase 1: Fix Issues -- Address all bugs found during testing -- Improve error messages -- Add better logging - -### Phase 2: Enhance Features -- Implement activity queue -- Add retry logic -- Add rate limiting -- Implement instance blocking - -### Phase 3: Production Readiness -- Add monitoring and metrics -- Add admin interface -- Add content filtering -- Implement moderation tools - -### Phase 4: Additional Features -- Support more activity types -- Support media attachments -- Support polls -- Support custom emojis - -## 📞 Getting Help - -If you encounter issues: - -1. **Check logs**: See the logs section above -2. **Review troubleshooting**: See `ACTIVITYPUB_TESTING_GUIDE.md` Part 5 -3. **Check database queries**: Use queries from `ACTIVITYPUB_TESTING_QUICKREF.md` -4. **Validate signatures**: Use helper API in `ACTIVITYPUB_TESTING_HELPER_API.md` - -## ✨ Quick Test Commands - -### All-in-One Test Sequence - -```bash -# 1. Setup -./setup-activitypub-test.sh - -# 2. Validate -./test-activitypub.sh - -# 3. Test WebFinger -curl "http://solar.local:5000/.well-known/webfinger?resource=acct:solaruser@solar.local" - -# 4. Test Actor -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/solaruser - -# 5. Test Follow (from Mastodon UI) -# Open http://mastodon.local:3001 and follow @solaruser@solar.local - -# 6. Check database -psql -d dyson_network -c "SELECT * FROM fediverse_relationships;" - -# 7. Test Post (create in Solar Network UI) -# Should appear in http://mastodon.local:3001 - -# 8. Verify content -psql -d dyson_network -c "SELECT * FROM fediverse_contents;" - -# 9. Test Like (like from Mastodon UI) -# Should appear in fediverse_reactions table - -# 10. Check activities -psql -d dyson_network -c "SELECT type, status FROM fediverse_activities;" -``` - -## 🎉 Conclusion - -You now have everything needed to test ActivityPub federation for Solar Network: - -- ✅ Self-hosted test environment (Mastodon) -- ✅ Setup automation (setup script) -- ✅ Quick validation (test script) -- ✅ Comprehensive testing guide -- ✅ Helper API for programmatic testing -- ✅ Quick reference for daily use -- ✅ Results template for tracking progress - -**Recommended workflow**: -1. Run `setup-activitypub-test.sh` -2. Run `test-activitypub.sh` for validation -3. Follow scenarios in `ACTIVITYPUB_TESTING_GUIDE.md` -4. Use `ACTIVITYPUB_TESTING_HELPER_API.md` for specific tests -5. Track results in `ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md` -6. Reference `ACTIVITYPUB_TESTING_QUICKREF.md` for commands - -Good luck with your federation testing! 🚀 diff --git a/docs/activitypub/ACTIVITYPUB_TESTING_QUICKREF.md b/docs/activitypub/ACTIVITYPUB_TESTING_QUICKREF.md deleted file mode 100644 index da36adc8..00000000 --- a/docs/activitypub/ACTIVITYPUB_TESTING_QUICKREF.md +++ /dev/null @@ -1,356 +0,0 @@ -# ActivityPub Testing Quick Reference - -## Quick Test Commands - -### 1. Test WebFinger -```bash -curl "http://solar.local:5000/.well-known/webfinger?resource=acct:username@solar.local" -``` - -### 2. Fetch Actor Profile -```bash -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/username -``` - -### 3. Get Outbox -```bash -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/username/outbox -``` - -### 4. Send Test Follow (from remote) -```bash -curl -X POST http://solar.local:5000/activitypub/actors/username/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{ - "@context": "https://www.w3.org/ns/activitystreams", - "id": "https://mastodon.local:3001/follow-123", - "type": "Follow", - "actor": "https://mastodon.local:3001/users/remoteuser", - "object": "https://solar.local:5000/activitypub/actors/username" - }' -``` - -### 5. Send Test Create (post) -```bash -curl -X POST http://solar.local:5000/activitypub/actors/username/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{ - "@context": "https://www.w3.org/ns/activitystreams", - "id": "https://mastodon.local:3001/post-123", - "type": "Create", - "actor": "https://mastodon.local:3001/users/remoteuser", - "object": { - "id": "https://mastodon.local:3001/objects/post-123", - "type": "Note", - "content": "Hello from Mastodon! @username@solar.local", - "attributedTo": "https://mastodon.local:3001/users/remoteuser", - "to": ["https://www.w3.org/ns/activitystreams#Public"] - } - }' -``` - -### 6. Send Test Like -```bash -curl -X POST http://solar.local:5000/activitypub/actors/username/inbox \ - -H "Content-Type: application/activity+json" \ - -d '{ - "@context": "https://www.w3.org/ns/activitystreams", - "id": "https://mastodon.local:3001/like-123", - "type": "Like", - "actor": "https://mastodon.local:3001/users/remoteuser", - "object": "https://solar.local:5000/activitypub/objects/post-id" - }' -``` - -## Database Queries - -### Check Actors -```sql -SELECT id, uri, username, display_name, instance_id -FROM fediverse_actors; -``` - -### Check Contents -```sql -SELECT id, uri, type, content, actor_id, created_at -FROM fediverse_contents -ORDER BY created_at DESC -LIMIT 20; -``` - -### Check Relationships -```sql -SELECT r.id, a1.uri as actor, a2.uri as target, r.state, r.is_following -FROM fediverse_relationships r -JOIN fediverse_actors a1 ON r.actor_id = a1.id -JOIN fediverse_actors a2 ON r.target_actor_id = a2.id; -``` - -### Check Activities -```sql -SELECT type, status, error_message, created_at -FROM fediverse_activities -ORDER BY created_at DESC -LIMIT 20; -``` - -### Check Reactions -```sql -SELECT r.type, c.uri as content_uri, a.uri as actor_uri -FROM fediverse_reactions r -JOIN fediverse_contents c ON r.content_id = c.id -JOIN fediverse_actors a ON r.actor_id = a.id; -``` - -## Check Keys in Publisher -```sql -SELECT id, name, meta -FROM publishers -WHERE meta IS NOT NULL; -``` - -## Docker Commands - -### Start Mastodon -```bash -docker-compose -f docker-compose.mastodon-test.yml up -d -``` - -### View Mastodon Logs -```bash -docker-compose -f docker-compose.mastodon-test.yml logs -f web -``` - -### Stop Mastodon -```bash -docker-compose -f docker-compose.mastodon-test.yml down -``` - -### Start GoToSocial -```bash -docker-compose -f docker-compose.gotosocial.yml up -d -``` - -## Solar Network Commands - -### Run Migrations -```bash -cd DysonNetwork.Sphere -dotnet ef database update -``` - -### Run with Debug Logging -```bash -dotnet run --project DysonNetwork.Sphere -- --logging:LogLevel:DysonNetwork.Sphere.ActivityPub=Trace -``` - -## Common Response Codes - -| Code | Meaning | -|------|---------| -| 200 | Success | -| 202 | Accepted (activity queued) | -| 401 | Unauthorized (invalid signature) | -| 404 | Not found (user/post doesn't exist) | -| 400 | Bad request (invalid activity) | - -## Activity Status Codes - -| Status | Code | Meaning | -|--------|------|---------| -| Pending | 0 | Activity waiting to be processed | -| Processing | 1 | Activity being processed | -| Completed | 2 | Activity successfully processed | -| Failed | 3 | Activity processing failed | - -## Relationship States - -| State | Code | Meaning | -|--------|------|---------| -| Pending | 0 | Follow request sent, waiting for Accept | -| Accepted | 1 | Follow accepted, relationship active | -| Rejected | 2 | Follow rejected | - -## Troubleshooting - -### "Failed to verify signature" - -**Check**: Signature header format -```bash -# Should be: -Signature: keyId="...",algorithm="rsa-sha256",headers="...",signature="..." -``` - -**Check**: Public key in actor profile -```bash -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/username | jq '.publicKey' -``` - -### "Actor not found" - -**Check**: Actor exists in database -```bash -psql -d dyson_network -c \ - "SELECT * FROM fediverse_actors WHERE uri = '...';" -``` - -**Check**: Actor URL is accessible -```bash -curl -v http://remote-instance.com/users/username -``` - -### "Content already exists" - -This is normal behavior - the system is deduplicating. - -### "Target publisher not found" - -**Check**: Publisher exists -```bash -psql -d dyson_network -c \ - "SELECT * FROM publishers WHERE name = '...';" -``` - -## Quick Test Sequence - -### Full Federation Test - -```bash -# 1. Start both instances -docker-compose -f docker-compose.mastodon-test.yml up -d -dotnet run --project DysonNetwork.Sphere - -# 2. Test WebFinger -curl "http://solar.local:5000/.well-known/webfinger?resource=acct:solaruser@solar.local" - -# 3. Get Actor -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/solaruser - -# 4. Send Follow from Mastodon -# (Do this in Mastodon UI or use curl above) - -# 5. Check database -psql -d dyson_network -c "SELECT * FROM fediverse_relationships;" - -# 6. Send Create (post) from Mastodon -# (Use curl command above) - -# 7. Check content -psql -d dyson_network -c "SELECT * FROM fediverse_contents;" - -# 8. Send Like from Mastodon -# (Use curl command above) - -# 9. Check reactions -psql -d dyson_network -c "SELECT * FROM fediverse_reactions;" - -# 10. Check activities -psql -d dyson_network -c "SELECT type, status FROM fediverse_activities;" -``` - -## Test URLs - -| Instance | Web | API | ActivityPub | -|----------|-----|-----|-----------| -| Solar Network | http://solar.local:5000 | http://solar.local:5000/api | http://solar.local:5000/activitypub | -| Mastodon | http://mastodon.local:3001 | http://mastodon.local:3001/api/v1 | http://mastodon.local:3001/inbox | - -## Environment Variables - -### Solar Network -```bash -export SOLAR_DOMAIN="solar.local" -export SOLAR_URL="http://solar.local:5000" -``` - -### Mastodon -```bash -export MASTODON_DOMAIN="mastodon.local" -export MASTODON_URL="http://mastodon.local:3001" -``` - -## Useful jq Commands - -### Extract Actor ID -```bash -curl ... | jq '.id' -``` - -### Extract Inbox URL -```bash -curl ... | jq '.inbox' -``` - -### Extract Public Key -```bash -curl ... | jq '.publicKey.publicKeyPem' -``` - -### Pretty Print Activity -```bash -curl ... | jq '.' -``` - -### Extract Activity Type -```bash -curl ... | jq '.type' -``` - -## Network Setup - -### /etc/hosts -``` -127.0.0.1 solar.local -127.0.0.1 mastodon.local -127.0.0.1 gotosocial.local -``` - -### Ports Used -- Solar Network: 5000 -- Mastodon: 3001 (web), 4000 (streaming) -- GoToSocial: 3002 -- PostgreSQL: 5432 -- Redis: 6379 -- Elasticsearch: 9200 - -## File Locations - -### Docker Compose Files -- `docker-compose.mastodon-test.yml` -- `docker-compose.gotosocial.yml` - -### Environment Files -- `.env.mastodon` - -### Data Volumes -- `./mastodon-data/` -- `./gotosocial-data/` - -## Clean Up Commands - -```bash -# Reset database -psql -d dyson_network <&1 | grep -i activitypub - -# Debug logging -dotnet run --project DysonNetwork.Sphere --logging:LogLevel:DysonNetwork.Sphere.ActivityPub=Trace -``` - -### Mastodon Logs -```bash -# All services -docker compose -f docker-compose.mastodon-test.yml logs -f - -# Web service only -docker compose -f docker-compose.mastodon-test.yml logs -f web - -# Filter for federation -docker compose -f docker-compose.mastodon-test.yml logs -f web | grep -i federation -``` - -## Stopping Everything - -```bash -# Stop Mastodon -docker compose -f docker-compose.mastodon-test.yml down - -# Stop with volume cleanup -docker compose -f docker-compose.mastodon-test.yml down -v - -# Restore /etc/hosts -sudo mv /etc/hosts.backup /etc/hosts - -# Remove test databases (optional) -psql -d dyson_network <&1 | grep -i error - -# Restart -# Ctrl+C in terminal and run again -``` - -### Activities not arriving - -```bash -# Check database -psql -d dyson_network -c "SELECT * FROM fediverse_activities WHERE status = 3;" - -# Check signature verification logs -dotnet run --project DysonNetwork.Sphere 2>&1 | grep -i "signature" - -# Verify actor keys -curl -H "Accept: application/activity+json" \ - http://solar.local:5000/activitypub/actors/solaruser | jq '.publicKey' -``` - -## Testing Checklist - -- [ ] Setup script completed successfully -- [ ] Mastodon is running and accessible -- [ ] Solar Network is running and accessible -- [ ] WebFinger returns correct data -- [ ] Actor profile includes public key -- [ ] Follow from Mastodon to Solar Network works -- [ ] Follow from Solar Network to Mastodon works -- [ ] Posts from Solar Network appear in Mastodon -- [ ] Posts from Mastodon appear in Solar Network database -- [ ] Likes federate correctly -- [ ] Replies federate correctly -- [ ] HTTP signatures are verified -- [ ] No errors in logs -- [ ] Database contains expected data - -## Next Steps - -1. **Test with a real instance**: - - Get a public domain or use ngrok - - Update `ActivityPub:Domain` in appsettings.json - - Test with mastodon.social or other public instances - -2. **Add more features**: - - Activity queue for async processing - - Retry logic for failed deliveries - - Metrics and monitoring - - Admin interface for federation management - -3. **Test with more instances**: - - Pleroma - - Pixelfed - - Lemmy - - PeerTube - -## Getting Help - -If something doesn't work: - -1. Check the logs (see Logs section above) -2. Review the troubleshooting section in [ACTIVITYPUB_TESTING_GUIDE.md](ACTIVITYPUB_TESTING_GUIDE.md) -3. Verify all prerequisites are installed -4. Check network connectivity between instances -5. Review the [ACTIVITYPUB_IMPLEMENTATION.md](ACTIVITYPUB_IMPLEMENTATION.md) for architecture details - -## Useful URLs - -### Test Instances -- Mastodon: http://mastodon.local:3001 -- Solar Network: http://solar.local:5000 - -### Documentation -- ActivityPub W3C Spec: https://www.w3.org/TR/activitypub/ -- Mastodon Federation Docs: https://docs.joinmastodon.org/admin/federation/ -- ActivityPub Playground: https://swicth.github.io/activity-pub-playground/ - -### Tools -- jq: JSON processor (https://stedolan.github.io/jq/) -- httpie: HTTP client (https://httpie.io/) -- Docker Compose: (https://docs.docker.com/compose/) diff --git a/docs/activitypub/ACTIVITYPUB_TESTING_README.md b/docs/activitypub/ACTIVITYPUB_TESTING_README.md deleted file mode 100644 index d6804c6a..00000000 --- a/docs/activitypub/ACTIVITYPUB_TESTING_README.md +++ /dev/null @@ -1,275 +0,0 @@ -# ActivityPub Testing Guide - -Complete guide for testing ActivityPub federation in Solar Network. - -## 📚 Documentation Files - -| File | Description | Size | -|------|-------------|-------| -| `ACTIVITYPUB_TESTING_INDEX.md` | **START HERE** - Master guide with overview | 12K | -| `ACTIVITYPUB_TESTING_QUICKSTART.md` | Quick reference for common tasks | 7K | -| `ACTIVITYPUB_TESTING_GUIDE.md` | Comprehensive testing scenarios (10 parts) | 19K | -| `ACTIVITYPUB_TESTING_QUICKREF.md` | Command and query reference | 8K | -| `ACTIVITYPUB_TESTING_HELPER_API.md` | Helper API for programmatic testing | 12K | -| `ACTIVITYPUB_TESTING_RESULTS_TEMPLATE.md` | Template to track test results | 10K | - -## 🚀 Quick Start - -### Option A: One-Command Setup (Recommended) - -```bash -# 1. Run setup script -./setup-activitypub-test.sh - -# 2. Run validation -./test-activitypub.sh - -# 3. Start Solar Network -cd DysonNetwork.Sphere -dotnet run -``` - -### Option B: Manual Setup - -1. **Read**: `ACTIVITYPUB_TESTING_QUICKSTART.md` -2. **Configure**: Copy `.env.testing.example` to `.env` and adjust -3. **Follow**: Step-by-step in `ACTIVITYPUB_TESTING_GUIDE.md` - -## 🎯 What You Can Test - -### With Self-Hosted Instance -- ✅ WebFinger discovery -- ✅ Actor profile retrieval -- ✅ Follow relationships (bidirectional) -- ✅ Post federation (Solar → Mastodon) -- ✅ Content reception (Mastodon → Solar) -- ✅ Like interactions -- ✅ Reply threading -- ✅ HTTP signature verification -- ✅ Content deletion - -### With Real Instance -- ✅ Public domain setup (via ngrok or VPS) -- ✅ Federation with public instances (mastodon.social, etc.) -- ✅ Real-world compatibility testing -- ✅ Performance under real load - -## 📋 Testing Workflow - -### Day 1: Basic Functionality -- Setup test environment -- Test WebFinger and Actor endpoints -- Verify HTTP signatures -- Test basic follow/unfollow - -### Day 2: Content Federation -- Test post creation and delivery -- Test content reception -- Test media attachments -- Test content warnings - -### Day 3: Interactions -- Test likes (both directions) -- Test replies and threading -- Test boosts/announces -- Test undo activities - -### Day 4: Real Instance -- Set up public domain -- Test with mastodon.social -- Test with other instances -- Verify cross-instance compatibility - -### Day 5: Edge Cases -- Test error handling -- Test failed deliveries -- Test invalid signatures -- Test malformed activities - -## 🛠️ Setup Scripts - -| Script | Purpose | -|--------|---------| -| `setup-activitypub-test.sh` | One-command setup of Mastodon + Solar Network | -| `test-activitypub.sh` | Quick validation of core functionality | - -Both scripts are executable (`chmod +x`). - -## 🔧 Configuration - -### Required Tools -- ✅ Docker (for Mastodon) -- ✅ .NET 10 SDK (for Solar Network) -- ✅ PostgreSQL client (psql) -- ✅ curl (for API testing) - -### Quick Setup -```bash -# 1. Install dependencies (Ubuntu/Debian) -sudo apt-get install docker.io docker-compose postgresql-client curl jq - -# 2. Run setup -./setup-activitypub-test.sh - -# 3. Validate -./test-activitypub.sh -``` - -## 📊 Progress Tracking - -Use the template to track your testing progress: - -```bash -# Copy the template -cp ACTIVITYPUB_TESTING_RESULTS_TEMPLATE.md my-test-results.md - -# Edit as you test -nano my-test-results.md -``` - -## 🐛 Troubleshooting - -### Quick Fixes - -**Mastodon won't start**: -```bash -# Check logs -docker compose -f docker-compose.mastodon-test.yml logs -f - -# Restart containers -docker compose -f docker-compose.mastodon-test.yml restart -``` - -**Can't reach Solar Network**: -```bash -# Check if running -curl http://solar.local:5000 - -# Check /etc/hosts -cat /etc/hosts | grep solar.local -``` - -**Activities not arriving**: -```bash -# Check database -psql -d dyson_network -c "SELECT * FROM fediverse_activities;" - -# Check logs -dotnet run --project DysonNetwork.Sphere | grep -i activitypub -``` - -For detailed troubleshooting, see `ACTIVITYPUB_TESTING_GUIDE.md` Part 5. - -## 📖 Learning Path - -### For Developers -1. Read `ACTIVITYPUB_IMPLEMENTATION.md` to understand the architecture -2. Read `ACTIVITYPUB_SUMMARY.md` to see what's implemented -3. Follow test scenarios in `ACTIVITYPUB_TESTING_GUIDE.md` -4. Use helper API in `ACTIVITYPUB_TESTING_HELPER_API.md` for testing - -### For Testers -1. Start with `ACTIVITYPUB_TESTING_QUICKSTART.md` -2. Use command reference in `ACTIVITYPUB_TESTING_QUICKREF.md` -3. Track results with `ACTIVITYPUB_TESTING_RESULTS_TEMPLATE.md` -4. Report issues with details from logs - -## 🎓 Success Criteria - -### Minimum Viable -- WebFinger works -- Actor profile valid -- Follow relationships work -- Posts federate correctly -- HTTP signatures verified - -### Production Ready -- Activity queue with retry -- Rate limiting -- Monitoring/alerting -- Admin interface -- Instance blocking -- Content moderation - -## 🚨 Common Pitfalls - -### Don't Forget -- ✅ Update `/etc/hosts` with both instances -- ✅ Run migrations before testing -- ✅ Check both instances are accessible -- ✅ Verify PostgreSQL is running -- ✅ Check logs when something fails - -### Watch Out For -- ❌ Using `localhost` instead of `solar.local` -- ❌ Forgetting to restart after config changes -- ❌ Not waiting for Mastodon to start (2-5 minutes) -- ❌ Ignoring CORS errors in browser testing -- ❌ Testing with deleted/invisible posts - -## 📚 Additional Resources - -### Official Specs -- [ActivityPub W3C](https://www.w3.org/TR/activitypub/) -- [ActivityStreams](https://www.w3.org/TR/activitystreams-core/) -- [HTTP Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) - -### Community Guides -- [Mastodon Federation](https://docs.joinmastodon.org/admin/federation/) -- [Federation Testing](https://docs.joinmastodon.org/spec/activitypub/) - -### Tools -- [ActivityPub Playground](https://swicth.github.io/activity-pub-playground/) -- [FediTest](https://feditest.com/) - -## 🆘 Support - -If you encounter issues: - -1. Check logs (both Solar Network and Mastodon) -2. Review troubleshooting section in the guide -3. Validate against success criteria -4. Check database state with queries -5. Review implementation docs - -## ✨ Next Steps - -After testing with self-hosted instance: - -1. Get a public domain or use ngrok -2. Update `ActivityPub:Domain` in appsettings.json -3. Test with public Mastodon instances -4. Add more ActivityPub features (queue, retry, etc.) -5. Implement admin interface -6. Add monitoring and metrics - -## 📞 File Reference - -All files are in the root of the DysonNetwork project: - -``` -DysonNetwork/ -├── ACTIVITYPUB_TESTING_INDEX.md # Start here! -├── ACTIVITYPUB_TESTING_QUICKSTART.md # Quick reference -├── ACTIVITYPUB_TESTING_GUIDE.md # Full guide -├── ACTIVITYPUB_TESTING_QUICKREF.md # Commands -├── ACTIVITYPUB_TESTING_HELPER_API.md # Test API -├── ACTIVITYPUB_TESTING_RESULTS_TEMPLATE.md -├── setup-activitypub-test.sh # Setup script -├── test-activitypub.sh # Test script -└── .env.testing.example # Config template -``` - -**Documentation files** (for reference): -``` -DysonNetwork/ -├── ACTIVITYPUB_IMPLEMENTATION.md # How it's implemented -├── ACTIVITYPUB_SUMMARY.md # Feature summary -└── ACTIVITYPUB_PLAN.md # Original plan -``` - ---- - -**Start here**: `ACTIVITYPUB_TESTING_INDEX.md` - -**Good luck with your testing!** 🚀 diff --git a/docs/activitypub/ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md b/docs/activitypub/ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md deleted file mode 100644 index e1ea87bf..00000000 --- a/docs/activitypub/ACTIVITYPUB_TEST_RESULTS_TEMPLATE.md +++ /dev/null @@ -1,282 +0,0 @@ -# ActivityPub Testing Results Template - -Use this template to track your testing progress. - -## Test Environment - -**Date**: ________________ - -**Test Configuration**: -- Solar Network URL: `http://solar.local:5000` -- Mastodon URL: `http://mastodon.local:3001` -- Database: `dyson_network` - -**Solar Network User**: -- Username: `_______________` -- Publisher ID: `_______________` - -**Mastodon User**: -- Username: `testuser@mastodon.local` -- Password: `TestPassword123!` - ---- - -## Test Results - -### ✅ Part 1: Infrastructure Setup - -| Test | Status | Notes | -|------|--------|-------| -| Setup script ran successfully | ☐ ☑ | | -| /etc/hosts updated | ☐ ☑ | | -| Docker containers started | ☐ ☑ | | -| Mastodon web accessible | ☐ ☑ | | -| Mastodon admin account created | ☐ ☑ | | -| Database migrations applied | ☐ ☑ | | -| Solar Network started | ☐ ☑ | | - -### ✅ Part 2: WebFinger & Actor Discovery - -| Test | Status | Expected | Actual | -|------|--------|---------|--------| -| WebFinger for Solar Network user | ☐ ☑ | Returns subject + links | _______________ | -| Actor profile JSON is valid | ☐ ☑ | Has id, type, inbox, outbox | _______________ | -| Public key present in actor | ☐ ☑ | publicKey.publicKeyPem exists | _______________ | -| Outbox returns public posts | ☐ ☑ | OrderedCollection with items | _______________ | -| Outbox totalItems count | ☐ ☑ | Matches public posts | _______________ | - -### ✅ Part 3: Follow Relationships - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Mastodon follows Solar Network user | ☐ ☑ | Relationship created in DB | _______________ | -| Accept sent to Mastodon | ☐ ☑ | Mastodon receives Accept | _______________ | -| Solar Network follows Mastodon user | ☐ ☑ | Relationship created | _______________ | -| Follow appears in Mastodon UI | ☐ ☑ | Mastodon shows "Following" | _______________ | -| Follow appears in Solar Network DB | ☐ ☑ | is_following = true | _______________ | -| Follow state is Accepted | ☐ ☑ | state = 1 (Accepted) | _______________ | -| Unfollow works correctly | ☐ ☑ | Relationship deleted/updated | _______________ | - -### ✅ Part 4: Content Federation (Create) - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Post created in Solar Network | ☐ ☑ | Post in sn_posts table | _______________ | -| Activity sent to Mastodon | ☐ ☑ | Logged as successful | _______________ | -| Post appears in Mastodon timeline | ☐ ☑ | Visible in federated timeline | _______________ | -| Post content matches | ☐ ☑ | Same text/HTML | _______________ | -| Post author is correct | ☐ ☑ | Shows Solar Network user | _______________ | -| Post timestamp is correct | ☐ ☑ | Same published time | _______________ | -| Multiple posts federate | ☐ ☑ | All posts appear | _______________ | - -### ✅ Part 5: Content Reception (Incoming Create) - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Create activity received | ☐ ☑ | Activity logged in DB | _______________ | -| Content stored in fediverse_contents | ☐ ☑ | Record with correct type | _______________ | -| Content not duplicated | ☐ ☑ | Only one entry per URI | _______________ | -| Actor created/retrieved | ☐ ☑ | Actor in fediverse_actors | _______________ | -| Instance created/retrieved | ☐ ☑ | Instance in fediverse_instances | _______________ | -| Content HTML preserved | ☐ ☑ | contentHtml field populated | _______________ | - -### ✅ Part 6: Reaction Federation (Like) - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Like from Mastodon to Solar post | ☐ ☑ | Like activity received | _______________ | -| Reaction stored in fediverse_reactions | ☐ ☑ | Record with type = 0 (Like) | _______________ | -| Like count incremented | ☐ ☑ | like_count increased | _______________ | -| Like appears in UI | ☐ ☑ | Visible on Solar Network | _______________ | -| Like appears in Mastodon | ☐ ☑ | Visible on Mastodon | _______________ | -| Unlike works correctly | ☐ ☑ | Like removed | _______________ | - -### ✅ Part 7: Reply Federation - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Reply from Mastodon to Solar post | ☐ ☑ | Create activity with inReplyTo | _______________ | -| Reply stored with parent reference | ☐ ☑ | in_reply_to field set | _______________ | -| Reply appears in Solar Network | ☐ ☑ | Visible as comment | _______________ | -| Reply shows parent context | ☐ ☑ | Links to original post | _______________ | - -### ✅ Part 8: Content Deletion - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Delete from Mastodon | ☐ ☑ | Delete activity received | _______________ | -| Content soft-deleted | ☐ ☑ | deleted_at timestamp set | _______________ | -| Content no longer visible | ☐ ☑ | Hidden from timelines | _______________ | - -### ✅ Part 9: HTTP Signature Verification - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Valid signature accepted | ☐ ☑ | Activity processed | _______________ | -| Invalid signature rejected | ☐ ☑ | 401 Unauthorized | _______________ | -| Missing signature rejected | ☐ ☑ | 401 Unauthorized | _______________ | -| Signature format correct | ☐ ☑ | keyId, algorithm, headers, signature | _______________ | -| Signing string correct | ☐ ☑ | Matches HTTP-Signatures draft | _______________ | - -### ✅ Part 10: Error Handling - -| Test | Status | Expected Result | Actual Result | -|------|--------|----------------|---------------| -| Invalid activity type rejected | ☐ ☑ | 400 Bad Request | _______________ | -| Malformed JSON rejected | ☐ ☑ | 400 Bad Request | _______________ | -| Non-existent actor rejected | ☐ ☑ | 404 Not Found | _______________ | -| Errors logged correctly | ☐ ☑ | error_message populated | _______________ | -| Activity status = Failed | ☐ ☑ | status = 3 | _______________ | - ---- - -## Database State After Tests - -### Actors Table -```sql -SELECT COUNT(*) as total_actors, - SUM(CASE WHEN is_local_actor THEN 1 ELSE 0 END) as local, - SUM(CASE WHEN NOT is_local_actor THEN 1 ELSE 0 END) as remote -FROM fediverse_relationships; -``` -- Total Actors: _______________ -- Local Actors: _______________ -- Remote Actors: _______________ - -### Contents Table -```sql -SELECT COUNT(*) as total_contents, - AVG(LENGTH(content)) as avg_content_length -FROM fediverse_contents WHERE deleted_at IS NULL; -``` -- Total Contents: _______________ -- Avg Content Length: _______________ - -### Activities Table -```sql -SELECT type, status, COUNT(*) -FROM fediverse_activities -GROUP BY type, status -ORDER BY type, status; -``` -- Activities by Type/Status: - - Create: Pending ___, Completed ____, Failed ___ - - Follow: Pending ___, Completed ____, Failed ___ - - Like: Pending ___, Completed ____, Failed ___ - - Accept: Pending ___, Completed ____, Failed ___ - -### Relationships Table -```sql -SELECT state, COUNT(*) as count -FROM fediverse_relationships -GROUP BY state; -``` -- Pending: _______________ -- Accepted: _______________ -- Rejected: _______________ - ---- - -## Logs Analysis - -### Solar Network Errors Found: -1. _______________ -2. _______________ -3. _______________ - -### Mastodon Errors Found: -1. _______________ -2. _______________ -3. _______________ - -### Warnings Found: -1. _______________ -2. _______________ -3. _______________ - ---- - -## Issues & Bugs Found - -| # | Severity | Description | Status | -|---|----------|-------------|--------| -| 1 | ☐ Low/Medium/High/Critical | _____________________ | ☐ Open/☐ Fixed | -| 2 | ☐ Low/Medium/High/Critical | _____________________ | ☐ Open/☐ Fixed | -| 3 | ☐ Low/Medium/High/Critical | _____________________ | ☐ Open/☐ Fixed | -| 4 | ☐ Low/Medium/High/Critical | _____________________ | ☐ Open/☐ Fixed | - ---- - -## Performance Notes - -| Metric | Value | Notes | -|--------|-------|-------| -| Average activity processing time | __________ ms | | -| Average HTTP signature verification time | __________ ms | | -| Outgoing delivery success rate | __________% | | -| Average WebFinger response time | __________ ms | | -| Database query performance | __________ | | - ---- - -## Compatibility Notes - -| Instance | Version | Works | Notes | -|----------|---------|--------|-------| -| Mastodon (self-hosted) | latest | ☐ ☑ | | -| Mastodon.social | ~4.0 | ☐ ☑ | | -| Pleroma | ~2.5 | ☐ ☑ | | -| GoToSocial | ~0.15 | ☐ ☑ | | - ---- - -## Recommendations - -### What Worked Well: -1. _____________________ -2. _____________________ -3. _____________________ - -### What Needs Improvement: -1. _____________________ -2. _____________________ -3. _____________________ - -### Features to Add: -1. _____________________ -2. _____________________ -3. _____________________ - ---- - -## Next Testing Phase - -- [ ] Test with public Mastodon instance -- [ ] Test with Pleroma instance -- [ ] Test media attachment federation -- [ ] Test with high-volume posts -- [ ] Test concurrent activity processing -- [ ] Test with different visibility levels -- [ ] Test with long posts (>500 chars) -- [ ] Test with special characters/emojis - ---- - -## Sign-off - -**Tested By**: _____________________ - -**Test Date**: _____________________ - -**Overall Result**: ☐ Pass / ☐ Fail - -**Ready for Production**: ☐ Yes / ☐ No - -**Notes**: ___________________________________________________________________________ - -__________________________________________________________________________ - -__________________________________________________________________________ - -__________________________________________________________________________ - diff --git a/docs/activitypub/FOLLOWING_USERS_GUIDE.md b/docs/activitypub/FOLLOWING_USERS_GUIDE.md deleted file mode 100644 index b08e96ea..00000000 --- a/docs/activitypub/FOLLOWING_USERS_GUIDE.md +++ /dev/null @@ -1,425 +0,0 @@ -# Follow Feature - User Guide - -## Quick Start: How to Follow Fediverse Users - -### Method 1: Via Search (Recommended) - -1. Go to the search bar in Solar Network -2. Type the user's full address: `@username@domain.com` - - Example: `@alice@mastodon.social` - - Example: `@bob@pleroma.site` -3. Click on their profile in search results -4. Click the "Follow" button -5. Wait for acceptance (usually immediate) -6. ✅ Done! Their posts will now appear in your timeline - -### Method 2: Via Profile URL - -1. If you know their profile URL, visit it directly: - - Example: `https://mastodon.social/@alice` -2. Look for the "Follow" button on their profile -3. Click it to follow -4. ✅ You're now following them! - -## What Happens When You Follow Someone - -### The Technical Flow -``` -You click "Follow" - ↓ -Solar Network creates Follow Activity - ↓ -Follow Activity is signed with your private key - ↓ -Solar Network sends Follow to their instance's inbox - ↓ -Their instance verifies your signature - ↓ -Their instance processes the Follow - ↓ -Their instance sends Accept Activity back - ↓ -Solar Network receives and processes Accept - ↓ -Relationship is stored in database - ↓ -Their public posts federate to Solar Network -``` - -### What You'll See - -- ✅ **"Following..."** (while waiting for acceptance) -- ✅ **"Following" ✓** (when accepted) -- ✅ **Their posts** in your home timeline -- ✅ **Their likes, replies, boosts** on your posts - -## Different Types of Accounts - -### Regular Users -- Full ActivityPub support -- Follows work both ways -- Content federates normally -- Example: `@alice@mastodon.social` - -### Locked Accounts -- User must manually approve followers -- You'll see "Pending" after clicking follow -- User receives notification to approve/deny -- Example: `@private@pleroma.site` - -### Bot/Service Accounts -- Automated content accounts -- Often auto-accept follows -- Example: `@newsbot@botsin.space` - -### Organizational Accounts -- Group or team accounts -- Example: `@team@company.social` - -## Managing Your Follows - -### View Who You're Following - -**Go to**: Following page or `GET /api/activitypub/following` - -You'll see: -- Username -- Display name -- Profile picture -- When you followed them -- Their instance (e.g., "Mastodon") - -### Unfollowing Someone - -**Method 1: Via UI** -1. Go to their profile -2. Click "Following" button (shows as active) -3. Click to unfollow - -**Method 2: Via API** -```bash -curl -X POST http://solar.local:5000/api/activitypub/unfollow \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "targetActorUri": "https://mastodon.social/users/alice" - }' -``` - -**Response**: -```json -{ - "success": true, - "message": "Unfollowed successfully" -} -``` - -### View Your Followers - -**Go to**: Followers page or `GET /api/activitypub/followers` - -You'll see: -- Users following you -- Their instance -- When they started following -- Whether they're local or from another instance - -## Searching Fediverse Users - -### How Search Works - -1. **Type in search bar**: `@username@domain.com` -2. **Solar Network queries their instance**: - - Fetches their actor profile - - Checks if they're discoverable -3. **Shows results**: - - Profile picture - - Display name - - Bio - - Instance name - -### Supported Search Formats - -| Format | Example | Works? | -|--------|---------|--------| -| Full handle | `@alice@mastodon.social` | ✅ Yes | -| Username only | `alice` | ⚠️ May search local users first | -| Full URL | `https://mastodon.social/@alice` | ✅ Yes | - -## Privacy Considerations - -### Public Posts -- **What**: Posts visible to everyone -- **Federation**: ✅ Federates to all followers -- **Timeline**: Visible in public federated timelines -- **Example**: General updates, thoughts, content you want to share - -### Private Posts -- **What**: Posts only visible to followers -- **Federation**: ✅ Federates to followers (including remote) -- **Timeline**: Only visible to your followers -- **Example**: Personal updates, questions - -### Unlisted Posts -- **What**: Posts not in public timelines -- **Federation**: ✅ Federates but marked unlisted -- **Timeline**: Only followers see it -- **Example**: Limited audience content - -### Followers-Only Posts -- **What**: Posts only to followers, no federated boost -- **Federation**: ⚠️ May not federate fully -- **Timeline**: Only your followers -- **Example**: Very sensitive content - -## Following Etiquette - -### Best Practices - -1. **Check before following**: - - Read their bio and recent posts - - Make sure they're who you think they are - - Check if their content aligns with your interests - -2. **Start with interactions**: - - Like a few posts first - - Reply thoughtfully - - Share interesting content - - Then follow if you want to see more - -3. **Respect instance culture**: - - Each instance has its own norms - - Read their community guidelines - - Be mindful of local rules - -4. **Don't spam**: - - Don't mass-follow users - - Don't send unwanted DMs - - Don't repeatedly like old posts - -5. **Use appropriate post visibility**: - - Public for general content - - Unlisted for updates to followers - - Private for sensitive topics - -### Red Flags to Watch - -1. **Suspicious accounts**: - - Newly created with generic content - - Only posting promotional links - - Unusual following patterns - -2. **Instances with poor moderation**: - - Lots of spam in public timelines - - Harassment goes unaddressed - - You may want to block the instance - -3. **Content warnings not respected**: - - Users posting unmarked sensitive content - - You can report/block these users - -## Troubleshooting - -### "Follow button doesn't work" - -**Possible causes**: -1. User doesn't exist -2. Instance is down -3. Network connectivity issue - -**What to do**: -1. Verify the username/domain is correct -2. Try searching for them again -3. Check your internet connection -4. Try again in a few minutes - -### "User doesn't appear in Following list" - -**Possible causes**: -1. Follow was rejected (locked account) -2. Follow is still pending -3. Error in federation - -**What to do**: -1. Check if their account is locked -2. Wait a few minutes for acceptance -3. Check your ActivityPub logs -4. Try following again - -### "Can't find a user via search" - -**Possible causes**: -1. Username/domain is wrong -2. User's instance is blocking your instance -3. User's profile is not discoverable - -**What to do**: -1. Double-check the spelling -2. Try their full URL: `https://instance.com/@username` -3. Check if they're from a blocked instance -4. Contact them directly for their handle - -## API Reference - -### Follow a Remote User - -**Endpoint**: `POST /api/activitypub/follow` - -**Request**: -```json -{ - "targetActorUri": "https://mastodon.social/users/alice" -} -``` - -**Success Response**: -```json -{ - "success": true, - "message": "Follow request sent. Waiting for acceptance.", - "targetActorUri": "https://mastodon.social/users/alice" -} -``` - -### Get Your Following - -**Endpoint**: `GET /api/activitypub/following?limit=50` - -**Response**: -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "I love tech!", - "avatarUrl": "https://...", - "followedAt": "2024-01-15T10:30:00Z", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -### Get Your Followers - -**Endpoint**: `GET /api/activitypub/followers?limit=50` - -**Response**: -```json -{ - "users": [ - { - "actorUri": "https://pleroma.site/users/bob", - "username": "bob", - "displayName": "Bob Jones", - "bio": "Federated user following me", - "avatarUrl": "https://...", - "followedAt": "2024-01-10T14:20:00Z", - "isLocal": false, - "instanceDomain": "pleroma.site" - } - ] -} -``` - -### Search Users - -**Endpoint**: `GET /api/activitypub/search?query=@alice@domain.com&limit=20` - -**Response**: -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "Tech enthusiast", - "avatarUrl": "https://...", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -## Real Examples - -### Example 1: Following a Mastodon User - -**What you do**: -1. Search for `@alice@mastodon.social` -2. Click on Alice's profile -3. Click "Follow" button -4. Wait 1-2 seconds -5. ✅ Alice appears in your "Following" list -6. ✅ Alice's public posts appear in your timeline - -**What happens technically**: -- Solar Network sends Follow to Alice's Mastodon instance -- Alice's Mastodon auto-accepts (unless locked) -- Mastodon sends Accept back to Solar Network -- Relationship stored in both databases -- Alice's future posts federate to Solar Network - -### Example 2: Following a Locked Account - -**What you do**: -1. Search for `@private@pleroma.site` -2. Click "Follow" button -3. ✅ See "Following..." (pending) -4. Wait for user to approve - -**What happens technically**: -- Solar Network sends Follow to private@pleroma.site -- Private user receives notification -- Private user manually approves the request -- Private user's instance sends Accept -- ✅ Now following! - -### Example 3: Following a Bot Account - -**What you do**: -1. Search for `@news@botsin.space` -2. Click "Follow" button -3. ✅ Immediately following (bots auto-accept) - -**What happens technically**: -- Follow is auto-accepted -- News posts appear in your timeline -- Regular updates from the bot - -## Key Differences from Traditional Social Media - -| Aspect | Traditional Social | ActivityPub | -|---------|------------------|-------------| -| Central server | ❌ No | ✅ Yes (per instance) | -| Multiple platforms | ❌ No | ✅ Yes (Mastodon, Pleroma, etc.) | -| Data ownership | ❌ On their servers | ✅ On your server | -| Blocking | ❌ One platform | ✅ Per instance | -| Migration | ❌ Difficult | ✅ Use your own domain | -| Federation | ❌ No | ✅ Built-in | - -## Getting Help - -If you have issues following users: - -1. **Check the main guide**: See `HOW_TO_FOLLOW_FEDIVERSE_USERS.md` -2. **Check your logs**: Look for ActivityPub errors -3. **Test the API**: Use curl to test follow endpoints directly -4. **Verify the user**: Make sure the user exists on their instance - -## Summary - -Following fediverse users in Solar Network: - -1. **Simple**: Just search and click "Follow" -2. **Works both ways**: You can follow them, they can follow you -3. **Works across instances**: Mastodon, Pleroma, Lemmy, etc. -4. **Federated content**: Their posts appear in your timeline -5. **Full interactions**: Like, reply, boost their posts - -It works just like following on any other social platform, but with the added benefit of being able to follow users on completely different services! 🌍 diff --git a/docs/activitypub/FOLLOW_FEDIVERSE_USER.md b/docs/activitypub/FOLLOW_FEDIVERSE_USER.md deleted file mode 100644 index af59021e..00000000 --- a/docs/activitypub/FOLLOW_FEDIVERSE_USER.md +++ /dev/null @@ -1,406 +0,0 @@ -# How to Follow (Subscribe to) Fediverse Users in Solar Network - -## Overview - -In ActivityPub terminology, "subscribing" to a user is called **"following"**. This guide explains how users in Solar Network can follow users from other federated services (Mastodon, Pleroma, etc.). - -## User Guide: How to Follow Fediverse Users - -### Method 1: Via Search (Recommended) - -1. **Search for the user**: - - Type their full address in the search bar: `@username@domain.com` - - Example: `@alice@mastodon.social` - - Example: `@bob@pleroma.site` - -2. **View their profile**: - - Click on the search result - - You'll see their profile, bio, and recent posts - -3. **Click "Follow" button**: - - Solar Network sends a Follow activity to their instance - - The remote instance will send back an Accept - - The user now appears in your "Following" list - -### Method 2: Via Profile URL - -1. **Visit their profile directly**: - - If you know their profile URL, visit it directly - - Example: `https://mastodon.social/@alice` - -2. **Look for "Follow" button**: - - Click it to follow - -3. **Confirm the follow**: - - Solar Network will send the follow request - - Wait for acceptance (usually immediate) - -## What Happens Behind the Scenes - -### The Follow Flow - -``` -User clicks "Follow" - ↓ -Solar Network creates Follow Activity - ↓ -Solar Network signs with publisher's private key - ↓ -Solar Network sends to remote user's inbox - ↓ -Remote instance verifies signature - ↓ -Remote instance processes the Follow - ↓ -Remote instance sends Accept Activity back - ↓ -Solar Network receives and processes Accept - ↓ -Relationship is established! -``` - -### Timeline Integration - -Once you're following a user: -- ✅ Their public posts appear in your "Home" timeline -- ✅ Their posts are federated to your followers -- ✅ Their likes, replies, and boosts are visible -- ✅ You can interact with their content - -## Following Different Types of Accounts - -### Individual Users -- **What**: Regular users like you -- **Example**: `@alice@mastodon.social` -- **Works**: ✅ Full support - -### Organizational/Bot Accounts -- **What**: Groups, bots, or organizations -- **Example**: `@official@newsbot.site` -- **Works**: ✅ Full support - -### Locked Accounts -- **What**: Users who manually approve followers -- **Example**: `@private@pleroma.site` -- **Works**: ✅ Follow request sent, waits for approval - -## Managing Your Follows - -### View Who You're Following - -**API Endpoint**: `GET /api/activitypub/following` - -**Response Example**: -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "I love tech and coffee! ☕", - "avatarUrl": "https://cdn.mastodon.social/avatars/...", - "followedAt": "2024-01-15T10:30:00Z", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -### Unfollowing Someone - -**API Endpoint**: `POST /api/activitypub/unfollow` - -**Request Body**: -```json -{ - "targetActorUri": "https://mastodon.social/users/alice" -} -``` - -**Response**: -```json -{ - "success": true, - "message": "Unfollowed successfully" -} -``` - -## Searching Fediverse Users - -**API Endpoint**: `GET /api/activitypub/search?query=@username@domain.com` - -**Response Example**: -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "Software developer | Mastodon user", - "avatarUrl": "https://cdn.mastodon.social/avatars/...", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -## Follow States - -| State | Meaning | What User Sees | -|--------|---------|----------------| -| Pending | Follow request sent, waiting for response | "Following..." (loading) | -| Accepted | Remote user accepted | "Following" ✓ | -| Rejected | Remote user declined | "Follow" button available again | -| Failed | Error occurred | "Error following" message | - -## Privacy & Visibility - -### Public Posts -- ✅ Federate to your followers automatically -- ✅ Appear in remote instances' timelines -- ✅ Can be boosted/liked by remote users - -### Private Posts -- ❌ Do not federate -- ❌ Only visible to your local followers -- ❌ Not sent to remote instances - -### Unlisted Posts -- ⚠️ Federate but not in public timelines -- ⚠️ Only visible to followers - -## Best Practices for Users - -### When Following Someone - -1. **Check their profile first**: - - Make sure they're who you think they are - - Read their bio to understand their content - -2. **Start with a few interactions**: - - Like a few posts - - Reply to something interesting - - Don't overwhelm their timeline - -3. **Respect their instance's rules**: - - Each instance has its own guidelines - - Read community rules before interacting - -4. **Report spam/harassment**: - - Use instance blocking features - - Report to instance admins - -### Following Across Instances - -1. **Use their full address**: - - `@username@instance.com` - - This helps identify which instance they're on - -2. **Be aware of instance culture**: - - Each instance has its own norms - - Some are more technical, others more casual - -3. **Check if they're from your instance**: - - Local users show `isLocal: true` - - Usually faster interaction - -## Troubleshooting - -### "Follow button doesn't work" - -**Possible Causes**: -1. User doesn't exist -2. Instance is down -3. Network issue - -**Solutions**: -1. Verify the user's address is correct -2. Check if the instance is accessible -3. Check your internet connection -4. Try again in a few minutes - -### "User doesn't appear in Following list" - -**Possible Causes**: -1. Follow was rejected -2. Still waiting for acceptance (locked accounts) -3. Error in federation - -**Solutions**: -1. Check the follow status via API -2. Try following again -3. Check if their account is locked -4. Contact support if issue persists - -### "Can't find a user" - -**Possible Causes**: -1. Wrong username or domain -2. User doesn't exist -3. Instance blocking your instance - -**Solutions**: -1. Double-check the address -2. Try searching from a different instance -3. Contact the user directly for their handle - -## API Reference - -### Follow a Remote User - -**Endpoint**: `POST /api/activitypub/follow` - -**Request**: -```json -{ - "targetActorUri": "https://mastodon.social/users/alice" -} -``` - -**Response**: `200 OK` -```json -{ - "success": true, - "message": "Follow request sent. Waiting for acceptance.", - "targetActorUri": "https://mastodon.social/users/alice" -} -``` - -### Get Following List - -**Endpoint**: `GET /api/activitypub/following?limit=50` - -**Response**: `200 OK` -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "...", - "avatarUrl": "...", - "followedAt": "2024-01-15T10:30:00Z", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -### Get Followers List - -**Endpoint**: `GET /api/activitypub/followers?limit=50` - -**Response**: `200 OK` -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "...", - "avatarUrl": "...", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -### Search Users - -**Endpoint**: `GET /api/activitypub/search?query=alice&limit=20` - -**Response**: `200 OK` -```json -{ - "users": [ - { - "actorUri": "https://mastodon.social/users/alice", - "username": "alice", - "displayName": "Alice Smith", - "bio": "...", - "avatarUrl": "...", - "isLocal": false, - "instanceDomain": "mastodon.social" - } - ] -} -``` - -## What's Different About ActivityPub Following? - -Unlike traditional social media: - -| Feature | Traditional Social | ActivityPub | -|---------|------------------|-------------| -| Central server | ✅ Yes | ❌ No - federated | -| All users on same platform | ✅ Yes | ❌ No - multiple platforms | -| Blocked instances | ❌ No | ✅ Yes - instance blocking | -| Following across platforms | ❌ No | ✅ Yes - works with Mastodon, Pleroma, etc. | -| Your data stays on your server | ❌ Maybe | ✅ Yes - you control your data | - -## User Experience Considerations - -### Making It Easy - -1. **Auto-discovery**: - - When users search for `@username`, suggest `@username@domain.com` - - Offer to search the fediverse - -2. **Clear UI feedback**: - - Show "Follow request sent..." - - Show "They accepted!" notification - - Show "Follow request rejected" message - -3. **Helpful tooltips**: - - Explain what ActivityPub is - - Show which instance a user is from - - Explain locked accounts - -4. **Profile badges**: - - Show instance icon/logo - - Show if user is from same instance - - Show if user is verified - -## Examples - -### Following a Mastodon User - -**User searches**: `@alice@mastodon.social` - -**What happens**: -1. Solar Network fetches Alice's actor profile -2. Solar Network stores Alice in `fediverse_actors` -3. Solar Network sends Follow to Alice's inbox -4. Alice's instance accepts -5. Solar Network stores relationship in `fediverse_relationships` -6. Alice's posts now appear in user's timeline - -### Following a Local User - -**User searches**: `@bob` - -**What happens**: -1. Solar Network finds Bob's publisher -2. Relationship created locally (no federation needed) -3. Bob's posts appear in user's timeline immediately -4. Same as traditional social media following - -## Summary - -Following fediverse users in Solar Network: - -1. **Search by `@username@domain.com`** - Works for any ActivityPub instance -2. **Click "Follow"** - Sends federated follow request -3. **Wait for acceptance** - Remote user can approve or auto-accept -4. **See their posts in your timeline** - Content federates to you -5. **Interact normally** - Like, reply, boost, etc. - -All of this is handled automatically by the ActivityPub implementation! diff --git a/docs/activitypub/UI_IMPLEMENTATION.md b/docs/activitypub/UI_IMPLEMENTATION.md deleted file mode 100644 index 85ede0c4..00000000 --- a/docs/activitypub/UI_IMPLEMENTATION.md +++ /dev/null @@ -1,298 +0,0 @@ -# ActivityPub UI Implementation - -## Overview - -Complete UI implementation for ActivityPub features in Solian client, including search, following, and followers screens. - -## Created Files - -### 1. Widgets (`lib/widgets/activitypub/`) - -#### `activitypub.dart` -- **Purpose**: Export file for ActivityPub widgets -- **Exports**: `ActivityPubUserListItem` - -#### `user_list_item.dart` -- **Purpose**: Reusable list item widget for displaying ActivityPub users -- **Features**: - - Avatar with remote instance indicator (public icon) - - Display name with instance badge (e.g., "mastodon.social") - - Bio with truncation (max 2 lines) - - Followed at timestamp (relative time) - - Follow/Unfollow buttons with loading states - - Tap callback for navigation to profile - -### 2. Screens (`lib/screens/activitypub/`) - -#### `activitypub.dart` -- **Purpose**: Export file for ActivityPub screens -- **Exports**: `ActivityPubSearchScreen`, `ActivityPubListScreen` - -#### `search.dart` -- **Purpose**: Search and follow ActivityPub users from other instances -- **Features**: - - Search bar with 500ms debounce - - Real-time search results - - Instant follow/unfollow actions - - Local tracking of followed users - - Empty states for no search and no results - - Refresh support via pull-to-refresh - - User feedback via snack bars -- **User Flow**: - 1. User enters search query (e.g., `@alice@mastodon.social`) - 2. Results appear after debounce - 3. User taps "Follow" → Follow request sent - 4. Success message shown - 5. Button updates to "Unfollow" - -#### `list.dart` -- **Purpose**: Display following/followers lists -- **Features**: - - Reusable for both Following and Followers - - Local state management - - Per-user loading states during actions - - Empty states with helpful hints - - Refresh support - - Auto-update lists when actions occur -- **Types**: - - `ActivityPubListType.following`: Shows users you follow - - `ActivityPubListType.followers`: Shows users who follow you -- **User Flow**: - 1. User opens Following/Followers screen - 2. List loads from API - 3. User can unfollow (Following tab) or follow (Followers tab) - 4. List updates automatically - 5. Success/error messages shown - -## Design Patterns - -### Follows Project Conventions - -1. **Material 3 Design**: All widgets use Material 3 components -2. **Styled Widget Package**: Used for `.padding()`, `.textColor()`, etc. -3. **Riverpod State Management**: Hooks for local state, providers for global state -4. **Error Handling**: `showErrorAlert()` from `alert.dart` for user feedback -5. **Success Feedback**: `showSnackBar()` for quick notifications -6. **Localization**: All strings use `.tr()` with placeholder args - -### Color Scheme & Theming - -- **Remote Badge**: Uses `Theme.colorScheme.primary` for indicator -- **Instance Tag**: Uses `Theme.colorScheme.secondaryContainer` -- **Text Colors**: Adaptive based on theme (dark/light) -- **States**: Loading indicators with standard `CircularProgressIndicator` - -### Spacing & Layout - -- **List Item Padding**: `EdgeInsets.only(left: 16, right: 12)` -- **Avatar Size**: 24px radius (48px diameter) -- **Badge Size**: Small (10px font) with 6px horizontal padding -- **Button Size**: Minimum 88px width, 36px height - -## Translations Added - -### New Keys in `assets/i18n/en-US.json` - -```json -{ - "searchFediverse": "Search Fediverse", - "searchFediverseHint": "Search by address, e.g. {}", - "searchFediverseEmpty": "Search for users on other ActivityPub instances", - "searchFediverseNoResults": "No users found for this search", - "following": "Following", - "followers": "Followers", - "follow": "Follow", - "unfollow": "Unfollow", - "followedUser": "Followed @{}", - "unfollowedUser": "Unfollowed @{}", - "followingEmpty": "You're not following anyone yet", - "followersEmpty": "No followers yet", - "followingEmptyHint": "Start by searching for users or explore other instances" -} -``` - -## Usage Examples - -### Using Search Screen - -```dart -import 'package:go_router/go_router.dart'; -import 'package:island/screens/activitypub/activitypub.dart'; - -// In navigation or route -Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ActivityPubSearchScreen(), - ), -); - -// Or using go_router -context.push('/activitypub/search'); -``` - -### Using List Screen - -```dart -// Following -ActivityPubListScreen( - type: ActivityPubListType.following, -); - -// Followers -ActivityPubListScreen( - type: ActivityPubListType.followers, -); -``` - -### Using User List Item Widget - -```dart -ActivityPubUserListItem( - user: user, - isFollowing: isFollowing, - isLoading: isLoading, - onFollow: () => handleFollow(user), - onUnfollow: () => handleUnfollow(user), - onTap: () => navigateToProfile(user), -); -``` - -## Integration Points - -### Navigation Integration - -To add ActivityPub screens to navigation: - -1. **Option A**: Add to existing tab/navigation structure -2. **Option B**: Add as standalone routes in `go_router` -3. **Option C**: Add to profile menu overflow menu - -### Service Integration - -All screens use `activityPubServiceProvider`: - -```dart -import 'package:island/services/activitypub_service.dart'; - -final service = ref.read(activityPubServiceProvider); -``` - -### Error Handling - -All errors are caught and displayed using: - -```dart -try { - // API call -} catch (err) { - showErrorAlert(err); -} -``` - -## Testing Checklist - -- [ ] Search for existing Mastodon user -- [ ] Search for Pleroma user -- [ ] Follow a user -- [ ] Unfollow a user -- [ ] View following list -- [ ] View followers list -- [ ] Test empty states -- [ ] Test loading states -- [ ] Test error handling -- [ ] Test dark mode -- [ ] Test RTL languages (if supported) - -## Technical Details - -### Dependencies - -**Already in project**: -- ✅ `cached_network_image` - For avatar images -- ✅ `easy_localization` - For translations -- ✅ `hooks_riverpod` - For state management -- ✅ `flutter_hooks` - For hooks (useState, useEffect, etc.) -- ✅ `material_symbols_icons` - For icons -- ✅ `relative_time` - For timestamp formatting -- ✅ `island/services/activitypub_service.dart` - API service (created earlier) -- ✅ `island/widgets/alert.dart` - Error/success dialogs -- ✅ `island/models/activitypub.dart` - Data models (created earlier) - -### Performance Considerations - -1. **Debounced Search**: 500ms delay prevents excessive API calls -2. **Local State Tracking**: `followingUris` Set prevents duplicate API calls -3. **Conditional Rebuilds**: Widget only rebuilds when necessary -4. **Image Caching**: Uses `CachedNetworkImageProvider` for avatars - -### Accessibility - -1. **Semantic Labels**: All ListTile widgets have proper content -2. **Touch Targets**: Minimum 44px touch targets for buttons -3. **Color Contrast**: Follows Material 3 color guidelines -4. **Loading Indicators**: Visual feedback during async operations - -## Future Enhancements - -### Potential Additions - -1. **Profile Integration**: Show ActivityPub profile details -2. **Post Timeline**: Show federated posts from followed users -3. **Instance Blocking**: Block entire ActivityPub instances -4. **Advanced Search**: Filter by instance, user type, etc. -5. **Batch Actions**: Follow/unfollow multiple users at once -6. **Suggested Users**: Show recommended users to follow -7. **Recent Activity**: Show recent interactions -8. **Notifications**: Follow/unfollow notifications - -### Localization - -Need to add same keys to other language files: -- `es-ES.json` -- `ja-JP.json` -- `ko-KR.json` -- etc. - -## Browser Testing - -Test with real ActivityPub instances: -- mastodon.social -- pixelfed.social -- lemmy.world -- pleroma.site -- fosstodon.org - -## Troubleshooting - -### Common Issues - -1. **Search returns no results** - - Check if user exists on remote instance - - Verify instance is accessible - - Try full URL instead of handle - -2. **Follow button not working** - - Check if user is already following - - Verify server is online - - Check API logs - -3. **Avatar not loading** - - Check remote avatar URL - - Verify network connection - - Check image cache - -## Summary - -✅ **Fully functional ActivityPub UI** with: -- Search screen for discovering fediverse users -- Following/Followers list screens -- Reusable user list item component -- Proper error handling and user feedback -- Material 3 design -- Responsive layout -- Local state management -- Debounced search -- Empty states and loading indicators - -**Ready for integration into main app navigation!** 🎉 diff --git a/lib/route_activitypub.patch b/lib/route_activitypub.patch deleted file mode 100644 index a7258e17..00000000 --- a/lib/route_activitypub.patch +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:island/screens/activitypub/activitypub.dart'; - -Add to Explore tab routes, after postCategoryDetail route: - - GoRoute( - name: 'activitypubSearch', - path: '/activitypub/search', - builder: (context, state) => const ActivityPubSearchScreen(), - ), - GoRoute( - name: 'activitypubFollowing', - path: '/activitypub/following', - builder: (context, state) => const ActivityPubListScreen( - type: ActivityPubListType.following, - ), - ), - GoRoute( - name: 'activitypubFollowers', - path: '/activitypub/followers', - builder: (context, state) => const ActivityPubListScreen( - type: ActivityPubListType.followers, - ), - ),