This commit is contained in:
a 2023-03-24 16:37:31 -05:00
parent 89bbcdacc0
commit 91ad4705ce
29 changed files with 1283 additions and 8 deletions

55
content/links/_dump.md Normal file
View file

@ -0,0 +1,55 @@
### web
minimum common web platform <https://common-min-api.proposal.wintercg.org/#index>
webfinger redirect in nginx config <https://blog.yaakov.online/something-i-learned-recently-webfinger/>
```nginx
location /.well-known/webfinger {
if ( $arg_resource = "acct:hello@yaakov.online" ) {
return 302 'https://cloudisland.nz/.well-known/webfinger/?resource=acct:yaakov@cloudisland.nz';
}
return 404;
}
```
mast logo <https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/d6/be/9c/d6be9cdc-8fa5-39b1-32b2-e1050a7093f6/AppIcon-0-2x-4-85-220.png/492x0w.png>
openxri project <https://openxri.sourceforge.net/>
+18665923734 -- birmingham al office of the us social security administration (also handles disability)
<https://codeberg.org/weex/the-fediverse/issues/7>
indiekit, a nodejs server that helps static websites do indieweb stuff (is it like a cms?) <https://getindiekit.com/introduction>
### demetrification
What Do Metrics Want? <http://computationalculture.net/what-do-metrics-want/>
The quest to create a world without likes, retweets, and follower counts <https://www.telegraph.co.uk/technology/2019/08/05/quest-create-world-without-likes-retweets-follower-counts/>
Will hiding likes on Instagram and Facebook improve mental health? <https://www.washingtonpost.com/lifestyle/wellness/likes-facebook-instagram-mental-health/2021/05/27/132073d0-be55-11eb-9c90-731aff7d9a0d_story.html>
### concert recording
<https://www.oade.com/index.php?main_page=product_info&cPath=19&products_id=256>
<http://www.audioreality.com/concert_recording_microphone_faq.htm>
### varia
V7MLIZ392DXQ4UC5GEMF <https://v7mliz392dxq4uc5gemf.neocities.org/>
### merch
<https://circasurvivestore.com>
<https://creature-club.com>
### music
<https://grantkirkhope.bandcamp.com/track/gruntilda-returns>
<https://virginbabylonrecords.bandcamp.com/album/enchanted-landscape-escape-remaster-2>

View file

