WIP: Manual ActivityPub inbox outbox implementation #4
@ -24,7 +24,7 @@ import (
|
||||
const (
|
||||
// ActivityStreamsContentType const
|
||||
ActivityStreamsContentType = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
|
||||
httpsigExpirationTime = 60
|
||||
httpsigExpirationTime = 60
|
||||
)
|
||||
|
||||
func containsRequiredHTTPHeaders(method string, headers []string) error {
|
||||
|
23
modules/activitypub/database.go
Normal file
23
modules/activitypub/database.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
)
|
||||
|
||||
func databaseAddToInbox(activity vocab.ActivityStreamsActivity) {
|
||||
}
|
||||
|
||||
func databaseAddToOutbox(activity vocab.ActivityStreamsActivity) {
|
||||
}
|
||||
|
||||
func GetInbox(user user_model.User) {
|
||||
}
|
||||
|
||||
func GetOutbox(user user_model.User) {
|
||||
}
|
38
modules/activitypub/fetch.go
Normal file
38
modules/activitypub/fetch.go
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
)
|
||||
|
||||
func Fetch(iri *url.URL) (b []byte, err error) {
|
||||
req := httplib.NewRequest(iri.String(), http.MethodGet)
|
||||
req.Header("Accept", ActivityStreamsContentType)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
clock, err := NewClock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header("Date", fmt.Sprintf("%s GMT", clock.Now().UTC().Format(time.RFC1123)))
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
|
||||
return
|
||||
}
|
||||
b, err = io.ReadAll(resp.Body)
|
||||
return
|
||||
}
|
12
modules/activitypub/follow.go
Normal file
12
modules/activitypub/follow.go
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
)
|
||||
|
||||
func follow(activity vocab.ActivityStreamsActivity) {
|
||||
}
|
19
modules/activitypub/inbox.go
Normal file
19
modules/activitypub/inbox.go
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
)
|
||||
|
||||
// Add an activity to a user's inbox
|
||||
func AddToInbox(activity vocab.ActivityStreamsActivity) {
|
||||
databaseAddToInbox(activity)
|
||||
|
||||
// Probably should use callbacks here
|
||||
if activity.GetJSONLDType().Name() == "Follow" {
|
||||
follow(activity)
|
||||
}
|
||||
}
|
46
modules/activitypub/outbox.go
Normal file
46
modules/activitypub/outbox.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
)
|
||||
|
||||
// Add an activity to a user's outbox
|
||||
func AddToOutbox(activity vocab.ActivityStreamsActivity) {
|
||||
databaseAddToOutbox(activity)
|
||||
|
||||
actorIRI := activity.GetActivityStreamsActor().Begin().GetIRI()
|
||||
|
||||
s := strings.Split(actorIRI.String(), ",")
|
||||
user, _ := user_model.GetUserByName(s[len(s)-1])
|
||||
|
||||
to := activity.GetActivityStreamsTo().Begin().GetIRI()
|
||||
fetched, _ := Fetch(to)
|
||||
var m map[string]interface{}
|
||||
json.Unmarshal(fetched, &m)
|
||||
|
||||
var person vocab.ActivityStreamsPerson
|
||||
resolver, _ := streams.NewJSONResolver(func(c context.Context, p vocab.ActivityStreamsPerson) error {
|
||||
person = p
|
||||
return nil
|
||||
})
|
||||
ctx := context.Background()
|
||||
_ = resolver.Resolve(ctx, m)
|
||||
inboxIRI := person.GetActivityStreamsInbox().GetIRI().String()
|
||||
|
||||
client, _ := NewClient(user, actorIRI.String()+"#main-key")
|
||||
|
||||
jsonmap, _ := streams.Serialize(activity)
|
||||
body, _ := json.Marshal(jsonmap)
|
||||
client.Post(body, inboxIRI)
|
||||
}
|
@ -10,14 +10,11 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/activitypub"
|
||||
gitea_context "code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
@ -88,29 +85,6 @@ func getPublicKeyFromResponse(ctx context.Context, b []byte, keyID *url.URL) (p
|
||||
return
|
||||
}
|
||||
|
||||
func fetch(iri *url.URL) (b []byte, err error) {
|
||||
req := httplib.NewRequest(iri.String(), http.MethodGet)
|
||||
req.Header("Accept", activitypub.ActivityStreamsContentType)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
clock, err := activitypub.NewClock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header("Date", fmt.Sprintf("%s GMT", clock.Now().UTC().Format(time.RFC1123)))
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
|
||||
return
|
||||
}
|
||||
b, err = io.ReadAll(resp.Body)
|
||||
return
|
||||
}
|
||||
|
||||
func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, err error) {
|
||||
r := ctx.Req
|
||||
|
||||
@ -125,7 +99,7 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er
|
||||
return
|
||||
}
|
||||
// 2. Fetch the public key of the other actor
|
||||
b, err := fetch(idIRI)
|
||||
b, err := activitypub.Fetch(idIRI)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user