Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publishing which extensions are used by a server #22

Open
cwebber opened this issue Sep 21, 2017 · 8 comments
Open

Publishing which extensions are used by a server #22

cwebber opened this issue Sep 21, 2017 · 8 comments

Comments

@cwebber
Copy link
Collaborator

cwebber commented Sep 21, 2017

Per #19 people are beginning to add ActivityStreams extensions with new vocabulary. But how do you know what extensions a server supports? Json-ld already provides much of what we need; we have a way of extending the vocabulary and if a server receives an object they don't know about, they can ignore it or do a best-effort rendering of it as just an Object. And the endpoints property on actors tell you what other server-wide API bits their server may provide. Actors can also have specific endpoints attached to themselves, as an actor.

Still, maybe you want to deliver an activity to someone's inbox or something and expect some side effect to be performed. It would be useful to know whether the server claims they would actually supprort it.

We could use something like Hydra but to be honest I think this would be too complicated for most implementors. Here's the minimal version of what I think is needed to describe what extensions are used by a server:

  • You need a way to look up a list of which extensions are implemented
  • You need each of those extensions to have a unique ID
  • You need a human readable description of each extension

Here's my suggestion on how to do it. Attach an extensions endpoint to the Actor's endpoints property (which reflects server-wide endpoints anyway). So like so:

  {"@context": "https://www.w3.org/ns/activitystreams",
   "type": "Person",
   "id": "https://social.example/alyssa/",
   "name": "Alyssa P. Hacker",
   "preferredUsername": "alyssa",
   /* ... */
   "endpoints": {
      "id": "https://social.example/endpoints/",
      "extensions": "https://social.example/extensions.json"}}

Now retrieving the extensions object gets you something like:

["https://apextensions.example/extensions/payment-offers", ...]

This is just a json object with a list of URIs. Each URI is the unique id indicating that the server is visiting that extension. If a developer wants, they can visit that URI to read a human-readable description of that extension. However there is no machine-readable markup of what the extension means; this is just the way for the developer to code into their program whether or not to expect there to be support for the functionality.

So in this example, Ben is writing and using a server that, when it is run, federates with his friends Alyssa P. Hacker and Eva Lu Ator's servers. Ben forgot to bring cash with him for lunch, so Alyssa and Eva split covering his lunch and he said he'd pay them back later. In Ben's client, he selects Alyssa as a "payment offer" recipient, containing some payload which presents a way for Alyssa to retrieve the payment, and which she must explicitly accept or reject. Ben's client sees that Alyssa's server has payment-offers listed as an accepted extension, so she should be able to accept/reject the offer, and the client allows Ben to proceed. When Ben tries to pay Eva, his client notices that she doesn't have the extension listed, and the client notifies Ben that she likely won't be able to accept the payment offer from her end. Oh well... Ben will just get her back in person at another time!

@cwebber
Copy link
Collaborator Author

cwebber commented Sep 21, 2017

This issue also came up between some users on Mastodon and surinna came up with a similar solution.

@cwebber
Copy link
Collaborator Author

cwebber commented Sep 21, 2017

Note that my suggestion doesn't help with notifying what extensions a client supports. There's probably not really a good way to do that, especially because an actor may be using multiple clients.

@ekiru
Copy link

ekiru commented Sep 23, 2017

