Okay I'm burnt out on small talk after the first coffeebreak. If anyone wants to just stand together without conversing so as not to look lonely/lost I'm game.
social (16 out of 23)
- Doesn't have proper authentication, just a field to enter in a key that the server uses to verify me.
- Doesn't do endpoint discovery, so I have to type that in as well.
- Only understands how to display ActivityStreams2 Collections, and only knows how to edit items within the Collections.
- Specifically only knows how to add
name
,published
andtags
to items in a Collection. - authenticates the user (I usually use IndieAuth, delegating the hardparts to https://indieauth.com),
- discovers the update endpoint from their profile (which to conform to AP right now would be via a JSON property
outbox
), - presents a UI that lets the user choose a collection to edit (could be discoverable from profile via
streams
property, but to start with I'll probably just offer a URL input), - posts the new values to the update endpoint.
Published a big update to Social Web Protocols. Read if you want to understand what the W3C Social Web WG is up to.
I got like 10 new followers during my Greyhound ordeal this morning. Maybe more likely that's actually due to the recent Solid media flurry than me complaining about buses, though.
Amy added https://www.theguardian.com/society/2016/jul/24/jack-monroe-i-want-to-be-treated-as-a-person-not-a-woman-or-a-man-interview-transgender-identity to https://rhiaro.co.uk/bookmarks/
SO much good stuff in one story, woah.
6th Social WG F2F Summary
This post is my own opinion, and does not necessarily represent the opinion of the Social Web WG!
See also day 1 minutes and day 2 minutes.
We met in Portland on 6th and 7th June. What follows is more detail on my perspective of the main conversations we had over the two days. Clarifications and corrections welcome. This doesn't cover everything we talked about in detail; as well as the following, we resolved (or at least discussed) issues on all of the specs, and took a few to new Working Draft status.
Demos
I demoed my ActivityPub implementations; clients Burrow for checkins, Obtainium for consumption/purchase logging, Replicator for food logging and Seeulator for journeys and events. These all do create only by sending either appropriate activities (including some extensions) to my activitypub endpoint (aka outbox, but not discoverable as such yet).
Seeulator creates the right kind of activity based on what attributes are filled in or left blank, essentially doing post-type discovery - albeit my own algorithm rather than tantek's spec from the user input to generate the right as:Activity
.
The newer thing I worked on was a client that only does updates of existing AS2 data. I wanted this so I could add captions to all my photos at img.amy.gy, so Morph does just that. This also means it has to be able to read/consume the AS2 data published at img.amy.gy about as:Collection
s of photos.
Aaron demoed the Webmention test suite at webmention.rocks and notes that there are Webmention Rocks stickers available for people submitting implementation reports..
Aaron also demoed a new feature in the Micropub spec which is the media endpoint. After some discussion recently it was established that all mainstream social APIs seem to post media (like images) that have been embedded in a post to a separate endpoint, then embed the returned URL in the post content, and MediaGoblin does this too. Aaron's implementation in Quill is really swish looking, uploading the file to the discovered media endpoint whilst you're typing the rest of the blog post, then embedding it back in the UI so you can see it straight away. I should probably implement something along these lines, and sync it up with what ActivityPub is doing (which is going to be basically the same); it's especially useful as I host my images on a completely different domain and stack from my blog posts and right now I have a by-hand process of uploading images to one server, then copying the URL into a blog post to embed.
Evan showed the Wordpress plugin implementation of AS2 by pfefferle, demonstrated on his fuzzy.ai blog. We all noticed a few bugs and AS1-isms in the implementation, but all correctable and all good flags for when we give advice for people switching existing implementations from AS1 to AS2.
Modularising ActivityPub
For a while I've been pushing to break ActivityPub up into several separate specs for each part, modularised by functionality, reasoning that this will lower the barrier to both CR and conforming implementations. I feel strongly that distinct functionalities should not be dependent upon one another to conform to the spec; ie. if I only want to implement subscribing/reading in my application, I shouldn't be required to implement creating new content as well. I've been back and forth on this with Chris and Jessica for at least a year and we're all getting closer to understanding one another. The WG resolved at this meeting to split into ActivityPub (reading, creating, updating, deleting content) and ActivitySub (name pending; subscription and delivery of content). It took me a little longer than it should have to really grok how closely tied 'delivery' and 'notifications' are, but now I realise that regardless of what triggers 'delivery' of an activity, the process of 'delivery' to someone's inbox is the same. The triggering part can be a subscription (a special side effect of receiving a Follow
activity) or a notification (an activity or object is created which is addressed to or links to a user or other activity/object). Thus I anticipate ActivitySub describing how the triggers work, then how delivery works upon a trigger. I'd still like to be able to conform to the 'delivery' part without worrying about the 'trigger' part (maybe I want to implement an entirely different subscription trigger mechanism) but this can be achieved with conformance classes if splitting the spec up further is too much.
New work
The working group wraps up at the end of 2016. There's still time for us to work on new specs, but the ideal is that anything new being presented to the group will have been incubated (worked on, tested, implemented) outside of the group beforehand, either in a CG or other community or organisation. Coming soon to an editor's draft near you: PubSubHubbub!
Next meeting
We confirmed we'll meet on Thursday and Friday at TPAC in Lisbon in September. We'll also run a social web breakout session on the plenary day (Wednesday) like we did last year.
Updated working draft of Social Web Protocols published ahead of the Social Web WG face-to-face next week: https://www.w3.org/TR/social-web-protocols/ This describes and explains the various specs the WG is working on. Far from done, but we're making progress..
Minimal ActivityPub update client
Today I finished morph, a client for posting ActivityStreams2 Update activities to an endpoint. The server handles this update activity however it wants, but the obvious thing to do is take the object
of the activity and make the indicated changes.
So far it:
Will be expanding its object editing abilities soon.
Code on github. See also: Minimal ActivityPub update endpoint.
Minimal ActivityPub update endpoint
ActivityPub updates objects by posting an ActivityStreams2 Update
Activity to the authenticated user's outbox
(discovered from their profile).
I store my photo albums as ActivityStreams2 Collections
, so this morning I made a minimal AP-compliant update endpoint today that lets me add captions to them. This is just the server componant. It lets me do:
curl -vX POST -H "Content-Type: application/activity+json" -H "Authorization: secret-token" -d @as-update.json https://path/to/endpoint
where as-update.json
contains:
{
"@context": "http://www.w3.org/activitystreams#",
"type": "Update",
"name": "Amy captioned a photo.",
"actor": "https://rhiaro.co.uk/about#me",
"object": {
"id": "https://uri/of/photo.jpg",
"name": "A brand new caption."
}
}
So far this replaces the entire object with the object embedded in the Activity. Hopefully we'll have a syntax to indicate partial updates in AP soon.
The code (PHP) at https://path/to/endpoint
contains a few functions that are at the discretion of the server (how to verify the authenticated user can write, what to do with the activity once it gets it, and exactly how to perform the update):
function verify_token($token){
// Magic to verify token passed in Authorization header here.
// I check it against a protected file on the server that contains a randomly generated long string.
return $response;
}
function store_activity($activity){
// Arbitrary server logic to store the activity that was posted.
// I just dump the JSON in a file.
return true;
}
function make_update($activity){
// Arbitrary server logic to perform the update on the object.
// I parse the value of object in the activity to work out where its data is stored in the filesystem, then rewrite the appropriate JSON file.
return true;
}
And here's the overall flow:
// Authentication
$headers = apache_request_headers();
if(isset($headers['Authorization'])) {
$token = $headers['Authorization'];
$response = verify_token($token);
$me = @$response['me'];
$iss = @$response['issued_by'];
$client = @$response['client_id'];
$scope = @$response['scope'];
}else{
header("HTTP/1.1 403 Forbidden");
echo "403: No authorization header set.";
exit;
}
if(empty($response)){
// Something went wrong with verification
header("HTTP/1.1 401 Unauthorized");
echo "401: Access token could not be verified.";
exit;
}elseif(stripos($me, "rhiaro.co.uk") === false || $scope != "update"){
// The wrong person and scope was returned when the token was verified.
header("HTTP/1.1 403 Forbidden");
echo "403: Access token was not valid.";
exit;
}else{
// Verified, good to go..
if(empty($_POST)){
$post = file_get_contents('php://input');
}
if(isset($post) && !empty($post)){
// Store activity
$id = date("Y-m-d_h:i:s")."_".uniqid();
if(store_activity($post)){
// Perform the update
if(make_update($post)){
header("HTTP/1.1 201 Created");
echo "Resource updated";
}else{
header("HTTP/1.1 500 Internal Server Error");
echo "500: Could not make update (probably a permissions issue). ";
}
}else{
header("HTTP/1.1 500 Internal Server Error");
echo "500: Could not store activity log (probably a permissions issue).";
}
}else{
header("HTTP/1.1 400 Bad Request");
echo "400: Nothing posted";
}
}
?>
Obviously I've stripped out my implementation-specific stuff to make it easier to read. The actual code on my server is here: github/rhiaro/img/pub.php.
The next thing I need to do is make a client that...
I love the work by Oliver Haimson about transitioning between idenitties online, and how digital footprints and arbitrary technical decisions make this difficult. ~"What would it look like for a social network site be oriented towards people drifting between identities over time as happens in the real world? Designing for forgetting and decay."
In reply to:
Solid lets developers choose their preferred model to build, and users choose the applications that implement the model they trust most.
Great issue raised in Solid tutorial: "There's some data that's about me and I own it and it's personal, but it's not something I should have the right to change or erase."
Dmitri: We owe some thanks to facebook et al for laying the groundwork of UX for data access and sharing
How do I trust what apps are doing with my data? Dmitri: hard question, needs tackling on many fronts, technical & social
Linked data applications for the decentralised social web: tutorial | chat solid.mit.edu
In reply to:
Mind blown by individuals as social machines talk in #socm2016... individualism as in Buddhism... something to do with state machines and temporality and 'megamoments' and then facebook status updates. For interoperability of social profiles between social machines. I barely followed and am really confused, yet positive there was something amazing in there.