Expose external accounts as virtual Org Social feeds that any client
can follow with a plain #+FOLLOW: line:
- /bridge/activitypub/@{user}@{instance}/ bridges a Mastodon or any
ActivityPub account (WebFinger, actor and paginated outbox; only
public top-level notes, with CW, hashtags, language and attachments)
- /bridge/rss/?url={feed} bridges any RSS/Atom feed (entry title as
*** sub-heading, converted body and link to the original article)
Registration is implicit on first GET. Bridged data is stored in the
existing Profile/Post tables so /profile/, /search/ and the rest of
the API work on bridged feeds. Active bridges are refreshed every 15
minutes; bridges unrequested for 90 days are cleaned up.
Remote HTML is converted to Org text, escaping headline-like lines so
external content cannot inject posts. Fetches enforce the Webmention
SSRF protections, a 10s timeout and a 5MB size cap. Bridged posts
never queue Webmentions nor publish notifications.
115 lines
4.3 KiB
Python
115 lines
4.3 KiB
Python
from django.http import JsonResponse
|
|
|
|
|
|
def root_view(request):
|
|
"""Root endpoint with HATEOAS links"""
|
|
return JsonResponse(
|
|
{
|
|
"type": "Success",
|
|
"errors": [],
|
|
"data": {
|
|
"name": "Org Social Relay",
|
|
"description": "P2P system for Org Social files",
|
|
},
|
|
"_links": {
|
|
"self": {"href": "/", "method": "GET"},
|
|
"feeds": {"href": "/feeds/", "method": "GET"},
|
|
"add-feed": {"href": "/feeds/", "method": "POST"},
|
|
"feed-content": {
|
|
"href": "/feed-content/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"mentions": {
|
|
"href": "/mentions/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"replies": {
|
|
"href": "/replies/?post={post_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"notifications": {
|
|
"href": "/notifications/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"sse-notifications": {
|
|
"href": "/sse/notifications/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"sse-notifications-all": {
|
|
"href": "/sse/notifications/",
|
|
"method": "GET",
|
|
},
|
|
"reactions": {
|
|
"href": "/reactions/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"replies-to": {
|
|
"href": "/replies-to/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"boosts": {
|
|
"href": "/boosts/?post={post_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"interactions": {
|
|
"href": "/interactions/?post={post_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"search": {
|
|
"href": "/search/?q={query}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"groups": {"href": "/groups/", "method": "GET"},
|
|
"group-messages": {
|
|
"href": "/groups/{group_name}/",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"join-group": {
|
|
"href": "/groups/{group_name}/members/?feed={feed_url}",
|
|
"method": "POST",
|
|
"templated": True,
|
|
},
|
|
"polls": {"href": "/polls/", "method": "GET"},
|
|
"poll-votes": {
|
|
"href": "/polls/votes/?post={post_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"profile": {
|
|
"href": "/profile/?feed={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
},
|
|
"rss": {
|
|
"href": "/rss.xml",
|
|
"method": "GET",
|
|
"description": "RSS feed of latest posts (supports ?tag={tag} and ?feed={feed_url} filters)",
|
|
},
|
|
"stats": {"href": "/stats/", "method": "GET"},
|
|
"bridge": {"href": "/bridge/", "method": "GET"},
|
|
"bridge-activitypub": {
|
|
"href": "/bridge/activitypub/@{user}@{instance}/",
|
|
"method": "GET",
|
|
"templated": True,
|
|
"description": "ActivityPub account as a virtual social.org feed",
|
|
},
|
|
"bridge-rss": {
|
|
"href": "/bridge/rss/?url={feed_url}",
|
|
"method": "GET",
|
|
"templated": True,
|
|
"description": "RSS/Atom feed as a virtual social.org feed",
|
|
},
|
|
},
|
|
}
|
|
)
|