@ -0,0 +1,127 @@
+++
title = "Dereferencing non-HTTPS URIs as `id`"
date = "2019-10-11"
+++
{{toc}}
## Preserved text
<https://socialhub.activitypub.rocks/t/dereferencing-non-https-uris-as-id/116>
---
@trwnh:
> 3.1 Object Identifiers
>
> All Objects in [ActivityStreams] should have unique global identifiers. ActivityPub extends this requirement; all objects distributed by the ActivityPub protocol MUST have unique global identifiers, unless they are intentionally transient […] These identifiers must fall into one of the following groups:
>
> 1. Publicly dereferencable URIs, such as HTTPS URIs, with their authority belonging to that of their originating server. (Publicly facing content SHOULD use HTTPS URIs).
> 2. An ID explicitly specified as the JSON null object, which implies an anonymous object (a part of its parent context)
>
> Identifiers MUST be provided for activities posted in server to server communication, unless the activity is intentionally transient. However, for client to server communication, a server receiving an object posted to the outbox with no specified id SHOULD allocate an object ID in the actors namespace and attach it to the posted object.
>
> All objects have the following properties:
>
> id
>
> The objects unique global identifier (unless the object is transient, in which case the id MAY be omitted).
>
> type
>
> The type of the object.
One thing I've wondered about is point 1 under 3.1 -- the id MUST be publicly dereferencable, with its authority belonging to the origin server... but it only SHOULD be https.
So, does this mean that there are other possible choices for a publicly dereferencable id with proper authority, that *isn't* HTTPS? I assume that the intention was to suggest using HTTPS over HTTP (e.g. section 3.2 assumes HTTP GET and content negotiation, as well as headers and 403/404 error codes; section 5.1/5.2 specifies HTTP POST to outbox/inbox; Section 6 uses MUST for making an HTTP POST to actor outboxes and 201 codes), but my curiosity is with other URI schemes entirely.
Perhaps one practical consideration (as there are various impractical ones, such as file://, ftp://, ftps://, sftp://, and so on) is to not use a URL but instead use a URN (such as doi, isbn, and other urn: URIs). Of course, this requires us to do a little more work to treat them as "dereferencable", such as by including a HTTPS proxy or some other resolver service. I wonder how that might be done, and whether this is at all worth pursuing. It could be used for deduplication, for example, by assigning a network-wide URN, with the authority deferred to the lookup service/proxy used as an instrument.
---
@cwebber:
> So, does this mean that there are other possible choices for a publicly dereferencable id with proper authority, that isnt HTTPS?
Yes and the [Golem demo](https://gitlab.com/spritely/golem/blob/master/README.org) shows exactly an example of this, using a (very-cut-down demo) of using [Datashards](https://datashards.net/) with ActivityPub (it was called “magenc” back then) to distribute activities. A similar example could be done with IPFS, for instance (though that doesnt provide the privacy/security properties that Datashards does).
Similarly, [bearcaps](https://github.com/cwebber/rwot9-prague/blob/bearcaps/topics-and-advance-readings/bearcaps.md) are a possible non-https URI scheme that we might use.
[...] Wanting to support Tor Onion Services is a reason I explicitly pushed back against pressure to make the spec https-only, which some people wanted.
---
@trwnh:
I guess what Im trying to comprehend the most would be, how would compatibility work between the HTTPS linked-data web, and the non-HTTPS documents? If we start passing around AP JSON-LD documents with non-HTTPS `id` then it would obviously break due to basically all implementations assuming that all they need to do is HTTP GET `id`.
I remember reading the [RWoT paper about DIDs in ActivityPub](https://github.com/WebOfTrustInfo/rwot5-boston/blob/master/final-documents/activitypub-decentralized-distributed.pdf) and having the same confusion at the time about how it would work practically. The closest thing I could find was [`instrument`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-instrument) in the AS2 Vocab, but that has a domain of `Activity` only, and is described as "Identifies one or more objects used (or to be used) in the completion of an `Activity`", so it would have to be redefined to work on `Object` as well.
---
@rinpatch:
Wouldn't an array of `id` work?
---
@trwnh:
Actually, multiple `id` seems interesting to me for a different thing: nomadic identity. Consider a case where an Object has multiple HTTPS URIs.
That might not be the best way to do it, though. In fact, one shortcoming that is immediately apparent to me is the question of what to do if the document retrieved from one `id` is different from that retrieved from another `id`. So it would be better to have one canonical `id` only, where possible. But technically, the problem of differing documents can still happen, due to something as simple as a desync.
[[future errata: this is what `alsoKnownAs` could be used for?]]
Id really like to focus on modeling how to dereference non-HTTPS in a way that is still roughly compatible with the HTTPS Web-based network. So far the following options have been mentioned:
* `id` as Array; pick whichever one you understand.
* `url` as Array; pick whichever one you understand but leave `id` as HTTPS.
* just break compat and let implementations figure out how to resolve `id` (if they can)
* use a local proxy directly as `id` (technically still globally unique but represents change of authority)
* use a proxy Service as `instrument` (and extend `instrument` to be applied to `Object` and not just `Activity`)
---
@how:
Im a bit concerned about extending to objects what could be done with creating an object-specifc actor acting as a proxy. The `instrument` service seems to be adapted to this use-case: you get a representation of the objects metadata but must use the out of band service to retrieve the actual object. Best of both worlds?
---
@nightpool:
The ActivityPub standard does not define that any given server must support any one scheme. I dont understand what the purpose of having it do so would be? it would just limit the flexibility of the protocol for no practical benefit (If two servers dont support the same schemes, then theyre obviously not going to be able to talk to each other, MUST or no MUST)
---
@trwnh:
I think theres probably mixing of concerns to treat non-HTTPS as primarily an issue of nomadic content; while there is *potential* application toward this, I think the incompatibility issue is probably more pressing in the long run. You can claim that a software is “compatible with ActivityPub”, but this is a statement that needs clarification and qualification. And this is also something that would become even more of an issue if ActivityPub is implemented via networks other than HTTP(S).
In that sense, there is no “ActivityPub network” there is only currently an “ActivityPub over HTTPS network” (using HTTPS ids), as well as a sub-network of “ActivityPub over HTTPS network, with WebFinger” (perhaps more colloquially referred to as “the Mastodon network”).
Even if every (or the majority of) software implementation(s) moves to adopt `bear:` URIs as `id`, there is now still the question of which URI schemes are supported with the `u` parameter of the bearcap. The draft for bearcaps defines `u` as “The stable URL that the bearer capability URI is associated with for requests”, which is, again, not specifically HTTP(S). But even then, specifying a “stable URL” means that we are precluding URNs as a form of reference.
As nightpool mentions:
> If two servers dont support the same schemes, then theyre obviously not going to be able to talk to each other
So I guess my main concern is that so-called “ActivityPub” software will settle around the lowest common denominator or the most restrictive set of requirements for interoperability. Id like to lessen that if possible, so that individual implementations have the option to explore alternative lookup strategies for other “publicly dereferencable” schemes without that implying a choice between “hard break in network compatibility” or “stuck using HTTPS for `id` because everyone else is”. Although a hard break might be desirable in some cases, e.g. “if you dont understand bearcaps then you cant interact with this object”.
---
## current thoughts
we've well and truly collapsed into the "https only" world by now. any attempt to use a different scheme represents a sort of netsplit. this is not all good or bad though; it just means that the only network we have is the World Wide Web.
`alsoKnownAs` may be useful here as well: <https://socialhub.activitypub.rocks/t/defining-alsoknownas/907/30>
> i see a few possible approaches:
>
> 1. defer `alsoKnownAs` to mastodon's usage (concept 2, controlling the listed actor). define a new term `aliases` (pending name) to represent concept 1, different identifiers for the same subject. we might also define `subject` or some similar term to identify a "canonical" identifier?
>
> 1. defer `alsoKnownAs` to the DID core definition (concept 1, different identifiers for the same subject). implement a transitional period in which mastodon and other projects switch to a different mechanism more along the lines of rel-me. eventually deprecate the use of `alsoKnownAs` for determining rel-me.
aside from that, the `instrument` idea still has some potential

View file

@ -0,0 +1,24 @@
+++
title = "Notifying remote servers that they should refetch an object"
date = "2019-11-01"
+++
{{toc}}
## Preserved text
<https://socialhub.activitypub.rocks/t/exposing-edit-history-via-activitystreams/2930>
@trwnh:
Per [expose edit history in ActivityPub representation · Issue #23292 · mastodon/mastodon · GitHub ](https://github.com/mastodon/mastodon/issues/23292)
@Johann150 raises a feature request for being able to view earlier versions of an activity or object before an Update was received. In the case where an object is Created and then Updated, someone receiving the Update who didnt receive the Create first would have no way of knowing what was contained in the original version. Someone fetching the object without having received either of the activities would be able to know that it was edited based on the presence of the `updated` property, but likewise would not be able to retrieve any additional information about previous versions.
Looking at the existing Activity Vocabulary we see that the only existing way to do this would be in the case that `context` was published, although this requires that the context MUST be a Collection, and you would have to dig through all the items to filter for Update activities (plus the initial Create). Additional issues arise from the ordering of Collections not always being consistent, but in general you will still have to traverse the entire context collection.
Therefore it likely makes sense to propose a new property called something like `history` or `revisions`. If there is any prior art or some existing specifications that could apply here, it would be helpful to know about them.
## current thoughts
idk

View file

@ -0,0 +1,436 @@
+++
title = "Unresolved issues surrounding Follow activities"
date = "2019-10-10"
+++
{{<toc>}}
## Preserved text
<https://socialhub.activitypub.rocks/t/unresolved-issues-surrounding-follow-activities/114>
<article>
# First, some context…
What the C2S spec says:
> 6.5 Follow Activity
>
>
>
> The Follow activity is used to subscribe to the activities of another actor.
>
>
>
> The side effect of receiving this in an outbox is that the server SHOULD add the object to the actors following Collection when and only if an Accept activity is subsequently received with this Follow activity as its object.
What the S2S spec says:
> 7.5 Follow Activity
>
>
>
> The side effect of receiving this in an **inbox** is that the server *SHOULD* generate either an `Accept` or `Reject` activity with the Follow as the `object` and deliver it to the `actor` of the Follow. The `Accept` or `Reject` *MAY* be generated automatically, or *MAY* be the result of user input (possibly after some delay in which the user reviews). Servers *MAY* choose to not explicitly send a `Reject` in response to a `Follow` , though implementors ought to be aware that the server sending the request could be left in an intermediate state. For example, a server might not send a `Reject` to protect a users privacy.
>
>
>
> In the case of receiving an `Accept` referencing this `Follow` as the object, the server *SHOULD* add the `actor` to the object actors [Followers Collection ](https://www.w3.org/TR/activitypub/#followers). In the case of a `Reject` , the server *MUST NOT* add the actor to the object actors [Followers Collection ](https://www.w3.org/TR/activitypub/#followers).
> > Note
> >
> >
> >
> > Sometimes a successful `Follow` subscription may occur but at some future point delivery to the follower fails for an extended period of time. Implementations should be aware that there is no guarantee that actors on the network will remain reachable and should implement accordingly. For instance, if attempting to deliver to an actor for perhaps six months while the follower remains unreachable, it is reasonable that the delivering server remove the subscriber from the `followers` list. Timeframes and behavior for dealing with unreachable actors are left to the discretion of the delivering server.
Special collections:
> 5.3 Followers Collection
>
>
>
> Every [actor ](https://www.w3.org/TR/activitypub/#actors) *SHOULD* have a `followers` collection. This is a list of everyone who has sent a [Follow](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow) activity for the actor, added as a [side effect](https://www.w3.org/TR/activitypub/#follow-activity-outbox). This is where one would find a list of all the actors that are following the actor. The `followers` collection *MUST* be either an [ `OrderedCollection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) or a [ `Collection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection) and *MAY* be filtered on privileges of an authenticated user or as appropriate when no authentication is given.
> > Note: Default for notification targeting
> >
> >
> >
> > The follow activity generally is a request to see the objects an actor creates. This makes the Followers collection an appropriate default target for [delivery](https://www.w3.org/TR/activitypub/#delivery) of notifications.
>
>
> 5.4 Following Collection
>
>
>
> Every actor *SHOULD* have a `following` collection. This is a list of everybody that the actor has followed, added as a [side effect](https://www.w3.org/TR/activitypub/#follow-activity-outbox). The `following` collection *MUST* be either an [ `OrderedCollection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) or a [ `Collection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection) and *MAY* be filtered on privileges of an authenticated user or as appropriate when no authentication is given.
In summary… C2S Follow puts a Follow activity in your outbox, your server waits for an Accept, then adds that actor to following. S2S Follow takes a Follow activity in your inbox, your server wraps it in Accept/Reject and delivers that. S2S Accept Follow adds that actor to followers. (All of this is SHOULD language.)
However, this leaves some things too ambiguous…
# Following only a *subset* of activities
By default, when you Follow an Actor, most implementations interpret that as a sign of interest in every single activity that the actor publishes, similar to the note in 5.3 (“The follow activity generally is a request to see the objects an actor creates.”). But there is no way to signal an interest in receiving only *some* of the activities. Perhaps the only possible concession here is the `streams` property of an actor, but there is basically nothing to guide implementations aside from a passing mention that is only 10 words long:
> **streams**
> A list of supplementary Collections which may be of interest.
This suggests a pull-based approach, where you can GET the `streams` of an actor… but you cannot have the actor deliver any activities from those streams. Nor is it explicitly defined whether these collections contain activities or objects, or what the collections are actually for (aside from heuristically guessing based on the name of the collection?) Perhaps there could be a way to consistently understand these collections and maybe follow just those streams instead of the actors, but that would require…
# Following non-actor objects
Per 6.5, “The Follow activity is used to subscribe to the activities of another actor.” But sometimes you dont necessarily care what a single actor does with multiple objects, you care about what multiple actors are doing with a single object.
AFAIK some implementations interpret Follow Object to generally mean that the software will deliver any activities targeting that object to any actor that has expressed interest through the Follow Object activity. Perhaps this should be formalized, as the following are currently not agreed upon:
* Who should you send the Follow Object to? The `attributedTo` actor? Does following that object imply also following the actor?
* How should you keep track of followed objects? Should they be added to the `following` collection like actors? Should individual objects define a `followers` collection?
* How do you know if an object is followable? If you send a Follow Object to remote software, it may not understand it. Is the presence of a `followers` collection enough for this? Does it also need `attributedTo`? Some other method?
# Practical applications
As prior art, Google+ Collections come to mind. For each post made to Google+, a user could choose to address it to Public, or to selected users (like actors), or to a Circle (like a collection of actors), or to a Community (like a group), or to a Collection (like a category/stream). This could be seen as confusing since it wasnt really well-explained to users what any of these concepts meant, and Google+ also used Circles both for addressing those users *and* for viewing posts from those users, whereas most other services have a separate Lists feature for viewing posts from a subset of users. In essence, users can categorize their posts at the same time as they choose who to address them to. Consider the following hypothetical documents:
```
{
"id": "https://social.example/actors/1",
"type": "Person",
"inbox": "https://social.example/inboxes/1",
"outbox": "https://social.example/outboxes/1",
"followers": "https://social.example/actors/1/followers",
"streams": ["https://social.example/collections/1"]
}
```
```
{
"id": "https://social.example/objects/1",
"type": "Note",
"content": "a simple note",
"attributedTo": "https://social.example/actors/1",
"followers": "https://social.example/objects/1/followers"
}
```
```
{
"id": "https://social.example/collections/1",
"type": "OrderedCollection",
"items": ["https://social.example/objects/1"],
"followers": "https://social.example/collections/1/followers"
}
```
```
{
"id": "https://social.example/activities/1",
"type": ["Create", "Add"],
"actor": "https://social.example/actors/1",
"object": "https://social.example/objects/1",
"target": "https://social.example/collections/1",
"to":
[
"https://social.example/actors/1/followers",
"https://social.example/objects/1/followers",
"https://social.example/collections/1/followers"
]
,
"cc": ["as:Public"]
}
```
# Etc
Any comments, additions, etc. about this?
</article>
---
@trwnh:
I should also add some discarded approaches that I considered at one point while thinking about this but determined to be too problematic:
* interpreting a Follow as subscribing to multiple actors instead of just one
* multiple outboxes (although this might still be applicable to other problems, just not this one for now)
* using Profiles instead of Actors (though this could still be done, it would be unsupported in current implementations; it would however become possible to Follow Profile instead of Follow Actor)
* having objects just be made into actors, a la the concept of message passing in computer science (although this adds a lot of complexity because objects generally only need a small part of what Actor provides)
* hackily having multiple actors representing the same Person, but using them to create objects, then Announcing those from a more “central” actor (too complicated and unwieldy)
---
@trwnh:
Sure, but how should we discover this?
As stated above I went with `attributedTo` and the presence of a `followers` property, but perhaps it may be better to use an explicit endpoint like `inbox`?
---
@trwnh:
Its almost 3 years later and I think Ive come around on this a bit
> As stated above I went with `attributedTo` and the presence of a `followers` property, but perhaps it may be better to use an explicit endpoint like `inbox`?
I think explicit is better than implicit. All thats required for an Object to be an Actor is to have `inbox` and `outbox`. The only issue with current language in the spec is that
> The outbox stream contains activities the user has published,
and semantically speaking actors are not equivalent to users, nor is the attribution required to match the same actor (or even *be* an actor `attributedTo` can include another activity, for example).
Where the previous approach fails is that the `followers` collection may not be included or published. The `followers` property is only a SHOULD and not a MUST.
For delivery of the Follow activity, we can refer to the guidance on delivery:
> The [inbox](https://www.w3.org/TR/activitypub/#inbox) is determined by first [ retrieving the target actors JSON-LD representation](https://www.w3.org/TR/activitypub/#retrieving-objects) and then looking up the `inbox` property. If a recipient is a `Collection` or `OrderedCollection`, then the server *MUST* dereference the collection (with the users credentials) and discover inboxes for each item in the collection. Servers *MUST* limit the number of layers of indirections through collections which will be performed, which *MAY* be one.
Which, again, implies that we should just attach `inbox` on anything followable. And if we do that, then we should/must attach `outbox` as well to make it an actor (although in practice this may not be strictly required it is possible to model having an inbox but no outbox, and some implementations might do this already in apparent violation of the spec).
---
@macgirvin:
I do recall when Mastodon first implemented ActivityPub and some folks were still using OStatus. In this case the inbox was set to NULL. We implemented AP at exactly the same time and this threw exceptions in my code. Was going to file a bug, but technically speaking I think its spec compliant. The language states that an actor must have the “following properties” and these records had the required properties, except they werent de-reference-able. In any case I consider this to be a legal interpretation and have code to handle it appropriately.
A more serious issue is that we implement access permissions to several collections and these are not de-reference-able unless the requestor has permission to access the collection. The spec is incredibly weak where it comes to dealing with permissions, but I have every right to restrict access of a resource to anybody I desire - even if it means my software isnt technically compliant. This makes the quoted section in your reply contentious. These are deliverable through the forward-to-owner sections referenced elsewhere in the spec so everything still works; but not all collections are de-reference-able by every actor that receives an activity — nor should they be.
---
@trwnh:
[quote="macgirvin, post:8, topic:114"]
In this case the inbox was set to NULL.
[/quote]
Hmm. My interpretation is that `inbox` and `outbox` properties MUST be provided, but not necessarily be public. Im not sure whether it makes sense to set `inbox` to `null` explicitly; is that not the same as excluding it? In any case, the practical implication of the current network (“ActivityPub over HTTPS”, or as Ive taken to calling it recently, “ActivityPub over HTTPS with Webfinger and HTTP Signatures” :stuck_out_tongue: ) is that one can simply POST to an inbox IRI and have it either return successfully or error out with a 405 Not Allowed (if federation is not implemented). Id be curious to hear any objections or concerns regarding this.
[quote="macgirvin, post:8, topic:114"]
I have every right to restrict access of a resource to anybody I desire - even if it means my software isnt technically compliant.
[/quote]
Im not sure if its technically “incompliant” to do so, but for what its worth, Pixelfed for example provides `inbox` for actors (currently equivalent to users, but under this proposal, it doesnt have to be), and this `inbox` only supports POST and not GET, for obvious reasons federation works by POSTing to the `inbox` and GET is only needed for C2S fetching your own inbox with authorization. That doesnt seem like a problem to me; if anything, it seems natural since the inbox is only for delivery. Setting `inbox: null` or leaving it out implies that the object is not an actor, since it does not have both `inbox` and `outbox` (the only two required properties for actors). Aside from this heuristic, there doesnt seem to be any other meaning to being an actor. So I would agree that yes, access to resources may be restricted without authorization. This doesnt seem like an issue, although I may be misunderstanding or overlooking something.
[quote="macgirvin, post:8, topic:114"]
This makes the quoted section in your reply contentious. These are deliverable through the forward-to-owner sections referenced elsewhere in the spec so everything still works; but not all collections are de-reference-able by every actor that receives an activity — nor should they be.
[/quote]
Inbox forwarding could perhaps be applicable, but not any more so than it already is.
To clarify, the assumed / proposed flow is something like this:
1. I GET an actor at `https://example.social/actors/1` and see that their `streams` advertises `https://example.social/collections/1`:
```
GET https://example.social/actors/1 HTTP/1.1
Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"
{
"@context": [...],
"id": "https://example.social/actors/1",
"type": "Person",
"inbox": "https://example.social/inboxes/1",
"outbox": "https://example.social/outboxes/1",
"streams": ["https://example.social/collections/1"],
...
}
```
2. I want to `Follow` the `Collection` at `https://example.social/collections/1` for updates. (Lets say this `Collection` is advertised within `streams` and represents some categorization of posts, similar to Wordpress categories or Google+ Collections. Its items contain some arbitrary objects like `Note`s that have been published within the category/stream.)
3. I perform `GET https://example.social/collections/1`, optionally with an HTTP Signature for my actor `https://ap.trwnh.com/actors/1`. The server responds with a `Collection` containing only the items I am authorized to see, based on the HTTP Signature attached. If no signature is attached, then only items with `audience: as:Public` will be returned (likewise for `to`/`cc`/etc if the server software uses those for addressing instead of `audience`).
```
GET https://example.social/collections/1 HTTP/1.1
Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"
Signature: keyId="https://ap.trwnh.com/actors/1/publicKey",...
{
"@context": [...],
"id": "https://example.social/collections/1",
"type": "OrderedCollection",
"totalItems": 1312,
"first": "https://example.social/collections/1?page=1",
"last": "https://example.social/collections/1?page=132",
"inbox": "https://example.social/inboxes/1",
"outbox": "https://example.social/outboxes/2"
}
```
4. From this response, I parse for the `Collection`s `inbox` property. If it does not have one, I assume it cannot be followed. If it does have one, then I assume I can send a `Follow` there. In this example, `https://example.social/collections/1` has `inbox: https://example.social/inboxes/1`. (This happens to be the inbox for `https://example.social/actors/1`, but it doesnt have to be. This is an implementation detail.) To follow the stream for updates:
```
POST https://example.social/inboxes/1 HTTP/1.1
Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"
{
"@context": [...],
"type": "Follow",
"actor": "https://ap.trwnh.com/actors/1",
"object": "https://example.social/collections/1"
}
```
5. The remote server then responds as per the individual implementations logic, e.g. with an `Accept Follow`
This is of course open to different methods of access control, object capability delegation, etc. the key point is that the followable object has an `inbox` to `POST` a `Follow`, which I prefer over heuristics like dereferencing `attributedTo` and looking for an `inbox` there. It is simpler to just provide the `inbox` directly. And you might as well provide an `outbox` too and make it a full-fledged actor, since being an actor doesnt actually imply much. Neither `inbox` nor `outbox` has to be public, anyway they just have to be there.
One other addendum is that, last I looked into this, I saw some discussion around Friendica and Zap having or planning support for `Follow Note`, but I was not able to find how this support was implemented, if it was.
---
@macgirvin:
Interesting. Yeah, that all make sense.
As I recall the rationale for inbox = null was a hint that an actor exists at this address, but it is only useful by some other protocol from ActivityPub. If you perform some alternate or broader scoped discovery (outside of AP) you might find that you can actually communicate with it.
We perform Follow Note and if I recall Ignore Note as internal activities to indicate you want to see (or not see) notifications for this thread in the future. We currently dont federate these activities - theyre strictly for internal use. The object is always the top-level post in a thread as these platforms default to conversation/threaded display.
Oh and the comment about permissions wasnt really about inbox/outbox but about recipient collections. We permit people to hide who is in their followers/following and circles/aspects collections if they dont feel like sharing these with the world. These will return 403 if the owner doesnt want anybody to see their contents. This affects the address de-duplication sections of the spec since these collections can only be expanded/iterated by their origin server. We do filter outbox contents based on the request http-signature but I think this is common practice.
---
@trwnh:
This may be off-topic but its worth pointing out that most projects Im familiar with tend to respond with some valid JSON(-LD), but intentionally leaving out any details the author does not want visible.
* Mastodons “Hide your network” option will return an `OrderedCollection` with the only useful property being `totalItems`. This is because Mastodons philosophy is to hide only the contents of the collection while still revealing metadata (presumably out of some concern for signaling “trustworthiness”, which to me seems flawed, but I digress):
```
GET https://mastodon.social/users/trwnh/followers HTTP/1.1
Accept: application/activity+json
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://mastodon.social/users/trwnh/followers",
"type": "OrderedCollection",
"totalItems": 2482
}
```
* Pixelfed currently does something similar, but intentionally “lies” and claims that there are 0 items while explicitly returning an empty array as the value:
```
GET https://pixelfed.social/users/trwnh/followers HTTP/1.1
Accept: application/activity+json
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://pixelfed.social/users/trwnh/followers",
"type": "OrderedCollectionPage",
"totalItems": 0,
"orderedItems": []
}
```
* Pleroma has separate toggles for hiding either the items or the count (or both). If the items are hidden, the `orderedItems` will simply not be present. If the count is hidden, the `totalItems` will simply not be present. If both are hidden, both properties will simply not be present. On a UX level, hiding the counts requires hiding the items, because hiding only the count leaves you open to manually counting the items yourself.
```
GET https://letsallovela.in/users/at/followers HTTP/1.1
Accept: application/activity+json
{
"@context": [...],
"first": "https://letsalllovela.in/users/at/followers?page=1",
"id": "https://letsalllovela.in/users/at/followers",
"type": "OrderedCollection"
}
```
* Misskey does the same thing as what you described: 403 Forbidden.
---
@trwnh:
In any case, I dont think that the spec necessarily intended to have the *sender* dereference follower collections for other actors rather, that role falls on the *receiver*, and the logic/rationale is as described in the Inbox Forwarding section, “avoiding ghost replies”:
> When Activities are received in the [inbox](https://www.w3.org/TR/activitypub/#inbox), the server needs to forward these to recipients that the origin was unable to deliver them to. To do this, the server *MUST* target and [deliver](https://www.w3.org/TR/activitypub/#delivery) to the values of `to`, `cc`, and/or `audience` if and only if all of the following are true:
>
> * This is the first time the server has seen this Activity.
> * The values of `to`, `cc`, and/or `audience` contain a Collection **owned by the server**.
> * The values of `inReplyTo`, `object`, `target` and/or `tag` are objects **owned by the server**. The server *SHOULD* recurse through these values to look for linked objects **owned by the server**, and *SHOULD* set a maximum limit for recursion (ie. the point at which the thread is so deep the recipients followers may not mind if they are no longer getting updates that dont directly involve the recipient). The server *MUST* **only target the values of `to`, `cc`, and/or `audience` on the original object** being forwarded, and **not pick up any new addressees** whilst recursing through the linked objects (in case these addressees were purposefully amended by or via the client).
>
> The server *MAY* filter its delivery targets according to implementation-specific rules (for example, spam filtering).
Essentially, inbox forwarding is a failsafe that allows a sender to say “look, heres the Activity, I dont know what this collection contains, so you deal with it, since its ostensibly under your authority.” This is why the “owned by the server” language is used multiple times in the above quoted section. Replying to, tagging, or performing an activity with the (locally owned) actor should trigger some discovery behavior. I must admit I find this recursive discovery behavior a bit problematic, although it is easier to swallow if you take it to mean “remote server implementations may notify / deliver to local actors that you reply to, tag, or act upon”. Perhaps it makes sense to notify someone if they were tagged or replied to, even if they were not explicitly addressed. Perhaps the implication is that they should be careful while doing so to not expand the scope of delivery. Perhaps the language in this third bullet point is simply bad language or bad guidance.
With that said, what matters for the purpose of inbox forwarding is that, if you are delivering to someone elses followers collection, then the sender needs to know how to refer to the `followers` IRI. But `followers` as a property is only a SHOULD and not a MUST. And I guess the “spam filtering” clause above also opens the door to implementations simply choosing *not* to forward to someone elses followers. (I think Mastodon does indeed filter out activities delivered to someone elses followers collection, based on a friends testing, but I cant remember for sure.) Anyway, a server that only implements S2S and not C2S might as well leave out the `followers` and `following` entirely, for privacy purposes. I dont think this would break anything if it does, that points to bugs in existing implementations. (Okay, it might break sharedInbox.)
One other tangent about inbox forwarding and addressing in general, that I might follow up on in another topic: I wish implementations would use `audience` more. It should be standard behavior to comment on someones post and address them, plus the value of `audience` (plus any other arbitrarily mentioned/added people, plus maybe your own followers). The audience of a post should be used even above `to`/`cc`, because to me `audience` carries human semantics while `to`/`cc`/`bto`/`bcc` are for server communication. For S2S purposes, the server implementation is actually free to deliver several slightly different activities to different inboxes, and in the case of `bto` and `bcc` this differing behavior is actually required. This, combined with the previous paragraph, leads to an issue where one may target their own `followers` collection without actually advertising it as their `followers` collection. Im not sure what kind of undefined behavior that would lead to… its things like this that make me think sharedInbox was a mistake.
---
@macgirvin:
This whole clause is about “conversational delivery” ; which is completely different from microblog use. We use conversational delivery so I understand it very well. This is the two fediverses problem I speak about quite often.
Ill put it in very simple terms. We have the Twitter fediverse and the Facebook fediverse. The protocol supports the Facebook fediverse through inbox forwarding but Twitter-like projects dont understand it and do things that break the Facebook fediverse. We can get along together but the first step is acknowledging that both models exist and learning how to implement both. The Facebook fediverse is important for things like private groups (ok “restricted”) and circles (restricted collections), so Twitter-like projects can get some benefit from supporting both.
And we can implement both. In the Facebook fediverse all comments to a restricted (not public) post go back to the sender of the top-level post and to nobody else. The actor that sent the top-level post delivers the comments downstream to all of the original recipients of the top-level post - and to nobody else. If its a public conversation commenters can send to whoever they want. This is the secret sauce that makes restricted conversations work.
In this model the sender of the top-level post is the only delivery authority for the entire threaded conversation. Now realise that this section was added to ActivityPub so that Facebook-like projects such as Friendica, Diaspora, and Hubzilla could exist in an ActivityPub fediverse, but the people writing the spec were nearly all from the Twitter side of the fediverse and to this day the Twitter side doesnt recognise that the Facebook side exists and has a different addressing/delivery model than they do.
It seems from your reply that conversational delivery is a bit alien to you as well. No worries. Ive proposed a mechanism to let everybody know for any given conversation which model to use. Its pretty simple and uses replyTo and works the same as emails reply-to. If its set, thats who you reply to - and you dont cc or deliver to anybody else; and you also copy that replyTo to your own comment before sending. If it isnt set, send your comment to whoever you want. Twitter-like projects will never set it except maybe in circles/aspects or private/restricted groups. Facebook-like projects will probably always set it except maybe in public conversations when their posts benefit from exponentially widening reach. And everybody lives happily ever after in the same fediverse. We support this today.
---
@trwnh:
Small point of contention: “Twitter fedi” projects like Mastodon implement inbox forwarding, but they dont make it the main mechanism of delivering replies in the same way that “Facebook fedi” projects expect to redistribute comments.
I am familiar with that model, and in fact Dennis Schubert proposed it some years back in criticism of the “twitter fedi” approach [ActivityPub - one protocol to rule them all? - Dennis Schubert ](https://overengineer.dev/blog/2018/02/01/activitypub-one-protocol-to-rule-them-all.html#replies-and-interactions) proposed back in 2018 that “Alices host is the one who delivered the shareable, so it feels somewhat natural to also ask Alices host to distribute the interactions […] a more sensible, reliable, and even more AcitivityStreamy way of handling replies would probably be adding the interaction to the replies collection and sending an `update`”. Whether the original activity is forwarded or whether an Update is sent doesnt particularly matter to me, since the model works the same either way your interaction exists in context of some top-level object.
In fact, we could be more explicit with this model by using the `context` property (which sadly goes largely unused on “twitter fedi”). If a post has a `context` of another post, it is a comment (Facebook-style). Otherwise, it is just a post (Twitter-style). These (Twitter-style) posts can exist in context of a Collection representing a conversation, or they can exist in a null context.
> Ive proposed a mechanism to let everybody know for any given conversation which model to use. Its pretty simple and uses replyTo and works the same as emails reply-to. If its set, thats who you reply to - and you dont cc or deliver to anybody else; and you also copy that replyTo to your own comment before sending. If it isnt set, send your comment to whoever you want.
Hmm, I guess this makes sense as a mechanism its like a more explicit version of `context`. Prior to this conversation I would have probably proposed something like the following algorithm:
1. Try to resolve `context` and check for `attributedTo`.
2. Resolve everything in `attributedTo` and deliver to any `inbox` found.
3. If there was no `context.attributedTo` or no actors/inboxes could be found, or if there was no `context`, then deliver your reply to whomever (your followers, as:Public, etc).
Again, though, Im not sure if `context.attributedTo.inbox` is the best approach here. At least `replyTo.inbox` saves a lookup step, and allows delivering to different actors, which would allow modeling anonymous objects.
As far as `context` goes, though, it would probably be a good idea to assign `context` = the top-level post (Facebook-style) or `context` = some Collection representing the conversation or thread, and then copy the `context` as-is when replying/commenting.
Perhaps an algorithm which supports both `context` and `replyTo` would look like this in pseudocode:
```
# Determine to/cc addressing
if "replyTo" in activity:
to = [
actor["inbox"]
for actor in activity["replyTo"]
if "inbox" in actor
]
elif (
"context" in activity
and "attributedTo" in activity["context"]
):
to = [
actor["inbox"]
for actor in activity["context"]["attributedTo"]
if "inbox" in actor
]
else:
to = ACTOR["followers"] + PUBLIC
# Copy any values that should be copied
if "replyTo" in activity:
replyTo = activity["replyTo"]
if "context" in activity:
context = activity["context"]
```
---
@macgirvin:
We also use context as youve described - but recently a number of new projects have started using context for other things than conversation ids. Fetching our context in fact returns a collection of the entire threaded conversation as seen by the root node - which is something I also wish more projects supported. But now that folks are doing other things with context and we also still have folks using them with OStatus semantics (which arent de-reference-able) I suppose well eventually have to come up with a different cross-platform way of fetching the entire conversation. Oh well.
Cheers.
## current thoughts
i plan to synthesize several things here -- a collection that could also be an actor, and maybe set as context. see FEP-7888 and a future FEP for that i guess

View file

@ -0,0 +1,159 @@
+++
title = "Resolving the Note vs. Article distinction"
date = "2019-11-01"
+++
## preserved text
<article>
# Background
[Activity Vocabulary - 3.3 Object Types ](https://www.w3.org/TR/activitystreams-vocabulary/#object-types):
> **Note**: Represents a short written work typically less than a single paragraph in length.
> **Article**: represents any kind of multi-paragraph written work.
Example 48 (Article):
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Article",
"name": "What a Crazy Day I Had",
"content": "<div>... you will never believe ...</div>",
"attributedTo": "http://sally.example.org"
}
```
Example 53 (Note):
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"name": "A Word of Warning",
"content": "Looks like it is going to rain today. Bring an umbrella!"
}
```
Semantically, the difference is never explicitly defined (how do you define a “paragraph”?), so the current fediverse has sort of assumed Article should be viewed natively on the remote website, while Note can be displayed as an inline status. Thus, Note is used to represent a status update, and a lot of the network just defaults to Note. The distinction is assumed to be formatting, but once again this is not an explicit definition (how do you define “formatting”?)
# Disambiguation
Going purely from the Activity Vocabulary descriptions and examples, I would possibly assume one or both of the following:
* Note SHOULD be plain text, Article SHOULD use HTML (or should these be a MUST?)
* Note SHOULD NOT use newlines (but are technically allowed to do so)
However, there is [ActivityPub 3.3 ](https://www.w3.org/TR/activitypub/#source-property), Example 8:
```
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "en"}],
"type": "Note",
"id": "http://postparty.example/p/2415",
"content": "<p>I <em>really</em> like strawberries!</p>",
"source": {
"content": "I *really* like strawberries!",
"mediaType": "text/markdown"}
}
```
This example Note uses HTML for its `content`, in order to demonstrate the `source` property.
Also, ActivityPub Example 4:
```
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://chatty.example/ben/p/51086",
"to": ["https://social.example/alyssa/"],
"actor": "https://chatty.example/ben/",
"object": {"type": "Note",
"id": "https://chatty.example/ben/p/51085",
"attributedTo": "https://chatty.example/ben/",
"to": ["https://social.example/alyssa/"],
"inReplyTo": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19",
"content": "<p>Argh, yeah, sorry, I'll get it back to you tomorrow.</p>
<p>I was reviewing the section on register machines,
since it's been a while since I wrote one.</p>"}}
```
This example Note uses two `<p>` elements, representing two short paragraphs (once again not “less than a single paragraph”).
So even the specs themselves are inconsistent on any distinction.
# How much does this actually matter?
Arguably not much, since implementations often convert Note and Article into their own internal schema for statuses anyway. But it could still be beneficial to set a clearer distinction going forward on how these types should be assigned, ideally.
</article>
---
@lanodan:
The distinction I make between Article and Note isnt related directly to its content but on how its supposed to be presented and used, Articles are more things for blogs where you have about a post per day and so articles should be easy to find back with a list of articles/tags and maybe a bit of search features, Notes are more stuff like microblogging where you can easily have hundreds in a day and arent that easy to find back even with good keywords in full text search.
Also I find that formatting is actually very useful for notes because it allows to express more/equivalent with less (like a word-list vs a paragraph).
This question goes a lot in the fediverse because they are the two mainly used activity types but one could also ask about the actor distinction between Organisation and Group, Application and Service. And so far Ive only seen ActivityPub Document be used in the wild for Images with textual description (like if Image couldnt have it in the first place), but Document has no inherent meaning either.
Note: Pleroma keeps the distinction between Articles and Notes internally, no real differencies for the Mastodon API though but there could be a query filter.
---
@trwnh:
For prior art, I can think of semantic HTMLs `<article>` being a section of HTML that can be reproduced elsewhere in its entirety.
W3Schools: "independent, self-contained content. An article should make sense on its own and it should be possible to distribute it independently from the rest of the site."
MDN: "a self-contained composition in a document, page, application, or site, which is intended to be independently distributable or reusable e.g. in syndication."
This could be a distinction worth making, maybe? that an Article should roughly map to an `<article>`, whereas a Note is just arbitrary text?
---
@nightpool:
I think using `Article` is a perfectly fine solution for when the desired semantics are “I think its better in a short-form microblogging context to display a link to this thing rather then the full content itself”.
When considering that some clients (especially native clients) often wont support increasingly rich text formatting, I think using Article vs Note for content where you think plain-text fallback is unacceptable is a totally fine decision to make. (But you shouldnt ignore the fact that its probably likely that people are going to write long-form clients that *do* support Articles but dont support every possible type of rich text formatting, like the way RSS readers restrict allowed formatting for readability)
---
@trwnh:
I cant remember where this was said to me, but I think someone (maybe nightpool?) suggested that Note could be used for message passing a la Discord, which would be a third distinction and perhaps better than length/newlines or plaintext (as explained previously why those are inconsistent). So in that case, we could say Note vs. Article is one of *formality*. IMO this could complement the Article-to-`<article>` suggestion above.
Taken together:
* Note = for informal message-passing
* Article = for publication or syndication
The only thing unresolved with this distinction would be the blurry line that is microblogging. Microblogs are often both informal *and* intended for republishing in feeds. Itd be pretty clear-cut to use Note for a messaging application and Article for a blogging platform, but… perhaps this implies top-level microblogging posts should be an `Article` and replies should be `Note`? Or that they should all be `Article` regardless of the fact that they are informal? Theres still room for discussion there.
---
@darius:
I think this is right on the money. My main use case for Article is that its a way to say that “this is a publication” Ive often talked about how this might actually help solve the “quote-tweet” design problem in Mastodon (and presumably other software). If an Article is something that is formal and published then its also something that can reasonably be commented upon. Articles can be quoted-commented, and Notes cannot. So I can dunk on a New York Times article, but not on a random thing someone posted as a note.
Edited to add: for composing posts on a microblogging service, I wonder if a “people can quote-comment on this post” checkbox or whatnot could be, at its most basic, a switch that underneath it all changes type for your post from Note to Article.
---
@trwnh:
quoting and commenting is kind of out-of-scope and its up to each platform to decide how they want to handle it, tbh. from a data view, it doesnt really matter because you can put whatever you want in `content`, and `inReplyTo` is just metadata (like `tag`). You can have an Article inReplyTo another Article, just as you can have a Note inReplyTo another Note (or a Note inReplyTo an Article, or even vice-versa, etc etc.)
the thing is, though, that its really seeming like if we use “syndication” as the distinction, then that would imply a lot of things that are currently Note might be better conceived of as Article.
---
## current thoughts
i wrote a whole thing abt this [here]({{< relref "!note-vs-article" >}})

View file

@ -0,0 +1,60 @@
+++
title = "Notifying remote servers that they should refetch an object"
date = "2019-11-01"
+++
{{toc}}
## Preserved text
<https://socialhub.activitypub.rocks/t/notifying-remote-servers-that-they-should-refetch-an-object/259>
@trwnh:
[quote="trwnh, post:1, topic:259, full:true"]
S2S Update:
> 7.3 Update Activity
>
> For server to server interactions, an `Update` activity means that the receiving server *SHOULD* update its copy of the `object` of the same `id` to the copy supplied in the `Update` activity. Unlike the [ client to server handling of the Update activity ](https://www.w3.org/TR/activitypub/#update-activity-outbox), this is not a partial update but a complete replacement of the object.
>
> The receiving server *MUST* take care to be sure that the `Update` is authorized to modify its `object` . At minimum, this may be done by ensuring that the `Update` and its `object` are of same origin.
Presumably sending something like this over S2S would just get the object replaced by an empty copy:
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/activities/1",
"type": "Update",
"actor": "https://example.com/actors/1",
"object": "https://example.com/objects/1"
}
```
So how would this update/refetch notification be done properly?
[/quote]
---
@nightpool:
wait, what? why would the example posted not be compliant? The two representations (including an IRI to dereference vs including an embedded object) should be identical on the JSON-LD level.
I agree that the spec might expect you to inline the object, but I absolutely disagree that it requires it.
---
@kaniini:
I agree with nightpool, a bare IRI is completely fine here.
---
@trwnh:
OK, then. If a bare IRI is fine, then the next question would probably be how this would be handled in existing implementations. If an ActivityPub implementation were to hypothetically use Update in this manner, would it be received and handled properly?
## Current thoughts
needs testing or review, but should be possible imo. and if it's possible then maybe it could be expected?

View file

@ -0,0 +1,82 @@
+++
title = "Signaling side effects asynchronously by generalizing Accept/Reject"
date = "2019-10-11"
+++
{{toc}}
## Preserved text
<https://socialhub.activitypub.rocks/t/signaling-side-effects-asynchronously-by-generalizing-accept-reject/125>
<article>
# Background
Per S2S (since Accept/Reject are not described in C2S):
> 7.6 Accept Activity
>
> The side effect of receiving this in an **inbox** is determined by the type of the `object` received, and it is possible to accept types not described in this document (for example, an `Offer` ).
>
> If the `object` of an `Accept` received to an **inbox** is a `Follow` activity previously sent by the receiver, the server *SHOULD* add the `actor` to the receivers [Following Collection](https://www.w3.org/TR/activitypub/#following).
>
> 7.7 Reject Activity
>
> The side effect of receiving this in an **inbox** is determined by the type of the `object` received, and it is possible to reject types not described in this document (for example, an `Offer` ).
>
>
>
> If the `object` of a `Reject` received to an **inbox** is a `Follow` activity previously sent by the receiver, this means the recipient did not approve the `Follow` request. The server *MUST NOT* add the `actor` to the receivers [Following Collection](https://www.w3.org/TR/activitypub/#following).
Note that for S2S purposes, Accept/Reject is only really defined for Follow activities. Per the Activity Vocabulary, it is also implicitly appropriate for `Offer` and `Invite`, but also [Example 10](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept) shows a much more ambiguous Accept Person targeting Group, which seems semantically awkward.
# Possible generalizations
Currently, the majority of the network uses Accept/Reject only for Follow on an Actor, and thus Accept/Reject is used only in that narrow definition. But there are other Activities that might require these semantics…
## Accept/Reject Join
Closed-membership `Group` semantics is maybe the most obvious benefit of generalizing Accept/Reject. It is of course possible to both Follow and Join a Group; Follow Group would semantically translate to being interested in what the Group posts to its outbox, as per the base AP spec. Some softwares handle Group membership based on its `followers`, but this is a bit of a hacky way to do things that is motivated by compatibility with the existing “Follow Actor” network. A much more semantic way to handle things would be to allow Join/Leave Group, but then Join would need Accept/Reject to allow modeling closed groups (at least, in a way different than just using the `Group` `followers` with `manuallyRequiresApproval` + `Announce` any activities received at `inbox` which is still a valid way of doing things for “mailing list” use cases). This would be clearer than Accepting a Person into a Group.
## Accept/Reject Create
When sending a Create to a remote server, there will generally be side effects interpreted by that remote servers software. One common example is that sending Create Note with `inReplyTo` may attach your Note as a reply to another Note. But this is not guaranteed to happen, e.g. if the remote software has a concept of “disabled comments” or “approved comments”. In that case, the remote software may want to signal that the use of `inReplyTo` will not automatically cause side effects to be processed, in the same way Follow must first be Accepted or Rejected. It might not make sense to explicitly *require* Accept/Reject semantics for such a case (as they are for Follow), but they can still be used for hinting the result.
## Accept/Reject Update/Add/Remove/Delete
In cases where an actor is performing actions on an object other than creating it, these actions may require approval from another actor who “owns” or “manages” that object. You may want to Accept an Offer of an Update, but it would be simpler to just Accept the Update. Per the AP spec, the only considerations made are as follows:
7.3 Update:
> The receiving server *MUST* take care to be sure that the `Update` is authorized to modify its `object` . At minimum, this may be done by ensuring that the `Update` and its `object` are of same origin.
7.4 Delete:
> (assuming the `object` is owned by the sending actor / server)
7.8 / 7.9, Add/Remove:
> * the `target` is not owned by the receiving server, and thus they cant update it.
> * the `object` is not allowed to be added/removed to the `target` collection for some other reason, at the receivers discretion.
So we have some guidance toward the “receivers discretion”, but no formal way of signaling that discretion back to the author of the received activity.
# But why not just use HTTP status codes?
HTTP status codes are synchronously returned at the time of the request, even if the request is handled asynchronously. You may send out a `202 Accepted` to indicate that the document was successfully received, but later send out a `Reject` Activity after some manual action was taken by an actor. This manual action may be performed long after the initial delivery to the remote server.
[/quote]
</article>
---
@nightpool:
I think this is a good idea, but i would like to see some implementor support before defining it further.
---
## current thoughts
yeah, actually. let's do it

View file

@ -0,0 +1,114 @@
+++
title = "Stricter specifications for pagination of Collections and OrderedCollections"
date = "2022-11-05"
+++
## Preserved text
<https://socialhub.activitypub.rocks/t/stricter-specifications-for-pagination-of-collections-and-orderedcollections/2633>
@trwnh:
<article>
## Overview
ActivityPub primarily depends on direct delivery of activities, but many implementations expose old post history via the `outbox`. In theory, you could fetch the outbox to discover old posts that werent delivered to you but should still be visible to you (e.g. Public posts that persist in the outbox). However, there is one big problem: pagination.
Specifically, pagination is an issue because you will have to fetch multiple pages, and you dont know exactly when to stop, or how to discover gaps. You may be able to fetch up until you see a post that you already have, but there may be other unseen posts beyond that one. The only way to be sure is to fetch every single page of the outbox, which can be a costly operation.
## Recommendations
Arguably, this situation can be improved by making some specific recommendations:
### Construct chronologically, but present in reverse order
Because an OrderedCollection is mandated to be “reverse chronological” specifically, extra care needs to be taken to allow stable page references. Perhaps pages should be built chronologically and simply presented in reverse order, crucially with the `first` page containing less than than the max page size.
Example: A page size of 10 and a collection of 23 items should be split into pages of 3, 10, 10. These pages would be presented as such:
```
[
[23 22 21]
[20 19 18 17 16 15 14 13 12 11]
[10 9 8 7 6 5 4 3 2 1]
]
```
### Stable page references should also be reversed
Furthermore, in order to maintain stable page references, such that if youve fetched a page before you dont have to fetch it again, page counters should be assigned in reverse order as well.
Taking the example from above, the pages would be identified as 3, 2, 1:
```
[
[23 22 21] // page 3
[20 19 18 17 16 15 14 13 12 11] // page 2
[10 9 8 7 6 5 4 3 2 1] // page 1
]
```
### Deleted items should either be Tombstoned or change the page size
All this work is useless if the pages have to be recalculated or the items get shifted to a different page. To prevent this, either serve a Tombstone in place of deleted items, or otherwise freeze the upper and lower bound of a page while allowing variable page sizes.
For example, lets say we delete post 17. The result might look like this:
```
[
[23 22 21] // page 3 (3 items)
[20 19 18 T 16 15 14 13 12 11] // page 2 (10 items, 1 Tombstone)
[10 9 8 7 6 5 4 3 2 1] // page 1 (10 items)
]
```
Or, it might look like this:
```
[
[23 22 21] // page 3 (3 items)
[20 19 18 16 15 14 12 11] // page 2 (9 items)
[10 9 8 6 5 4 3 2 1] // page 1 (10 items)
]
```
Notice that page 3 remains unchanged, rather than item 21 becoming part of the 2nd page.
### Accessing pages should be done in a consistent way
The final piece of the puzzle is a way to consistently load specific pages. For example, consider a collection at `/collection/id`. You might be able to attach a query parameter `?page=N` to access the Nth page via `/collection/id?page=N`. Or you might have some route such as `/collection/id/page/N`. Whatever the case, there should be a way of getting pages that can be expected to work across all implementations. Or, at the very least, a way that may be inferred easily, but a standard pagination technique would be better.
My thinking is that `/page/N` would be better, because it would allow for static pages as an option more easily,
Also for consistency: Tombstone is preferable to exclusion, because it allows dynamic page sizing on-the-fly in dynamic servers that use query parameters.
</article>
---
@silverpill:
Perhaps a timestamp filter could solve this problem?
For example, `/collection/id?after=1667766000` can return a paginated subset of the collection, and if the client knows the time of the last sync, it can retrieve missing objects with fewer requests.
This way implementations can continue to use their preferred pagination mechanism.
---
@trwnh:
Having a timestamp filter might work for dynamic server implementations but not for static server implementations. I took care in making sure, while writing the above post, that the recommendations would be applicable to both static and dynamic servers.
---
@trwnh:
in writing this up i seem to have overlooked the `startIndex` property of OrderedCollectionPage, which is basically just a positive offset for how far into the OrderedCollection you are with the first item. unfortunately this is less useful due to reverse chronology being mandated by ActivityPub; it would be far more useful in a forward-chronological collection. it also doesnt apply to regular CollectionPage sadly.
there is still the option of having a regular Collection contain OrderedCollectionPage, though, or otherwise simply disregarding the “MUST be reverse chronological” bit and committing a spec violation.
---
## current thoughts
idk. really wish the OrderedCollection wasn't mandated to be reverse-chron and it was instead forward-chron at least. this carries over to OrderedCollectionPage too...

View file

@ -3,7 +3,6 @@ toc = true
autonumbering = true
+++
## (closeable)
- #1062 remote follow dialog should make it easier to recommend or remember your instance [was fixed by cookies but not closed. later the whole "remote follow" dialog was removed in 4.0]
@ -43,6 +42,13 @@ autonumbering = true
- #5784 [someone confused that local timeline isn't geographically local]
- #5788 remember timeline position [we have timeline markers now]
- #5915 rename lists and support filters on lists [done now]
- #6041 add self to own list [done now]
- #6069 notification for when someone signs up on bridge.joinmastodon.org [which is long dead]
- #6079 replying to post mentioning multiple users does not focus on compose box [yes it does now i tested it]
- #6087 auto-CW long posts or auto-CW certain users [first half done, second half is dupe of #6078 after filter revamp]
- #6137 deleted accounts appear in searches [not anymore? can't replicate]
- #6220 insert spaces between text and custom emoji shortcode when selecting custom emoji [tested, it does this now]
- #6239 captioning images resets focus to compose box [no longer valid; images are captioned in a separate modal now]
### (duplicates)
@ -51,6 +57,8 @@ autonumbering = true
- #4098 duplicate of #609 ("private profiles" vs "private-ish profiles")
- #5491 duplicate of #1306 ("timeline jumps due to incoming posts")
- #5710 duplicate of #4305 ("make getting started movable" vs "make context column movable")
- #6093 duplicate of #6078 (filter out by username includes filtering yourself out)
- #6288 duplicate of #34 (backfill statuses from remote accounts)
### (maybe closeable?)
@ -76,6 +84,12 @@ autonumbering = true
- #5612 Support `longdesc` on images [longdesc is deprecated and obsolete apparently]
- #5737 store metadata about relationship changes (when/why) [we have profile notes now so that probably works]
- #5896 allow mods to force hide all media from an account [is this the same as "force-mark as sensitive" or is it more like "reject media"?]
- #6033 postgres 10 has a long-running query on public timelines? [is this still relevant]
- #6064 remote suspensions do not always reach you for followers? [has this been fixed now? issue is from 2017]
- #6073 hashtag cloud on landing/about page [is this addressed by trending tags on explore page?]
- #6135 404 on follow attempt [old issue, not replicated]
- #6250 don't send email notifications if a notification is seen in an active session [isn't this done by default now? there's a setting to "always send"]
- #6321 "quiet hours" mode where notifications are not shown [this is done at the OS level]
---
@ -120,6 +134,14 @@ autonumbering = true
- #5658 remote gif avatar gets corrupted on docker instances
- #5707 wrong localization for zh-TW on relative short timestamp
- #5960 status creation fails on id collision in transaction
- #6070 discovering a post that wasn't federated can cause the counter to +1 mistakenly
- #6083 a certain video got stuck on the first frame
- #6113 favorite/boost counts take a while to update/refresh
- #6139 old accounts deleted manually should be cleaned up [do we have this as a rake task or tootctl cleanup command?]
- #6156 hide boosts from someone you follow, and you will not receive boost notifications from them
- #6208 if the timeline is full of filtered posts, it doesn't load more
- #6329 atom feeds have a CORS issue
- #6338 zwsp is wrongly included in URL parser but correctly removed by hashtag parser
### (feature requests)
@ -160,6 +182,9 @@ autonumbering = true
- #5691 allow users to select their language on the landing page while logged out
- #4983 [original issue was about making posts unboostable, but was misunderstood to be about filtering out notifications for when a certain post is boosted]
- #5787 separate preference for "autoplay media" and "animate emoji"
- #6094 embed profiles or timelines
- #6122 tell the user when they are impacted by instance domain blocks
- #6332 show which local users follow a remote user in the moderation UI
#### (more niche)
@ -171,6 +196,10 @@ autonumbering = true
- #5675 choose the default tab for your profile
- #5714 maybe your posts should be cached offline in the web app's local storage so that if your instance goes offline you have a backup
- #5867 Support 360 panaroma photos
- #6067 notify when a hashtag is used
- #6084 user analytics
- #6090 RSS feed for all interactions on a post?
- #6350 choose the date format localization for timestamps
### (meta)
@ -186,6 +215,7 @@ autonumbering = true
- #5781 refetch avatars (and other media?) after remove instance domain block with "reject media" checked
- #5797 prevent replying to someone without mentioning them
- #5883 allow pagination from oldest to newest [or discover the oldest post id somehow]
- #6136 API request limit should be higher -- 100 statuses?
#### (vague or inactionable)
@ -200,7 +230,8 @@ autonumbering = true
- #5553 urls should not be assumed 23 characters
- #5686 two stages of following -- unapproved and approved. send public posts to unapproved followers [could be handled with audiences instead?]
- #5723 granular post privacy (control whether post goes to public timelines, is available unauthenticated, local-only, etc)
- #5774 ability to change your instance domain (LOCAL_DOMAIN)
- #5774 ability to change your instance domain (LOCAL_DOMAIN)
- #6192 scss stylesheets should have more color variables
---
@ -225,6 +256,13 @@ autonumbering = true
- #5619 Suport Alibaba Object Storage as an alternative to S3
- #5729 Replace Paperclip with Shrine
- #5972 Rename "always mark media as sensitive" to "Mark media as sensitive by default" [TODO: Low hanging fruit]
- #6007 button to generate archive exports on behalf of the user, then email them with a link to that archive
- #6031 Full-width japanese period gets included as part of path query in URLs (after the slash). this can break links
- #6351 URL renderer / linkifier adds empty span.invisible to the end of many links
#### specific to search
- #6287 search for multiple hashtags
#### specific to signups and new accounts
@ -238,12 +276,14 @@ autonumbering = true
- #4640 activitypub property to signal when you opt out of search indexing (similar to robots.txt or robots meta tag in html)
- #4964 use a versioned json-ld @context [currently mastodon just uses the unversioned activitystreams context, but i'm not entirely sure what issues this may cause if any and why]
- #5500 human-readable errors on trying to post to activitypub inbox endpoint
- #6262 converted statuses should append Hashtags to the end of the status_content maybe?
#### REST API
- #2048 support Android Intent URIs when registering a client app [currently failing due to use of `#` in uri; workaround is to register custom scheme in android?]
- #5273 API response should include Relationship on each Notification, so that you can tell when a notification came from a follower/following/mutual [arguably you could embed the Relationship on the Account but that might be expensive]
- #5492 API for a client app to update its own registered information (such as `redirect_uris`) using an app token generated from the stored `client_id`+`client_secret`
- #6040 errors should have a non-localized string key to identify which specific error occurred (can be matched exactly)
#### Streaming API
@ -277,6 +317,13 @@ autonumbering = true
---
### Filters
- #18955 Revamp filters to cover more use cases
- #6078 Filters ignore username
---
### Lists
- #5938 backfill lists when adding new accounts to them
@ -301,6 +348,10 @@ autonumbering = true
- #1471 show account preview on hover
- #1955 hash acct/url and pick a distinct color to allow more easily identifying when an account is different or is a homograph and possibly impersonation
- #4647 when you hide media that isn't marked nsfw, it should stay hidden persistently (currently it is reshown on refresh)
- #6028 poor contrast on the CW and privacy toggles in the compose form
- #6034 clarify the difference between "desktop notifications" and "push notifications" toggles
- #6035 notification settings are messy and poorly laid out
- #6210 show when a boost was made, not just the original post timestamp
- #7860 show confirmation dialog before more things
- #3702 show confirmation dialog before posting
@ -338,6 +389,7 @@ autonumbering = true
- #921 `rich` OEmbed (e.g. for soundcloud)
- #1255 allow wider aspect ratios instead of zoom-cropping thumbnail [auto height instead of `object-fit: cover`?]
- #2034 when a modal is open, pause all animations in the background
- #6254 "reduce motion" should disable side-scrolling animation for preview of multiple images
##### specific to authoring media
@ -362,6 +414,8 @@ autonumbering = true
- #3875 "edit profile" link should be easier to tap on mobile [TODO: low hanging fruit]
- #4508 better focus contrast / visibility for status action buttons [currently, there is a slight transparent background on focus but no prominent outline like other focused elements] [TODO: low hanging fruit] [side note: the video player has even worse contrast on focus, i legit could not tell it was focused]
- #4510 when you focus on a post and expand it, the focus should shift to the detailed status view instead of staying in the column
- #6152 larger click/touch target for adding account to list
- #6185 error toast notifications should show up closer to the source of the error, not in the lower left corner
##### performance
@ -401,6 +455,25 @@ autonumbering = true
- #3872 combine Getting Started + Compose into one column, since they're both always open?
- #4399 CW toggle and sensitive media toggle should be linked such that expanding a post expands the media with it, and collapsing a post should rehide the media
- #4689 CW and sensitive media should not be linked at all
- #6141 show a media indicator in the CW "show more" toggle
- #5727 UI mockup for two-column layout on tablets
- #5736 more layout adjustments. variable column width, variable font size, variable media thumbnail size
- #5958 quickly switch between lists in a pinned column, or allow pinning the main "Lists" list
- #5958 quickly switch between lists in a pinned column, or allow pinning the main "Lists" list
- #6267 use typescript
---
<script>
let tag = /\#(\d+)/g;
let link = '<a href="https://github.com/mastodon/mastodon/issues/$1">#$1</a>';
document
.querySelectorAll('li')
.forEach(
(node) => {
node.innerHTML = node.innerHTML.replace(tag,link);
}
);
</script>

View file

@ -29,12 +29,18 @@ if you receive an Accept/Reject Follow, check ONLY for the following:
if object is inlined, you don't need to check that object.id is local. the above is enough information, PROVIDED THAT you have a local pending follow request. if you do not have a pending follow, then DO NOT process an incoming Accept Follow. however, you may receive a Reject Follow at any time, indicating that you should destroy that follow relationship. note that you may also receive an Undo Accept Follow by some implementations. this is discouraged but should be handled as well
<https://github.com/misskey-dev/misskey/issues/9250>
## DO NOT CHECK TYPES DURING VALIDATION
an Actor has an `inbox` and `outbox`. that's it.
an Activity has an `actor`. that's it.
a Collection has `items` or `orderedItems`. that's it.
etc
## DON'T PANIC WHEN YOU SEE A TYPE YOU DON'T UNDERSTAND
say you understand tags of type Mention and Hashtag and Emoji. someone sends you a `tag` array with a raw Link. DON'T PANIC. the document is still valid. just filter out anything you don't understand, something like
@ -56,4 +62,24 @@ const UNDERSTOOD_TAG_TYPES = new Set(["Mention", "Hashtag", "Emoji"])
let document = ...
tags = document.tag.filter(tag => tag.type in UNDERSTOOD_TAG_TYPES)
// do whatever you need to now
```
```
## DO NOT CONFUSE ITEMS AND ORDEREDITEMS
`items` indicates that this is a Collection
however, `orderedItems` is valid on both Collection and OrderedCollection! it is defined like this in the as2 context:
```json
"orderedItems": {
"@id": "as:items",
"@type": "@id",
"@container": "@list"
}
```
so it is basically just an alias for `items` where it MUST be an array, and the array's order matters. (if it were `@container: set`, then it MUST be an array, but the array's order does not matter.)
### tangent: a Collection may be ordered without being an OrderedCollection
OrderedCollection is defined as strictly reverse chronological by ActivityPub. however, other orderings are valid on regular Collections. the use of the `orderedItems` term allows plain-JSON implementations to do exactly this.

View file

@ -0,0 +1,20 @@
+++
+++
A Collection is an Object that has `items` or `orderedItems`
however, `orderedItems` is valid on both Collection and OrderedCollection! it is defined like this in the as2 context:
```json
"orderedItems": {
"@id": "as:items",
"@type": "@id",
"@container": "@list"
}
```
so it is basically just an alias for `items` where it MUST be an array, and the array's order matters. (if it were `@container: set`, then it MUST be an array, but the array's order does not matter.)
### tangent: a Collection may be ordered without being an OrderedCollection
OrderedCollection is defined as strictly reverse chronological by ActivityPub. however, other orderings are valid on regular Collections. the use of the `orderedItems` term allows plain-JSON implementations to do exactly this.

View file

@ -0,0 +1,75 @@
+++
+++
FEP-7888: Demystifying the context property <https://socialhub.activitypub.rocks/t/fep-7888-demystifying-the-context-property/3021>
## conceptual overview
ActivityStreams Vocabulary defines the context property, but it is "intentionally vague". Unfortunately, this makes the definition so vague as to be practically useless.
Aside from being "intentionally vague", the definition is also somewhat circular; it requires knowing what a context is and having some conceptual understanding of the notion of "context". However, we are given some guidance towards its "intended function", which is to group objects by some common purpose or origin.
We might similarly use a `tag` for grouping objects and activities. Current fediverse projects often include a `Hashtag` (defined as an extension within the ActivityStreams namespace, but not actually adopted or defined formally). This `Hashtag` signals an intent to be included or discovered through a collection of objects bearing the same `Hashtag`, uniquely identified by its `name`. The maintenance of such collections is assumed to be the responsibility of the receiving server, although an `href` is provided for convenience, in order to browse the collection of tagged objects at the source. (This also makes the `Hashtag` a sub-type of `Link`.)
The key property of such a tag is to signal a general, implicit association by reference. We might then consider a context to be an explicit association, but such an explicit association requires an explicit definition.
Various dictionaries define context generally as something that helps you understand the situation. Following from this, the context should be something that helps you process the activity or object. Ignoring the context may lead to misunderstanding the activity or object; the object or activity exists *within* that context.
Specific contexts can be thought of in several applications:
- the "authoritative context" is a context in which some authority can be applied;
- the "conversational context" is a context which represents some conversation and possibly its history;
- the "originating context" is a context which represents some intended starting point that you might look at first.
We might continue to articulate further types of contexts, but the general pattern that emerges is that a context exists to form a purposeful grouping, regardless of the specific purpose. For example, if we had the notion of a conversation, then we might reasonably say that someone owns this conversation and can apply their authority to it. Looking at some object or activity within this context is generally not recommended on its own; it is better to view the entire conversation or some page of it rather than viewing a singular message.
The context may be presented using the following abstractions:
- A "topic" in a forum presentation
- A "conversation" in a social networking presentation
- A "room" in a chatting or messaging presentation
- A "thread" in any of the above contexts (forum thread, social media thread, chat thread)
Contexts may be nested within other contexts:
- A forum topic/thread may be nested in a "forum" or "forum category", and may be nested in another parent forum as a sub-forum.
- A "wall" on a profile or group may contain conversations, which in turn may contain the top-level object and its comments
- A "guild" or "space" may contain multiple chat rooms with a common audience
It is also possible to *not* have a context. Such objects exist only in the general context of their author (via `attributedTo`) and are otherwise self-sufficient. This can include:
- An article published on a web site, particularly one meant to be accessible directly via a permalink
- A post in a blogging or microblogging environment, particularly one that does not represent a conversation, or where `inReplyTo` is meant only as a loose reference.
- An activity intended for or acting upon an object without a context
## normative language
The use of `context` SHOULD adhere to the following guidelines:
- The `context` SHOULD have a purpose. Consider tags for looser references.
- The `context` SHOULD be resolvable. The resolved object or link should describe the context with at least the additional information needed to fully process the activity or object.
- The resolved `context` SHOULD be a Collection or a subtype. This Collection SHOULD contain the related items.
- The `context` MAY require authorization to resolve properly or fully, but SHOULD include an `attributedTo` property at minimum.
When encountering an object with a `context`:
- You MAY copy the `context` as-is, if you wish for your object to be included in the same context.
- You MAY set your own `context`, if you wish for your object to be in a separate context owned by you.
- You MAY remove the `context` entirely, if you wish for your object to exist on its own.
In cases where you copy a context owned by someone else, you SHOULD send your activity to the owner of that context, defined via `context.attributedTo` if resolvable. You SHOULD NOT send your activity to anyone else, unless you implement a mechanism to allow third-party observers to verify that your object or activity is indeed a valid member of the referenced context. (A further FEP may follow up on this topic.)
Upon receipt of such an activity referencing a context owned by you, you SHOULD distribute the object to the audience of the context, specified by `context.audience`, and possibly including `context.followers` if the context is itself an actor. This may be done with inbox forwarding or by delivering an Add activity. An Announce activity SHOULD NOT be used, as this would be interpreted as a reshare. (Verification mechanisms for inbox forwarding or Adding private objects is out-of-scope for this FEP.) You MAY drop certain activities not matching specific policies; for example, you might filter out spam, or implement a policy such that only certain actors (members, participants, etc.) are allowed to be included in the context. (Signaling which actors can participate is out-of-scope for this FEP and may be covered in a further FEP.)
In cases where you copy an unresolvable context, or a context without an owner, you may deliver to an arbitrary audience as if there were no context. However, this is not recommended. Actors that receive such an activity or object with an unverifiable context SHOULD ignore this context, and SHOULD NOT associate the object with the declared context.
### c2s
The following algorithm may be used to create an object within a context collection:
1. Create the `Collection` representing the context. Save the generated Collection `id` to be used in the next step.
2. Create the `Object` and specify the `context` as the `id` obtained in step 1. Set an appropriate `audience` or use `to`/`cc` to deliver the Create activity as-is. Save the returned Object or its `id` to be used in the next step.
3. Add the `Object` to the context `Collection`, using the response from step 2. You may wish to deliver this Add activity `to`/`cc` your intended recipients, especially if you did not deliver the Create Object from step 2.
## future directions: contexts as actors that can be followed and addressed

View file

@ -0,0 +1,19 @@
+++
+++
Follows are realistically transient. it is therefore enough to:
- keep track of local state
- mutate state based on activities
if you receive an Accept/Reject Follow, check ONLY for the following:
- actor
- type == Accept/Reject
- object.actor
- object.type == Follow
- object.object == actor
if object is inlined, you don't need to check that object.id is local. the above is enough information, PROVIDED THAT you have a local pending follow request. if you do not have a pending follow, then DO NOT process an incoming Accept Follow. however, you may receive a Reject Follow at any time, indicating that you should destroy that follow relationship. note that you may also receive an Undo Accept Follow by some implementations. this is discouraged but should be handled as well
<https://github.com/misskey-dev/misskey/issues/9250>

View file

@ -0,0 +1,3 @@
+++
+++

View file

@ -87,7 +87,7 @@ DNS authority means you can assign names underneath a given domain name... this
URN authority means you can assign names underneath a given URN namespace... this authority derives from some agreement with standards bodies.
therefore, it can be said that the real difference between DNS and URN is that the former grants authority based on technical registration, while the latter grants authority based on social registration. in other words a URN can be used even without the internet. consequently, **URNs can be handed out freely and in a decentralized manner**.
therefore, it can be said that the real difference between DNS and URN is that the former grants authority based on technical registration, while the latter grants authority based on social registration. in other words a URN can be used even without the internet. consequently, **URNs can be handed out freely and in a decentralized manner**, and the problem you have to solve is consensus between authorities.
## see also

View file

@ -28,6 +28,7 @@
<body>
{{ partial "site-header.html" . }}
{{ partial "breadcrumbs.html" . }}
<div class="container">{{ partial "lastmod.html" . }}</div>
{{ block "main" . }}
{{ end }}
{{ partial "site-footer.html" . }}

View file

@ -0,0 +1,3 @@
{{ if eq .Kind "page" }}
<p class="lastmod">Last modified <datetime class="date">{{ or .Page.Params.updated (.Lastmod.UTC.Format "Mon Jan 2, 2006 at 15:04 MST") }}</datetime><!--span class="edit-link"><br><a href='{{if eq .Site.Params.forge "github"}}{{printf "https://github.com/%s/edit/%s/%s/%s" .Site.Params.repo .Site.Params.branch .Site.Language.ContentDir .File.Path}}{{else if eq .Site.Params.forge "gitea"}}{{printf "%s/%s/_edit/%s/%s/%s" .Site.Params.forgeUrl .Site.Params.repo .Site.Params.branch (cond (isset .Site.Language "ContentDir") .Site.Language.ContentDir "content") .File.Path}}{{else}}#{{end}}'>Edit this page</a></span--></p>
{{ end }}

View file

@ -1,9 +1,7 @@
<footer class="site-footer">
<hr>
<div class="container">
{{ if eq .Kind "page" }}
<p class="lastmod">Last modified <datetime class="date">{{ or .Page.Params.updated (.Lastmod.UTC.Format "Mon Jan 2, 2006 at 15:04 MST") }}</datetime><!--span class="edit-link"><br><a href='{{if eq .Site.Params.forge "github"}}{{printf "https://github.com/%s/edit/%s/%s/%s" .Site.Params.repo .Site.Params.branch .Site.Language.ContentDir .File.Path}}{{else if eq .Site.Params.forge "gitea"}}{{printf "%s/%s/_edit/%s/%s/%s" .Site.Params.forgeUrl .Site.Params.repo .Site.Params.branch (cond (isset .Site.Language "ContentDir") .Site.Language.ContentDir "content") .File.Path}}{{else}}#{{end}}'>Edit this page</a></span--></p>
{{ end }}
{{ partial "lastmod.html" . }}
</div>
</footer>