Closed snarfed closed 5 years ago
I wonder whether can somehow tell the instance that we don't care about following, by which I mean: just allow anyone to follow you. I figure that since it's your site on the fediverse, and anything on your site is public, it doesn't really matter having to confirm a follower.
Not sure which property we'd have to set then - and if possible at all.
It's probably the 'locked' property, and it's set to false, so yeah, bridgy probably needs to respond here. Did you see a request coming in by any chance on bridgy ? :)
yes! here it is. bridgy fed responded with HTTP 501 Not Implemented.
POST https://fed.brid.gy/realize.be/inbox
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"sensitive": "as:sensitive",
"movedTo": {
"@id": "as:movedTo",
"@type": "@id"
},
"Hashtag": "as:Hashtag",
"ostatus": "http://ostatus.org#",
"atomUri": "ostatus:atomUri",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
},
"featured": {
"@id": "toot:featured",
"@type": "@id"
},
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value"
}
],
"id": "https://mastodon.social/6d1af0b9-ef6a-46b0-b662-f79b21d7c983",
"type": "Follow",
"actor": "https://mastodon.social/users/swentel",
"object": "https://fed.brid.gy/realize.be",
"signature": {
"type": "RsaSignature2017",
"creator": "https://mastodon.social/users/swentel#main-key",
"created": "2018-09-20T17:10:37Z",
"signatureValue": "[REDACTED]"
}
}
it'd probably actually be a pretty simple change to just reply to all AP Follows with AP Accept. feel free to try!
So, I've gotten to the point where I could actually send a request, but the response returned 'Request not signed'.
I've attached the WIP patch. The source_domain is hard coded right now. As I was testing with the output from above, I guess it can never work since the signatureValue is not available there - unless I read the spec wrong for Accept and maybe the signature is not needed anyway there.
sleeping time now, tips appreciated :)
thanks again for working on this! you're right, mastodon requires all inbox POSTs to include a signature: https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
if you want to test with your existing bridgy fed based realize.be account, i'm happy to send you your private key, via IRC DM or however.
alternatively, you could make your own bridgy fed app engine app, deploy there, and switch your site to redirect .well-known/*
to it instead, and test with it.
or, if you're ambitious, you could do what i did to test bridgy fed: run a website on localhost, and also run a mastodon instance on localhost, and test between them! i can send you lots of detailed raw notes from when i did this; they may or may not help. 😬
If you could send me the private key that would be great. I want to try and get the existing 'Follow' request confirmed, so it be handier to use the realize.be account. You can send it to swentel @ gmail.
Silly question then maybe, where do I put it exactly ? :)
Edit: I see the new generated key in datastore viewer, so I should probably import it there ..
Thanks for the mail! Didn't resolve anything yet though. When checking the mastodon source, it looks for the 'Signature' in the headers. Which makes me wonder why it works in send_webmentions (like and repost work the same I guess). I copied the code more or less from there. So a bit clueless now how to proceed further to be honest :/
So, because I'm better at PHP, I exported my private key and than started hacking around, and guess what. I got it working :) It took me a while to create the proper object and signature, but now https://mastodon.social/users/swentel/following is following @realize@realize.be
(if you would search for swentel, you'd also see that the bridgy user knows it has one follower, also cool).
So, this is how the headers looked like for the accept request:
Array
(
[Content-Type] => application/activity+json
[date] => Sat, 22 Sep 2018 20:45:01 GMT
[signature] => keyId="https://fed.brid.gy/realize.be#main-key",algorithm="rsa-sha256",headers="date",signature="REDACTED"
)
This is how the accept object looked liked that made it work eventually. It took a couple of iterations as I was getting 202 back but nothing happened until the right format - rings a bell right ;-) (I will experiment with the reply thing this weekend to see if I can make it work too by experimenting with the format) The id is a uuid. Other than that, format is really straightforward
(
[type] => Accept
[id] => d0ca0cd7-7115-4003-9ef8-18b584fc70e9
[@context] => https://www.w3.org/ns/activitystreams
[actor] => https://fed.brid.gy/realize.be
[object] => stdClass Object
(
[type] => Follow
[actor] => https://mastodon.social/users/swentel
[object] => https://fed.brid.gy/realize.be
)
)
Note, this also returns a 202, which is kind of annoying, but I did it twice now. I unfollowed, then did a follow request again, ran the command from my local machine and the accept was ok.
Also, this is how a follow activity looks like, which even easier.
(
[type] => Follow
[id] => d0ca0cd7-7115-4003-9ef8-18b584fc70e9
[@context] => https://www.w3.org/ns/activitystreams
[actor] => https://fed.brid.gy/realize.be
[object] => https://mastodon.social/users/swentel
)
So giving that information, I think I can get the object formatted ok in python, not sure about the signature though, but I will give it a shot.
hey, nice progress! thanks for the detailed investigation!
you may be right about the HTTP Signature header. bridgy fed uses the httpsig library, which says in its docs:
Known Limitations ; ...
Draft 2 added support for the Signature header. As this was principally designed to be an authentication helper, that header is not currently supported. PRs welcome.
presumably right now it uses the Authorization header instead. maybe this is why bridgy fed's other AP requests to Mastodon now often 202 and fail too? I'll add it to my list to try!
ahh my memory is awful. i discussed this with that library's author a while ago: https://github.com/ahknight/httpsig/issues/9
presumably right now it uses the Authorization header instead. maybe this is why bridgy fed's other AP requests to Mastodon now often 202 and fail too
Hard to say. I've been testing with sending a AP reply now using the Signature header and getting 202 back all the time as well. If I change one character in the signature, the authorization fails, so it means we're getting through, but we don't have a clear idea what happens next then. I'm digging through the mastodon code, because the 202 is not helpful at all :/
With replies now working, the party can start for real now :)
Getting the 'accept' response in might be crucial to start growing an audience, I'll see if I can update my patch for that part!
So think this should actually be workable .. :) The request is to mastodon, but signature fails locally.
Also, the way I get the source_domain is absolutely horrible, but it's a bit to late right now.
diff --git a/activitypub.py b/activitypub.py
index 871208a..9d8a357 100644
--- a/activitypub.py
+++ b/activitypub.py
@@ -1,7 +1,9 @@
"""Handles requests for ActivityPub endpoints: actors, inbox, etc.
"""
+import datetime
import json
import logging
+import string
import appengine_config
@@ -12,13 +14,15 @@ from oauth_dropins.webutil import util
import webapp2
import common
-from models import MagicKey
+from models import MagicKey, Response
+from httpsig.requests_auth import HTTPSignatureAuth
SUPPORTED_TYPES = (
'Announce',
'Article',
'Audio',
'Create',
+ 'Follow',
'Image',
'Like',
'Note',
@@ -83,6 +87,10 @@ class InboxHandler(webapp2.RequestHandler):
# TODO: verify signature if there is one
+ if type == 'Follow':
+ accept_follow(activity)
+ return
+
# fetch actor if necessary so we have name, profile photo, etc
if type in ('Like', 'Announce'):
for elem in obj, activity:
@@ -95,6 +103,46 @@ class InboxHandler(webapp2.RequestHandler):
common.send_webmentions(self, as1, protocol='activitypub',
source_as2=json.dumps(activity))
+def accept_follow(activity):
+ logging.info('Sending Accept to inbox')
+
+ activity_accept = {
+ '@context': 'https://www.w3.org/ns/activitystreams',
+ 'id': activity['id'],
+ 'type': 'Accept',
+ 'actor': activity['object'],
+ 'object': {
+ 'type': 'Follow',
+ 'actor': activity['actor'],
+ 'object': activity['object'],
+ }
+ }
+
+ # source domain - this is still wrong in so many ways ... :)
+ source_domain = string.replace(activity['object'], 'https://fed.brid.gy/r/', '')
+ source_domain = string.replace(source_domain, 'http://', '')
+ source_domain = string.replace(source_domain, 'https://', '')
+ logging.info('source domain ' + source_domain)
+
+ # inbox url.
+ target = activity['actor']
+ actor = common.get_as2(target).json()
+ inbox_url = actor.get('inbox')
+ logging.info('Inbox url ' + inbox_url)
+
+ acct = 'acct:%s@%s' % (source_domain, source_domain)
+ key = MagicKey.get_or_create(source_domain)
+ signature = HTTPSignatureAuth(secret=key.private_pem(), key_id=acct,
+ algorithm='rsa-sha256')
+
+ # deliver source object to target actor's inbox.
+ headers = {
+ 'Content-Type': common.CONTENT_TYPE_AS2,
+ # required for HTTP Signature
+ # https://tools.ietf.org/html/draft-cavage-http-signatures-07#section-2.1.3
+ 'Date': datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'),
+ 'signature': signature,
+ }
+ resp = common.requests_post(inbox_url, json=activity_accept, headers=headers)
+ self.response.write(resp.text)
+
ooh exciting, this is a great start! i'll merge and update this.
the next step is to translate it to an mf2 "follow" post and send a webmention. based on https://indieweb.org/follow , i think it'd be an h-entry
with two key parts:
p-author
with the mastodon user's detailsu-follow-of
pointing to the indieweb user's home pagewe'd store this in a Response
object (see models.py
), call its proxy_url()
method to get the webmention source url, use the indieweb user's home page as the target url, and send that webmention.
ok! done. following should work now. we respond with an Accept
, and we also store the follower in the datastore, so we can maybe eventually deliver new posts to them, as in #33.
next i'll work on translating AP Follow
s to u-follow-of
indieweb posts.
note to myself: in AS1 this is the follow
verb with the followee as the object.
Since followers are stored, we should probably also check an 'Unfollow' is send to the inbox too, so that the follower can be removed.
Also, followee, I love that word :)
yup! looks like it's actually an Undo
. here's an example from mastodon:
{
"@context": "...",
"id": "https://mastodon.technology/users/snarfed#follows/145220/undo",
"type": "Undo",
"actor": "https://mastodon.technology/users/snarfed",
"object": {
"id": "https://mastodon.technology/3e362975-8468-4f71-9d13-c4cd86b1547f",
"type": "Follow",
"actor": "https://mastodon.technology/users/snarfed",
"object": "https://fed.brid.gy/snarfed.org"
},
"..."
}
ok! we now translate AP Follow
s to indie u-follow-of
webmentions. https://indieweb.org/follow
example rendered follow on my site: https://snarfed.org/about#comment-2615238
source mf2 html:
<article class="h-entry">
<span class="p-uid">https://mastodon.technology/1ce118f7-a038-422a-b322-f190e184fc3e</span>
<span class="p-author h-card">
<data class="p-uid" value="https://mastodon.technology/users/snarfed"></data>
<a class="p-name u-url" href="https://mastodon.technology/@snarfed">Ryan Barrett</a>
<img class="u-photo" src="https://static.mastodon.technology/accounts/avatars/000/023/507/original/01401e3558e03feb.png" alt="" />
</span>
<a class="u-follow-of" href="https://snarfed.org/"></a>
</article>
which parses to:
{
"type": ["h-entry"],
"properties": {
"uid": ["https://mastodon.technology/1ce118f7-a038-422a-b322-f190e184fc3e"],
"follow-of": ["https://snarfed.org/"],
"author": [
{
"type": ["h-card"],
"properties": {
"uid": ["https://mastodon.technology/users/snarfed"],
"name": ["Ryan Barrett"],
"url": ["https://mastodon.technology/@snarfed"],
"photo": ["https://static.mastodon.technology/accounts/avatars/000/023/507/original/01401e3558e03feb.png"]
},
"value": "Ryan Barrett"
}
]
}
}
next TODOs:
u-follow-of
webmentions to AP Follow
s.Undo
s ie unfollows. this is new ground for indieweb; we're still deciding how exactly to translate those. maybe a 410 delete of the original follow post? https://indieweb.org/unfollowok, u-follow-of
webmention => AP Follow
now works too, as of 2bb418dc72589c2bcdf0488fe45df5c1b8526011. woo! closing this issue.
we're discussing in IRC right now how following an indieweb site in mastodon isn't yet supported or doesn't work well, and we don't have a good story for the reverse, ie indicating to mastodon that you're following a mastodon account.
i think the feature request is for bridgy fed to translate and deliver indieweb follow posts (ie
u-x-follow-of
) to ActivityPubFollow
activities, and vice versa. (TODO: what's the OStatus equivalent?)two difficulties:
Follow
handling is currently buggy and makes Mastodon-specific assumptions, so it doesn't currently work with other ActivityPub implementations: https://github.com/tootsuite/mastodon/issues/4933cc @sknebel @keithjgrant @aaronpk @miklb