ActivityStreams and ActivityPub in Elixir.
The main part of the library code is a literal translation from the go-fed package written in Go.
Property modules for the ActivityStreams ontology are
generated using mix ontology.gen
.
Type value modules are hand-coded for now.
See https://github.com/go-fed/activity/tree/master/astool for the details on how this worked in go-fed. In this project we do a simpler, non-type-checked parsing of the ontology .jsonld file that go-fed curated from the ActivityStreams vocabulary and specification.
See the README for the fedi_server
example application, in the
"examples" folder, for a simple Phoenix web app that uses this library
to implement basic ActivityPub handling.
If available in Hex, the package can be installed
by adding fedi
to your list of dependencies in mix.exs
:
def deps do
[
{:fedi, "~> 0.1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/fedi.
See IMPLMENTATION.md for test suite coverage, in order to assess the conformance of the library and example application to the ActivityPub specification for both the Social API (client-to-server interactions) and the Federated Protocol (server-to-server interactions).
The example application uses a user token stored in a session cookie,
possibly fetched from a persistent "remember_me" cookie,
to authenticate activities posted to the outbox for the Social API,
following the standard methods of phx.gen.auth
.
For the Federated protocol, the application creates HTTP signatures on outgoing activities posted to remote inboxes, and validates HTTP signatures for activities arriving at local inboxes.
There is also support for 'webfinger', 'host-meta' and 'nodeinfo' endpoints in the example application.
Status URLS
id
- "https://mastodon.cloud/users/pzingg/statuses/109365863602876549"url
- "https://mastodon.cloud/@pzingg/109365863602876549"
The application supports these singleton items via GET requests:
/@:nickname
(HTML shows user profile and timeline. JSON shows user profile only.)/@:nickname/:object_id
/users/:nickname
(HTML shows user profile and timeline. JSON shows user profile only.)/users/:nickname/statuses/:object_id
The application supports these collections via GET requests:
/@:nickname/:object_id/likes
(TODO)/@:nickname/:object_id/shares
(TODO)/@:nickname/:object_id/reblogs
(TODO)/@:nickname/:object_id/favourites
(TODO)/@:nickname/featured
(TODO)/@:nickname/followers
(JSON)/@:nickname/following
(JSON)/@:nickname/liked
(TODO)/@:nickname/media
(TODO. HTML only - media)/@:nickname/with_replies
(TODO. HTML only - posts and replies)/@:nickname
(HTML only - posts)/inbox
(TODO - JSON - shared inbox)/users/:nickname/followers
(JSON)/users/:nickname/following
(JSON)/users/:nickname/inbox
(Accept JSON-LD only)/users/:nickname/outbox
(Accept JSON-LD only)/users/:nickname/media
(TODO; media)/users/:nickname/collections/featured
(TODO)/users/:nickname/collections/liked
(TODO)/users/:nickname/statuses/:object_id/likes
(TODO)/users/:nickname/statuses/:object_id/shares
(TODO)/users/:nickname/statuses/:object_id/reblogs
(TODO)/users/:nickname/statuses/:object_id/favourites
(TODO)/users/:nickname/with_replies
(TODO - posts and replies)/users/:nickname
(JSON gives user profile. HTML redirects to/@:nickname
- posts)
as well as ad-hoc account collections.
The example application also has some rudimentary "web" support
a la Mastodon. It supports only Note
objects posted in Markdown
format, but is able to parse out hyperlinks, mentions and hashtags,
and can display Note content as HTML with links for these.
There are also basic stubs for the Mastodon timelines "Home", "Local" and "Federated".
The routes for these "web" urls are:
/web/accounts/:nickname
(HTML shows user profile and timeline.)/web/directory
/web/bookmarks
(TODO)/web/favorites
(TODO)/web/statuses/:object_id
/web/timelines/home
/web/timelines/local
/web/timelines/direct
(TODO. Direct messages only)/web/timelines/federated
(TODO)
Add more Mastodon-ish features that are not in the AP spec if they are easy to implement.
%{
"type" => "Create",
"to" => "as:Public",
"cc" => [
"https://example.com/users/me/followers",
"https://other.example/users/mentioned"
],
"actor" => "https://example.com/users/me",
"object" => %{
"type" => "Note",
"id" => "https://example.com/users/original/objects/OBJECTID",
"content" => "**My Markdown post** mentioning @mentioned@other.example",
"attributedTo" => "https://example.com/users/me",
"tag" => [
%{
"type" => "Mention",
"href" => "https://other.example/users/mentioned",
"name" => "@mentioned@other.example"
}
]
}
}
Must not have any "as:Public" or follower audience.
%{
"type" => "Create",
"to" => "https://example.com/users/someone",
"actor" => "https://example.com/users/me",
"object" => %{
"type" => "Note",
"id" => "https://example.com/users/original/objects/OBJECTID",
"content" => "**My Markdown message**",
"attributedTo" => "https://example.com/users/me"
}
}
%{
"type" => "Create",
"to" => [
"https://example.com/users/original",
"https://example.com/users/me/followers"
],
"cc" => [
"as:Public",
"https://other.example/users/mentioned"
],
"actor" => "https://example.com/users/me",
"object" => %{
"type" => "Note",
"content" => "@original@example.com **My Markdown reply**",
"attributedTo" => "https://example.com/users/me",
"inReplyTo" => "https://example.com/users/original/objects/OBJECTID",
"tag" => [
%{
"type" => "Mention",
"href" => "https://example.com/users/original",
"name" => "@original@example.com"
}
]
}
}
%{
"type" => "Announce",
"to" => "as:Public",
"cc" => [
"https://example.com/users/me/followers",
"https://other.example/users/mentioned"
],
"actor" => "https://example.com/users/me",
"object" => "https://example.com/users/original/objects/OBJECTID"
}
Favorites can be shared or not?
%{
"type" => "Add",
"to" => "https://example.com/users/me",
"actor" => "https://example.com/users/me",
"object" => "https://example.com/users/original/objects/OBJECTID",
"target" => "https://example.com/users/me/favorites"
}
Bookmarks can be shared or not?
%{
"type" => "Add",
"to" => "https://example.com/users/me",
"actor" => "https://example.com/users/me",
"object" => "https://example.com/users/original/objects/OBJECTID",
"target" => "https://example.com/users/me/bookmarks"
}
Muting hides the user from your view:
- You won’t see the user in your home feed
- You won’t see other people boosting the user
- You won’t see other people mentioning the user
- You won’t see the user in public timelines
- Can have an expiration time
Blocking hides a user from your view:
- You won’t see the user in your home feed
- You won’t see other people boosting the user
- You won’t see other people mentioning the user
- You won’t see the user in public timelines
- You won’t see notifications from that user
Additionally, on the blocked user’s side:
- The user is forced to unfollow you
- The user cannot follow you
- The user won’t see other people’s boosts of you
- The user won’t see you in public timelines
- If you and the blocked user are on the same server, the blocked user will not be able to view your posts on your profile while logged in.
If you block an entire server:
- You will not see posts from that server on the public timelines
- You won’t see other people’s boosts of that server in your home feed
- You won’t see notifications from that server
- You will lose any followers that you might have had on that server
- RSS 2.0 support, with Dave Winer markdown ideas
- RSSCloud server support for notifications
- Provide clear instructions for how to hook the library up to a Phoenix application.
- Document the
ontology.gen
mix task.
- Limit the ranges and domains of properties and types according to the .jsonld ontology.
- Add builder methods (new, clear, set, get, etc) to restrict programmatic access to valid ranges and domains.
Fedi.Application.endpoint_url/0
should fetch the external endpoint URL from the implementing application, not the other way around. Maybe this can be done with a__using__
macro, set up in the implementing application.