You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/copilot-instructions.md
+32Lines changed: 32 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,4 +20,36 @@ When developing UI components:
20
20
- Do not add code comments that explain what code does — write self-explanatory code instead.
21
21
- The project is in early development and changes frequently; keep implementations simple and avoid over-engineering.
22
22
- If an opportunity to simplify or refactor existing code is noticed, ask the user before making those changes.
23
+
- Be targeted with your test execution.
23
24
25
+
## ActivityStreams `IObjectOrLink` Type Evaluation
26
+
27
+
Properties typed as `IEnumerable<IObjectOrLink>` (e.g. `Actor`, `Object`, `AttributedTo`, `InReplyTo`, `To`, etc.) can hold a mix of inline objects and unresolved references. The concrete runtime type is determined by the JSON:
|`{"type":"Link",...}` or `{"type":"Mention",...}`|`ILink`| Qualified link |
33
+
|`{"type":"Note",...}` (or any known type) |`IObject` (concrete subtype) | Inline object |
34
+
| Object with no `type`|`ObjectOrLink`| Anonymous object |
35
+
36
+
**Always check `ILink` first** — a plain URL string is the most common form of an unresolved actor/object reference:
37
+
38
+
```csharp
39
+
varref=activity.Actor?.FirstOrDefault();
40
+
if (refisILinklink)
41
+
actorId=link.Href?.ToString(); // unresolved — fetch if needed
42
+
elseif (refisActoractor)
43
+
actorId=actor.Id; // already inline
44
+
```
45
+
46
+
**`ILink` serializes back to a plain string** when `Href` is the only property set — so `is ILink` (not `is Link`) is the correct check for "unresolved reference".
47
+
48
+
**`IEnumerable<ILink>`** (e.g. `Object.Url`) always contains links — no need to type-check.
49
+
50
+
**`IImageOrLink`** (used for `Icon`/`Image`) only ever holds `Image` or `Link`.
51
+
52
+
**To dereference:** use `IActivityPubClient.GetAsync<T>(link.Href)`. Never assume an `IObjectOrLink` is a full object without checking `is IObject` first.
53
+
54
+
## 3rd Party Libraries
55
+
- If we need details for Kristoffer Strube's ActivityStreams .NET library, refer to the official GitHub repository: https://github.com/KristofferStrube/ActivityStreams
Copy file name to clipboardExpand all lines: README.md
+120-6Lines changed: 120 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,13 +6,104 @@ A modular .NET library for building ActivityPub-enabled applications.
6
6
7
7
Broca provides a complete, standards-compliant implementation of the ActivityPub protocol for .NET developers. It offers both client and server capabilities with a clean API that makes federation simple.
8
8
9
-
**Key Features:**
10
-
- ✅ Full ActivityPub client and server implementation
11
-
- ✅ HTTP Signatures for authenticated federation
9
+
## Features
10
+
11
+
### Core ActivityPub Protocol
12
+
13
+
**Client-to-Server (C2S)**
14
+
- ✅ Post activities to outbox (Create, Like, Follow, Announce, Undo)
15
+
- ✅ Server-assigned activity IDs with proper URL structure
16
+
- ✅ Follow/Unfollow relationship management
17
+
- ✅ HTTP Signature authentication for outbox operations
18
+
- ✅ API key-based client authentication
19
+
20
+
**Server-to-Server (S2S) Federation**
21
+
- ✅ Cross-server activity delivery with HTTP Signatures
22
+
- ✅ Background delivery queue with retry logic
23
+
- ✅ Follow/Accept/Reject workflow (auto-accept and manual approval modes)
24
+
- ✅ Undo operations (Follow, Like, Announce)
25
+
- ✅ Delete activities with Tombstone support
26
+
- ✅ Update Person for profile changes
27
+
- ✅ Move activity for account migration with `alsoKnownAs` validation
28
+
- ✅ Date validation (reject stale or future-dated requests)
29
+
- ✅ Actor caching and refresh
30
+
31
+
**Shared Inbox**
32
+
- ✅ Efficient batch delivery to multiple local users
33
+
- ✅ To, Cc, and Bcc addressing support
34
+
- ✅ Public addressing (`https://www.w3.org/ns/activitystreams#Public`)
All critical and high-priority federation features are complete. See [docs/s2s-compliance-todo.md](docs/s2s-compliance-todo.md) for detailed compliance tracking.
All tests use real HTTP clients and in-memory servers to validate end-to-end behavior, not mocked implementations. This ensures that Broca works correctly with actual ActivityPub clients and servers in the fediverse.
425
+
312
426
## Contributing
313
427
314
428
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for development workflow and guidelines.
`Move` is used by Mastodon for account portability. When a user migrates to a new account, followers are automatically migrated.
22
+
23
+
**Implementation:** Handles `Move` by updating the follower's following list: replaces the old actor IRI with the new one if the new actor's `alsoKnownAs` references the old one (prevents spoofing).
24
+
25
+
**Status:** ✅ Implemented and tested with security validation.
26
+
27
+
---
28
+
29
+
### M2 · Actor document missing `featured` collection (pinned posts)
30
+
31
+
**File:**`ActorController.cs` → `Get`
32
+
33
+
Mastodon expects a `featured` property on the actor document pointing to an `OrderedCollection` of pinned post URIs. Without it, Mastodon logs warnings and will never show pinned posts.
34
+
35
+
**Fix:** Add `featured` to the actor's extension data pointing to `{baseUrl}/users/{username}/collections/featured`. The collections infrastructure exists; needs to be exposed on the actor document.
36
+
37
+
**Priority:** Medium - affects user features but doesn't break federation.
38
+
39
+
---
40
+
41
+
### ✅ M3 · `alsoKnownAs` field supported (COMPLETED)
42
+
43
+
**File:**`ActorController.cs`
44
+
45
+
Required for `Move`-based account migration. Actors can declare aliases via the `alsoKnownAs` property.
46
+
47
+
**Implementation:** Supported via actor's ExtensionData dictionary. Set as a JSON array of actor URI strings.
48
+
49
+
**Status:** ✅ No code changes required - ExtensionData already serializes arbitrary fields in actor documents.
50
+
51
+
---
52
+
53
+
### M4 · Followers / Following collections expose full member list without authentication
For locked accounts (`manuallyApprovesFollowers = true`) this leaks the full social graph. Mastodon hides this behind authentication for locked actors.
58
+
59
+
**Fix:** Check if the actor has `manuallyApprovesFollowers = true` and, if so, require the requester to be authenticated (or return only the count with no items).
60
+
61
+
**Priority:** Medium - privacy concern for locked accounts.
62
+
63
+
---
64
+
65
+
## 🟢 Low / Cosmetic
66
+
67
+
### L4 · HTTP signature `ParseSignatureParts` splits on first `=` only
The outer `Split(',')` then inner `Split('=', 2)` approach is correct for most cases, but any Signature header component whose *value* legitimately contains a comma (after line-folding) would be mishandled.
72
+
73
+
**Fix:** Consider a more robust parser that handles quoted-string values per RFC 7230.
74
+
75
+
**Priority:** Low - rarely encountered in practice.
0 commit comments