This is very similar (well, other than being more ActivityPub-native) to what I and a couple of others (@marrus-sh and @beatrix-bitrot) had been talking about/considering (summarized in the gist I linked to on mastodon in the post @cwebber linked to above (I'm the surinna mentioned)). The one major difference is that we wanted a place to allow extensions to stick additional information about an instance's support for each extension, which this proposal does not provide. Our thought was to provide both an array like @cwebber proposed above and a map alongside it with keys being extension URLs and the values and their interpretation at the liberty of the individual extensions (we were going to stick this in a general instance metadata endpoint initially, so we were going to have a "supports-extensions" property there that contained the array and then properties whose keys are an extension URL in the instance metadata would be information about a particular extension. With this proposal, perhaps instead of the extensions endpoint pointing to just a JSON array, we could have it point to a JSON object that contained that array as a property as well as another property for additional information/metadata about individual extensions (or the like with my/marrus/beatrix's idea, we might just stick those additional info/metadata properties as properties on the top-level JSON object)?

As a perhaps-motivating example, the @glitch-soc fork of Mastodon has a "profile metadata" feature that lets users add a few key-value pairs to their profile that will be displayed separately from the rest of their bio/summary. We currently expose this with specially-formatted and -handled text in the bio/summary (largely for compatibility reasons), but if we add API endpoints to manipulate it directly, we'd want to communicate that we supported that as an extension so that clients that understand it will know to use those endpoints. We currently limit them to 5 key-value pairs, but other servers/implementations supporting the feature might want to allow more or might not want to allow that many. Clients which support an editing UI for the profile metadata might want to know how many entries are allowed by a server so we'd want to expose this information, so we'd want to expose something like { "max-entries": 5 } for that extension.

ekiru added a commit to glitch-soc/mastodon that referenced this issue Sep 23, 2017
This is in line with cwebber's proposal at
swicg/general#22
@cwebber
Copy link
Collaborator Author

cwebber commented Sep 27, 2017

For clarity, @ekiru added their example at the bottom of this gist

@ekiru I see your motivating example and it makes sense. Here's maybe another way to do it would be to break it up into two endpoints: one for extensions (still just an array of uris) and one for configuration (which when resolved is an object with information about server-wide configuration information that presumably applies to extensions, or whatever)?

@jaywink
Copy link

jaywink commented Sep 27, 2017

It would be great if the extensions were a part of some a bit more generic metadata document, which could be used to provide various types of information about the instance, related to name, server software, version, usage, owner, protocols supported, services, etc. And activitypub extensions under their own key. Basically just a normal JSON object with various keys.

The Diaspora powered network has one like this, which has proven immensely useful for the network. It allows us to see how much active users there are, what kind of different software stacks are involved and what services like cross-posting or chat they provide. The schema is locked down pretty tight, even to the enums, which IMHO makes the diaspora NodeInfo not really useful for generic usage (even though originally that was the idea).

I hacked my own version, more in a "how it could be" than really expecting anyone to use it. It's imaginatively called NodeInfo2. It is more flexible and it also has some notes on how it could work with ActivityPub which doesn't do .well-known's.

Anyway, the point is. If we're going to have to expose metadata about extensions, let's do it in a generic metadata document that can be used to expose usage statistics, server information and other stuff that would help not just the activitypub network, but also any other servers that want to adopt it - even if they're not federating projects.

@ghost
Copy link

ghost commented Sep 27, 2017

This site metadata is included in zot inside a 'site' section of the channel discovery record. In zot6 this is available via a protocol request (application/x-zot+json) to the site root . It's important in our case because the site has a public key which is used to both sign and encrypt information which has no specific recipient or recipients. It also presents the endpoints for openWebAuth to allow viewing of protected content and provides discovery of mirrored directory servers.

{
    "url": "https://x.macgirvin.com",
    "url_sig": "i2UnaZKKUOYZumBNTTZ...",
    "post": "https://x.macgirvin.com/post",
    "openWebAuth": "https://x.macgirvin.com/owa",
    "authRedirect": "https://x.macgirvin.com/magic",
    "key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQE...",
    "directory_mode": "standalone",
    "directory_url": "https://x.macgirvin.com/dirsearch",
    "encryption": [
        "aes256ctr",
        "camellia256cfb",
        "cast5cfb"
    ],
    "signing": [
        "sha256"
    ],
    "zot": "6.0"
}

Nodeinfo is usually implemented along with the Diaspora protocol since it is required to use the Diaspora relays, but most sites are configured to provide bogus or null information in order to lower their attack surfaces. The Nodeinfo data is mostly for statistical collection and has little or no functional value. The site info is necessary/critical for interop. Such a mechanism that is available via AP requests to the site root or other discovery mechanism could be useful for a number of purposes.

@nightpool
Copy link

nightpool commented Nov 22, 2017

We talked about this for a while at the SocialCG meeting today, and the consensus was that any type of "extensions" endpoint to ActivityPub is, functionality-wise, exactly equivalent to adding a new JSON-LD namespaced property to the actor representation advertising support for that extension. So for example, the initial motivating example could be:

 {
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Person",
  "id": "https://social.example/alyssa/",
  "name": "Alyssa P. Hacker",
  "preferredUsername": "alyssa",

  "https://apextensions.example/extensions/payment-offers": true
}

and one with data could be:

 {
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Person",
  "id": "https://social.example/alyssa/",
  "name": "Alyssa P. Hacker",
  "preferredUsername": "alyssa",

  "https://glitch.social/ns#maxEntries": 5
}

And of course, these could be collapsed into context entries for ease of use.

@sandhawke
Copy link

And if it's going to be widely used, it can be in the AS namespace, so it reads better, like

{
   ...
   paymentOffers: true
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants