aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoïc Dachary2021-10-28 17:13:24 -1000
committerAnthony Wang2022-03-18 17:34:09 -0500
commit678a56fbf81f6568ba82b6236c534ce10ab18fea (patch)
tree4c4df83362a4d6034f6cff2961619cc7604a489e
parent4951af4d994d134b63d58a61ace9a71b7fa770e0 (diff)
activitypub: add the public key to Person (#14186)
Refs: https://github.com/go-gitea/gitea/issues/14186 Signed-off-by: Loïc Dachary <loic@dachary.org>
-rw-r--r--integrations/api_activitypub_person_test.go39
-rw-r--r--routers/api/v1/activitypub/person.go58
2 files changed, 90 insertions, 7 deletions
diff --git a/integrations/api_activitypub_person_test.go b/integrations/api_activitypub_person_test.go
index 2efa82f02..e031e886d 100644
--- a/integrations/api_activitypub_person_test.go
+++ b/integrations/api_activitypub_person_test.go
@@ -13,6 +13,7 @@ import (
"testing"
"code.gitea.io/gitea/modules/setting"
+ "github.com/go-fed/activity/pub"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
@@ -22,8 +23,10 @@ import (
func TestActivityPubPerson(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
setting.Federation.Enabled = true
+ setting.Database.LogSQL = true
defer func() {
setting.Federation.Enabled = false
+ setting.Database.LogSQL = false
}()
username := "user2"
@@ -41,11 +44,41 @@ func TestActivityPubPerson(t *testing.T) {
ctx := context.Background()
err := resolver.Resolve(ctx, m)
assert.Equal(t, err, nil)
- assert.Equal(t, person.GetTypeName(), "Person")
- assert.Equal(t, person.GetActivityStreamsName().Begin().GetXMLSchemaString(), username)
- assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), person.GetJSONLDId().GetIRI().String())
+ assert.Equal(t, "Person", person.GetTypeName())
+ assert.Equal(t, username, person.GetActivityStreamsName().Begin().GetXMLSchemaString())
+ keyId := person.GetJSONLDId().GetIRI().String()
+ assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), keyId)
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.GetActivityStreamsOutbox().GetIRI().String())
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/inbox$", username), person.GetActivityStreamsInbox().GetIRI().String())
+
+ pkp := person.GetW3IDSecurityV1PublicKey()
+ publicKeyId := keyId + "/#main-key"
+ var pkpFound vocab.W3IDSecurityV1PublicKey
+ for pkpIter := pkp.Begin(); pkpIter != pkp.End(); pkpIter = pkpIter.Next() {
+ if !pkpIter.IsW3IDSecurityV1PublicKey() {
+ continue
+ }
+ pkValue := pkpIter.Get()
+ var pkId *url.URL
+ pkId, err = pub.GetId(pkValue)
+ if err != nil {
+ return
+ }
+ assert.Equal(t, pkId.String(), publicKeyId)
+ if pkId.String() != publicKeyId {
+ continue
+ }
+ pkpFound = pkValue
+ break
+ }
+ assert.NotNil(t, pkpFound)
+
+ pkPemProp := pkpFound.GetW3IDSecurityV1PublicKeyPem()
+ assert.NotNil(t, pkPemProp)
+ assert.True(t, pkPemProp.IsXMLSchemaString())
+
+ pubKeyPem := pkPemProp.Get()
+ assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
}
diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go
index ae1a8a7bb..326629f8b 100644
--- a/routers/api/v1/activitypub/person.go
+++ b/routers/api/v1/activitypub/person.go
@@ -9,12 +9,38 @@ import (
"net/url"
"strings"
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/user"
"github.com/go-fed/activity/streams"
)
+// hack waiting on https://github.com/go-gitea/gitea/pull/16834
+func GetPublicKey(user *models.User) (string, error) {
+ if settings, err := models.GetUserSetting(user.ID, []string{"activitypub_pubPem"}); err != nil {
+ return "", err
+ } else if len(settings) == 0 {
+ if priv, pub, err := activitypub.GenerateKeyPair(); err != nil {
+ return "", err
+ } else {
+ privPem := &models.UserSetting{UserID: user.ID, Name: "activitypub_privPem", Value: priv}
+ if err := models.SetUserSetting(privPem); err != nil {
+ return "", err
+ }
+ pubPem := &models.UserSetting{UserID: user.ID, Name: "activitypub_pubPem", Value: pub}
+ if err := models.SetUserSetting(pubPem); err != nil {
+ return "", err
+ }
+ return pubPem.Value, nil
+ }
+ } else {
+ return settings[0].Value, nil
+ }
+}
+
+// NodeInfo returns the NodeInfo for the Gitea instance to allow for federation
func Person(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username} information
// ---
@@ -31,15 +57,15 @@ func Person(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/ActivityPub"
- user.GetUserByParamsName(ctx, "username")
+ user := user.GetUserByParamsName(ctx, "username")
username := ctx.Params("username")
person := streams.NewActivityStreamsPerson()
id := streams.NewJSONLDIdProperty()
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
- url_object, _ := url.Parse(link)
- id.SetIRI(url_object)
+ idIRI, _ := url.Parse(link)
+ id.SetIRI(idIRI)
person.SetJSONLDId(id)
name := streams.NewActivityStreamsNameProperty()
@@ -47,7 +73,7 @@ func Person(ctx *context.APIContext) {
person.SetActivityStreamsName(name)
ibox := streams.NewActivityStreamsInboxProperty()
- url_object, _ = url.Parse(link + "/inbox")
+ url_object, _ := url.Parse(link + "/inbox")
ibox.SetIRI(url_object)
person.SetActivityStreamsInbox(ibox)
@@ -56,6 +82,30 @@ func Person(ctx *context.APIContext) {
obox.SetIRI(url_object)
person.SetActivityStreamsOutbox(obox)
+ publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty()
+
+ publicKeyType := streams.NewW3IDSecurityV1PublicKey()
+
+ pubKeyIdProp := streams.NewJSONLDIdProperty()
+ pubKeyIRI, _ := url.Parse(link + "/#main-key")
+ pubKeyIdProp.SetIRI(pubKeyIRI)
+ publicKeyType.SetJSONLDId(pubKeyIdProp)
+
+ ownerProp := streams.NewW3IDSecurityV1OwnerProperty()
+ ownerProp.SetIRI(idIRI)
+ publicKeyType.SetW3IDSecurityV1Owner(ownerProp)
+
+ publicKeyPemProp := streams.NewW3IDSecurityV1PublicKeyPemProperty()
+ if publicKeyPem, err := GetPublicKey(user); err != nil {
+ ctx.Error(http.StatusInternalServerError, "GetPublicKey", err)
+ } else {
+ publicKeyPemProp.Set(publicKeyPem)
+ }
+ publicKeyType.SetW3IDSecurityV1PublicKeyPem(publicKeyPemProp)
+
+ publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKeyType)
+ person.SetW3IDSecurityV1PublicKey(publicKeyProp)
+
var jsonmap map[string]interface{}
jsonmap, _ = streams.Serialize(person)
ctx.JSON(http.StatusOK, jsonmap)