activitypub/activitypub/manager/ap_routes.py

417 wiersze
14 KiB
Python

import re
from .base import app
WEBFINGER = re.compile(r'(?:acct:)?(?P<username>[\w.!#$%&\'*+-/=?^_`{|}~]+)@(?P<host>[\w.:-]+)')
@app.route("/user/<nickname>", ["GET"])
def route_user(self, nickname):
#obj = self.database.actors.find_one(id=nickname)
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/publickey", ["GET"])
def route_publickey(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/outbox", ["GET"])
def route_user_outbox(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/outbox/<page>", ["GET"])
def route_outbox_page(self, nickname, page):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
#@app.route("/user/<nickname>/outbox", ["POST"])
#def route_(self):
# return self.render_template("test.html")
@app.route("/user/<nickname>/inbox", ["GET"])
def route_inbox(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/inbox/<page>", ["GET"])
def route_inbox_page(self, nickname, page):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
#@app.route("/user/<nickname>/inbox", ["POST"])
#def route_(self):
# return self.render_template("test.html")
@app.route("/user/<nickname>/followers", ["GET"])
def route_followers(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/followers/<page>", ["GET"])
def route_followers_page(self, nickname, page):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/following", ["GET"])
def route_following(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/following/<page>", ["GET"])
def route_following_page(self, nickname, page):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/liked", ["GET"])
def route_liked(self, nickname):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/user/<nickname>/liked/<page>", ["GET"])
def route_liked_page(self, nickname, page):
obj = self.Actor(id=nickname)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>", ["GET"])
def route_activity(self, uuid):
obj = self.manager.Note(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/replies", ["GET"])
def route_activity_replies(self, uuid):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/replies/<page>", ["GET"])
def route_activity_replies_page(self, uuid, page):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/likes", ["GET"])
def route_activity_likes(self, uuid):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/likes/<page>", ["GET"])
def route_activity_likes_page(self, uuid, page):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/shares", ["GET"])
def route_activity_shares(self, uuid):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/activity/<uuid>/shares/<page>", ["GET"])
def route_activity_shares_page(self, uuid, page):
obj = self.Activity(id=uuid)
if obj:
return self.render_json(
obj.to_dict()
)
else:
return self.error(404)
@app.route("/content/<uuid>", ["GET"])
def route_content(self, uuid):
return self.render_template(
"test.html",
uuid=uuid,
)
@app.route("/content/<uuid>/replies", ["GET"])
def route_content_replies(self, uuid):
return self.render_template(
"test.html",
uuid=uuid,
)
@app.route("/content/<uuid>/replies/<page>", ["GET"])
def route_content_replies_page(self, uuid, page):
return self.render_template(
"test.html",
uuid=uuid,
page=page,
)
@app.route("/content/<uuid>/likes", ["GET"])
def route_content_likes(self, uuid):
return self.render_template(
"test.html",
uuid=uuid,
)
@app.route("/content/<uuid>/likes/<page>", ["GET"])
def route_content_likes_page(self, uuid, page):
return self.render_template(
"test.html",
uuid=uuid,
page=page,
)
@app.route("/content/<uuid>/shares", ["GET"])
def route_content_shares(self, uuid):
return self.render_template(
"test.html",
uuid=uuid,
)
@app.route("/content/<uuid>/shares/<page>", ["GET"])
def route_content_shares_page(self, uuid, page):
return self.render_template(
"test.html",
uuid=uuid,
page=page,
)
@app.route("/.well-known/webfinger", ["GET"])
def route_webfinger(self):
"""
?resource=acct:bob@my-example.com
"""
resource = self.get_argument("resource")
obj = None
if resource:
matches = WEBFINGER.match(resource)
if matches:
username = matches["username"]
host = matches["host"]
id = "https://%s/%s" % (host, username)
obj = self.database.actors.find_one({"id":id})
## Add a temp person:
#obj = self.Person(id="dsblank")
#self.database.actors.insert_one(obj.to_dict())
if obj:
return self.render_json({
"subject": resource,
"links": [{
"rel": "self",
"type": "application/activity+json",
"href": obj["id"]
}]
})
else:
return self.error(404)
"""
From: https://github.com/tootsuite/mastodon/blob/master/spec/fixtures/requests/activitypub-webfinger.txt
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/jrd+json; charset=utf-8
X-Content-Type-Options: nosniff
Date: Sun, 17 Sep 2017 06:22:50 GMT
{"subject":"acct:foo@ap.example.com","aliases":["https://ap.example.com/@foo","https://ap.example.com/users/foo"],"links":[{"rel":"http://webfinger.net/rel/profile-page","type":"text/html","href":"https://ap.example.com/@foo"},{"rel":"http://schemas.google.com/g/2010#updates-from","type":"application/atom+xml","href":"https://ap.example.com/users/foo.atom"},{"rel":"self","type":"application/activity+json","href":"https://ap.example.com/users/foo"},{"rel":"salmon","href":"https://ap.example.com/api/salmon/1"},{"rel":"magic-public-key","href":"data:application/magic-public-key,RSA.u3L4vnpNLzVH31MeWI394F0wKeJFsLDAsNXGeOu0QF2x-h1zLWZw_agqD2R3JPU9_kaDJGPIV2Sn5zLyUA9S6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh8lDET6X4Pyw-ZJU0_OLo_41q9w-OrGtlsTm_PuPIeXnxa6BLqnDaxC-4IcjG_FiPahNCTINl_1F_TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq-t8nhQYkgAkt64euWpva3qL5KD1mTIZQEP-LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3QvuHQ==.AQAB"},{"rel":"http://ostatus.org/schema/1.0/subscribe","template":"https://ap.example.com/authorize_follow?acct={uri}"}]}
From: https://mastodon.social/.well-known/webfinger?resource=acct:dsblank@mastodon.social
{"subject": "acct:dsblank@mastodon.social",
"aliases": ["https://mastodon.social/@dsblank",
"https://mastodon.social/users/dsblank"],
"links": [ {"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://mastodon.social/@dsblank"},
{"rel": "http://schemas.google.com/g/2010#updates-from",
"type":"application/atom+xml",
"href":"https://mastodon.social/users/dsblank.atom"},
{"rel":"self",
"type":"application/activity+json",
"href":"https://mastodon.social/users/dsblank"},
{"rel":"salmon",
"href":"https://mastodon.social/api/salmon/368878"},
{"rel":"magic-public-key",
"href":"data:application/magic-public-key,RSA.3L4-ufnddoOSl-YS6pel0q-tz01cjutYsl6sVM3QkJBX9T3Mp9MCarbbh5xEfttxIPCzZZAv1Yv_VRyOsexPi7CfF8z2pOjaZ-HD7KrwovhgiiL8YIwd_6o3qc5eCUibE56DyemUfqxWWNcvJH64D57cF0sMaZpx95DSQ5JKkcIq2M_M1Wm5AQZH5NIKnVyR55eOH7zN09mvZrK_S93b5DYaeBIjNwgtTBRDj4qqNtRtF5SM3_XmdWskA_KArP586W7CI4ZK538WbnT09JNA3d7TJQrwLXwkXJMX1nQARKQfyjbRbg2lXJcdHV_0pJqnJa9p24O0ysOtPN6LqL6v5w==.AQAB"},
{"rel":"http://ostatus.org/schema/1.0/subscribe",
"template":"https://mastodon.social/authorize_follow?acct={uri}"}
]
}
From: https://a4.io/.well-known/webfinger?resource=acct:t@a4.io
{"subject": "acct:t@a4.io",
"aliases": ["https://a4.io"],
"links": [{"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html", "href": "https://a4.io"},
{"rel": "self", "type": "application/activity+json", "href": "https://a4.io"},
{"rel": "http://ostatus.org/schema/1.0/subscribe", "template": "https://a4.io/authorize_follow?profile={uri}"},
{"rel": "magic-public-key", "href": "data:application/magic-public-key,RSA.zTYvKgiDIanj3XnpoGPdVmwq0A_FPqcoJXqMpNcIOVzWcOGK1WkxLeOnCcXhnxNnKpnXQIjU8MRz2y1tOfVEZHmII_hnOh2hcS3K5Sd_yHWnQkPgfnSBzn46mx3m8Nwi49qOZ0--ARGzVhOaBJhuUX2MvBrHl2A2GRjRtTnzACqFxB-ezZNGG6Ymvzv7CTCPXKUlygNqDy0Hi48SM_2LSmgotz5L0Vng3q33c9XeGR3YAiUlCevCDTyvIAkzN4hlP5zYezp_Bp7CkoY3teIvCaxZS5n92I_Oj2Xyq60v0MeXiqyXioGNPnUB8QtFV20kEhdwJik0_DubiRP_2Iy65w==.AQAB"},
{"href": "https://sos-ch-dk-2.exo.io/hexaninja/hexaninja-alpha.png", "rel": "http://webfinger.net/rel/avatar", "type": "image/png"}]
}
From https://willnorris.com/.well-known/webfinger?resource=acct:will@willnorris.com:
{
"subject": "acct:will@willnorris.com",
"aliases": [
"mailto:will@willnorris.com",
"https://willnorris.com/"
],
"links": [
{
"rel": "http://webfinger.net/rel/avatar",
"href": "https://willnorris.com/logo.jpg",
"type": "image/jpeg"
},
{
"rel": "http://webfinger.net/rel/profile-page",
"href": "https://willnorris.com/",
"type": "text/html"
}
]
}
{
"subject": "acct:alice@my-example.com",
"links": [
{
"rel": "self",
"type": "application/activity+json",
"href": "https://my-example.com/actor"
}
]
}
"""
# /api/v1/instance
"""
{
"uri":"mastodon.social",
"title":"Mastodon",
"description":"This page describes the mastodon.social \u003cem\u003einstance\u003c/em\u003e - wondering what Mastodon is? Check out \u003ca href=\"https://joinmastodon.org\"\u003ejoinmastodon.org\u003c/a\u003e instead! In essence, Mastodon is a decentralized, open source social network. This is just one part of the network, run by the main developers of the project \u003cimg draggable=\"false\" alt=\"🐘\" class=\"emojione\" src=\"https://mastodon.social/emoji/1f418.svg\" /\u003e It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!",
"email":"hello@joinmastodon.org",
"version":"2.4.3",
"urls": {
"streaming_api":"wss://mastodon.social"
},
"stats": {
"user_count":171746,
"status_count":6467133,
"domain_count":5177
},
"thumbnail":"https://files.mastodon.social/site_uploads/files/000/000/001/original/DN5wMUeVQAENPwp.jpg_large.jpeg",
"languages":["en"],
"contact_account": {
"id":"1",
"username":"Gargron",
"acct":"Gargron",
"display_name":"Eugen",
"locked":false,
"bot":false,
"created_at":"2016-03-16T14:34:26.392Z",
"note":"\u003cp\u003eDeveloper of Mastodon. 25\u003c/p\u003e",
"url":"https://mastodon.social/@Gargron",
"avatar":"https://files.mastodon.social/accounts/avatars/000/000/001/original/eb9e00274b135808.png",
"avatar_static":"https://files.mastodon.social/accounts/avatars/000/000/001/original/eb9e00274b135808.png",
"header":"https://files.mastodon.social/accounts/headers/000/000/001/original/af58e4df0e8b3e15.png",
"header_static":"https://files.mastodon.social/accounts/headers/000/000/001/original/af58e4df0e8b3e15.png",
"followers_count":92732,
"following_count":530,
"statuses_count":40388,
"emojis":[],
"fields":[
{
"name":"Patreon",
"value":"\u003ca href=\"https://www.patreon.com/mastodon\" rel=\"me nofollow noopener\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"\"\u003epatreon.com/mastodon\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e"
},
{
"name":"Liberapay",
"value":"\u003ca href=\"https://liberapay.com/Mastodon/\" rel=\"me nofollow noopener\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003eliberapay.com/Mastodon/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e"
}
]
}
}
"""