gotosocial/vendor/code.superseriousbusiness.org/activity/streams
tobi dcfc9b7885 [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315)
This pull request implements two new properties on ActivityPub actors: `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb`.

As documented, these properties allow actors to signal their preference for whether or not their posts should be hidden from unauthenticated web views (ie., web pages like the GtS frontend, web apps like the Mastodon frontend, web APIs like the Mastodon public timeline API, etc). This allows remote accounts to *opt in* to having their unlisted visibility posts shown in (for example) the replies section of the web view of a GtS thread. In future, we can also use these properties to determine whether we should show boosts of a remote actor's post on a GtS profile, and that sort of thing.

In keeping with our stance around privacy by default, GtS assumes `true` for `hidesCcPublicFromUnauthedWeb` if the property is not set on a remote actor, ie., hide unlisted/unlocked posts by default. `hidesToPublicFromUnauthedWeb` is assumed to be `false` if the property is not set on a remote actor, ie., show public posts by default.

~~WIP as I still want to work on the documentation for this a bit.~~

New props are already in the namespace document: https://gotosocial.org/ns

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4315
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-07-09 16:50:25 +02:00
..
impl [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
values [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
vocab [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_consts.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_doc.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_init.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_json_resolver.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_manager.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_activitystreams_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_activitystreams_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_activitystreams_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_activitystreams_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_activitystreams_property_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_activitystreams_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_funkwhale_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_funkwhale_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_funkwhale_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_funkwhale_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_funkwhale_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_gotosocial_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_gotosocial_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_gotosocial_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_gotosocial_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_gotosocial_property_constructors.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_gotosocial_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_jsonld_property_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_litepub_disjoint.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_litepub_extendedby.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_litepub_extends.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_litepub_isorextends.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_litepub_type_constructors.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_pkg_schema_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_schema_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_schema_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_schema_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_schema_property_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_schema_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_property_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_toot_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_disjoint.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_extendedby.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_extends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_isorextends.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_property_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_pkg_w3idsecurityv1_type_constructors.go [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
gen_resolver_utils.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_type_predicated_resolver.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
gen_type_resolver.go [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315) 2025-07-09 16:50:25 +02:00
README.md [chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
util.go [bugfix] Remove errant alsoKnownAs inline @context entry (#4280) 2025-06-18 13:39:09 +02:00

streams

ActivityStreams vocabularies automatically code-generated with astool.

Reference & Tutorial

The go-fed website contains tutorials and reference materials, in addition to the rest of this README.

How To Use

go get github.com/go-fed/activity

All generated types and properties are interfaces in github.com/go-fed/streams/vocab, but note that the constructors and supporting functions live in github.com/go-fed/streams.

To create a type and set properties:

var actorURL *url.URL = // ...

// A new "Create" Activity.
create := streams.NewActivityStreamsCreate()
// A new "actor" property.
actor := streams.NewActivityStreamsActorProperty()
actor.AppendIRI(actorURL)
// Set the "actor" property on the "Create" Activity.
create.SetActivityStreamsActor(actor)

To process properties on a type:

// Returns true if the "Update" has at least one "object" with an IRI value.
func hasObjectWithIRIValue(update vocab.ActivityStreamsUpdate) bool {
  objectProperty := update.GetActivityStreamsObject()
  // Any property may be nil if it was either empty in the original JSON or
  // never set on the golang type.
  if objectProperty == nil {
    return false
  }
  // The "object" property is non-functional: it could have multiple values. The
  // generated code has slightly different methods for a functional property
  // versus a non-functional one.
  //
  // While it may be easy to ignore multiple values in other languages
  // (accidentally or purposefully), go-fed is designed to make it hard to do
  // so.
  for iter := objectProperty.Begin(); iter != objectProperty.End(); iter = iter.Next() {
    // If this particular value is an IRI, return true.
    if iter.IsIRI() {
      return true
    }
  }
  // All values are literal embedded values and not IRIs.
  return false
}

The ActivityStreams type hierarchy of "extends" and "disjoint" is not the same as the Object Oriented definition of inheritance. It is also not the same as golang's interface duck-typing. Helper functions are provided to guarantee that an application's logic can correctly apply the type hierarchy.

thing := // Pick a type from streams.NewActivityStreams<Type>()
if streams.ActivityStreamsObjectIsDisjointWith(thing) {
  fmt.Printf("The \"Object\" type is Disjoint with the %T type.\n", thing)
}
if streams.ActivityStreamsLinkIsExtendedBy(thing) {
  fmt.Printf("The %T type Extends from the \"Link\" type.\n", thing)
}
if streams.ActivityStreamsActivityExtends(thing) {
  fmt.Printf("The \"Activity\" type extends from the %T type.\n", thing)
}

When given a generic JSON payload, it can be resolved to a concrete type by creating a streams.JSONResolver and giving it a callback function that accepts the interesting concrete type:

// Callbacks must be in the form:
//   func(context.Context, <TypeInterface>) error
createCallback := func(c context.Context, create vocab.ActivityStreamsCreate) error {
  // Do something with 'create'
  fmt.Printf("createCallback called: %T\n", create)
  return nil
}
updateCallback := func(c context.Context, update vocab.ActivityStreamsUpdate) error {
  // Do something with 'update'
  fmt.Printf("updateCallback called: %T\n", update)
  return nil
}
jsonResolver, err := streams.NewJSONResolver(createCallback, updateCallback)
if err != nil {
  // Something in the setup was wrong. For example, a callback has an
  // unsupported signature and would never be called
  panic(err)
}
// Create a context, which allows you to pass data opaquely through the
// JSONResolver.
c := context.Background()
// Example 15 of the ActivityStreams specification.
b := []byte(`{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "Sally created a note",
  "type": "Create",
  "actor": {
    "type": "Person",
    "name": "Sally"
  },
  "object": {
    "type": "Note",
    "name": "A Simple Note",
    "content": "This is a simple note"
  }
}`)
var jsonMap map[string]interface{}
if err = json.Unmarshal(b, &jsonMap); err != nil {
  panic(err)
}
// The createCallback function will be called.
err = jsonResolver.Resolve(c, jsonMap)
if err != nil && !streams.IsUnmatchedErr(err) {
  // Something went wrong
  panic(err)
} else if streams.IsUnmatchedErr(err) {
  // Everything went right but the callback didn't match or the ActivityStreams
  // type is one that wasn't code generated.
  fmt.Println("No match: ", err)
}

A streams.TypeResolver is similar but uses the golang types instead. It accepts the generic vocab.Type. This is the abstraction when needing to handle any ActivityStreams type. The function ToType can convert a JSON-decoded-map into this kind of value if needed.

A streams.PredicatedTypeResolver lets you apply a boolean predicate function that acts as a check whether a callback is allowed to be invoked.

FAQ

Why Are Empty Properties Nil And Not Zero-Valued?

Due to implementation design decisions, it would require a lot of plumbing to ensure this would work properly. It would also require allocation of a non-trivial amount of memory.