[chore] Serve main-key as bare key, not stub actor

This commit is contained in:
tobi 2024-03-02 13:18:20 +01:00
parent 9032891eef
commit 52f96bf621
4 changed files with 40 additions and 47 deletions

View file

@ -77,6 +77,9 @@ const (
// See https://www.w3.org/TR/activitystreams-vocabulary/#microsyntaxes // See https://www.w3.org/TR/activitystreams-vocabulary/#microsyntaxes
// and https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag // and https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag
TagHashtag = "Hashtag" TagHashtag = "Hashtag"
// PublicKey is the internal type name of a Public Key.
PublicKey = "PublicKey"
) )
// isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity). // isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity).

View file

@ -50,12 +50,31 @@ func Serialize(t vocab.Type) (m map[string]interface{}, e error) {
return serializeStatusable(t, true) return serializeStatusable(t, true)
case IsActivityable(tn): case IsActivityable(tn):
return serializeActivityable(t, true) return serializeActivityable(t, true)
case tn == PublicKey:
return serializePubkey(t)
default: default:
// No custom serializer necessary. // No custom serializer necessary.
return streams.Serialize(t) return streams.Serialize(t)
} }
} }
// serializePubkey is a custom serializer for a bare PublicKey type.
// Unlike the standard streams.Serialize function, it includes the
// ActivityStreams JSON-LD namespace in the @context entry.
func serializePubkey(t vocab.Type) (map[string]interface{}, error) {
data, err := streams.Serialize(t)
if err != nil {
return nil, err
}
data["@context"] = []string{
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
}
return data, nil
}
// serializeWithOrderedItems is a custom serializer // serializeWithOrderedItems is a custom serializer
// for any type that has an `orderedItems` property. // for any type that has an `orderedItems` property.
// Unlike the standard streams.Serialize function, // Unlike the standard streams.Serialize function,

View file

@ -48,22 +48,19 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque
} }
if uris.IsPublicKeyPath(requestURL) { if uris.IsPublicKeyPath(requestURL) {
// If request is on a public key path, we don't need to // If request is on the public key path, we don't need to
// authenticate this request. However, we'll only serve // authenticate this request. Just serve the public key.
// the bare minimum user profile needed for the pubkey. pubKey, err := p.converter.AccountToASPubKey(ctx, receiver)
//
// TODO: https://github.com/superseriousbusiness/gotosocial/issues/1186
minimalPerson, err := p.converter.AccountToASMinimal(ctx, receiver)
if err != nil { if err != nil {
err := gtserror.Newf("error converting to minimal account: %w", err) err := gtserror.Newf("error converting to pubKey: %w", err)
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)
} }
// Return early with bare minimum data. // Return early with bare minimum data.
return data(minimalPerson) return data(pubKey)
} }
// If the request is not on a public key path, we want to // If the request is not on the public key path, we want to
// try to authenticate it before we serve any data, so that // try to authenticate it before we serve any data, so that
// we can serve a more complete profile. // we can serve a more complete profile.
pubKeyAuth, errWithCode := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername) pubKeyAuth, errWithCode := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername)
@ -110,8 +107,8 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque
return data(person) return data(person)
} }
func data(requestedPerson vocab.ActivityStreamsPerson) (interface{}, gtserror.WithCode) { func data(t vocab.Type) (interface{}, gtserror.WithCode) {
data, err := ap.Serialize(requestedPerson) data, err := ap.Serialize(t)
if err != nil { if err != nil {
err := gtserror.Newf("error serializing person: %w", err) err := gtserror.Newf("error serializing person: %w", err)
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)

View file

@ -360,34 +360,8 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
return person, nil return person, nil
} }
// AccountToASMinimal converts a gts model account into an activity streams person, suitable for federation. // AccountToASPubKey returns the PublicKey representation for the given Account.
// func (c *Converter) AccountToASPubKey(ctx context.Context, a *gtsmodel.Account) (vocab.W3IDSecurityV1PublicKey, error) {
// The returned account will just have the Type, Username, PublicKey, and ID properties set. This is
// suitable for serving to requesters to whom we want to give as little information as possible because
// we don't trust them (yet).
func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account) (vocab.ActivityStreamsPerson, error) {
person := streams.NewActivityStreamsPerson()
// id should be the activitypub URI of this user
// something like https://example.org/users/example_user
profileIDURI, err := url.Parse(a.URI)
if err != nil {
return nil, err
}
idProp := streams.NewJSONLDIdProperty()
idProp.SetIRI(profileIDURI)
person.SetJSONLDId(idProp)
// preferredUsername
// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI.
preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty()
preferredUsernameProp.SetXMLSchemaString(a.Username)
person.SetActivityStreamsPreferredUsername(preferredUsernameProp)
// publicKey
// Required for signatures.
publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty()
// create the public key // create the public key
publicKey := streams.NewW3IDSecurityV1PublicKey() publicKey := streams.NewW3IDSecurityV1PublicKey()
@ -401,8 +375,14 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account)
publicKey.SetJSONLDId(publicKeyIDProp) publicKey.SetJSONLDId(publicKeyIDProp)
// set owner for the public key // set owner for the public key
// owner id should be the activitypub URI of this user
// something like https://example.org/users/example_user
ownerURI, err := url.Parse(a.URI)
if err != nil {
return nil, err
}
publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty() publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty()
publicKeyOwnerProp.SetIRI(profileIDURI) publicKeyOwnerProp.SetIRI(ownerURI)
publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp) publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp)
// set the pem key itself // set the pem key itself
@ -418,13 +398,7 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account)
publicKeyPEMProp.Set(string(publicKeyBytes)) publicKeyPEMProp.Set(string(publicKeyBytes))
publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp) publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp)
// append the public key to the public key property return publicKey, nil
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey)
// set the public key property on the Person
person.SetW3IDSecurityV1PublicKey(publicKeyProp)
return person, nil
} }
// StatusToAS converts a gts model status into an ActivityStreams Statusable implementation, suitable for federation // StatusToAS converts a gts model status into an ActivityStreams Statusable implementation, suitable for federation