mirror of
1
Fork 0

Merge pull request 'tests: improve actvititypub integration test code' (#5771) from gusted/forgejo-activity-integration-test into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5771
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
Earl Warren 2024-11-01 22:29:47 +00:00
commit 1bb0e4fbd1
34 changed files with 154 additions and 194 deletions

View File

@ -10,6 +10,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -12,6 +12,7 @@ import (
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/auth" _ "code.gitea.io/gitea/models/auth"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/perm/access" _ "code.gitea.io/gitea/models/perm/access"
) )

View File

@ -0,0 +1 @@
[] # empty

View File

@ -0,0 +1 @@
[] # empty

View File

@ -10,6 +10,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -13,6 +13,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/system" _ "code.gitea.io/gitea/models/system"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/organization" _ "code.gitea.io/gitea/models/organization"
_ "code.gitea.io/gitea/models/repo" _ "code.gitea.io/gitea/models/repo"
_ "code.gitea.io/gitea/models/user" _ "code.gitea.io/gitea/models/user"

View File

@ -19,6 +19,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -16,6 +16,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/repo" _ "code.gitea.io/gitea/models/repo"
_ "code.gitea.io/gitea/models/user" _ "code.gitea.io/gitea/models/user"
) )

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" // register table model _ "code.gitea.io/gitea/models" // register table model
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/perm/access" // register table model _ "code.gitea.io/gitea/models/perm/access" // register table model
_ "code.gitea.io/gitea/models/repo" // register table model _ "code.gitea.io/gitea/models/repo" // register table model
_ "code.gitea.io/gitea/models/user" // register table model _ "code.gitea.io/gitea/models/user" // register table model

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" // register models _ "code.gitea.io/gitea/models" // register models
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/system" // register models of system _ "code.gitea.io/gitea/models/system" // register models of system
) )

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -18,6 +18,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -17,6 +17,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -17,6 +17,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/issues" _ "code.gitea.io/gitea/models/issues"
) )

View File

@ -10,6 +10,7 @@ import (
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -10,6 +10,7 @@ import (
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -14,6 +14,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -14,6 +14,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@ -10,6 +10,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -11,6 +11,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/services/attachment" "code.gitea.io/gitea/services/attachment"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/contexttest"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -13,6 +13,7 @@ import (
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@ -12,6 +12,7 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View File

@ -5,12 +5,12 @@ package integration
import ( import (
"net/http" "net/http"
"net/url"
"testing" "testing"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests"
ap "github.com/go-ap/activitypub" ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -20,31 +20,29 @@ import (
func TestActivityPubActor(t *testing.T) { func TestActivityPubActor(t *testing.T) {
defer test.MockVariableValue(&setting.Federation.Enabled, true)() defer test.MockVariableValue(&setting.Federation.Enabled, true)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer tests.PrepareTestEnv(t)()
onGiteaRun(t, func(*testing.T, *url.URL) { req := NewRequest(t, "GET", "/api/v1/activitypub/actor")
req := NewRequest(t, "GET", "/api/v1/activitypub/actor") resp := MakeRequest(t, req, http.StatusOK)
resp := MakeRequest(t, req, http.StatusOK) assert.Contains(t, resp.Body.String(), "@context")
body := resp.Body.Bytes()
assert.Contains(t, string(body), "@context")
var actor ap.Actor var actor ap.Actor
err := actor.UnmarshalJSON(body) err := actor.UnmarshalJSON(resp.Body.Bytes())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, ap.ApplicationType, actor.Type) assert.Equal(t, ap.ApplicationType, actor.Type)
assert.Equal(t, setting.Domain, actor.PreferredUsername.String()) assert.Equal(t, setting.Domain, actor.PreferredUsername.String())
keyID := actor.GetID().String() keyID := actor.GetID().String()
assert.Regexp(t, "activitypub/actor$", keyID) assert.Regexp(t, "activitypub/actor$", keyID)
assert.Regexp(t, "activitypub/actor/outbox$", actor.Outbox.GetID().String()) assert.Regexp(t, "activitypub/actor/outbox$", actor.Outbox.GetID().String())
assert.Regexp(t, "activitypub/actor/inbox$", actor.Inbox.GetID().String()) assert.Regexp(t, "activitypub/actor/inbox$", actor.Inbox.GetID().String())
pubKey := actor.PublicKey pubKey := actor.PublicKey
assert.NotNil(t, pubKey) assert.NotNil(t, pubKey)
publicKeyID := keyID + "#main-key" publicKeyID := keyID + "#main-key"
assert.Equal(t, pubKey.ID.String(), publicKeyID) assert.Equal(t, pubKey.ID.String(), publicKeyID)
pubKeyPem := pubKey.PublicKeyPem pubKeyPem := pubKey.PublicKeyPem
assert.NotNil(t, pubKeyPem) assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem) assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
} }

View File

@ -4,18 +4,19 @@
package integration package integration
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"net/http/httptest"
"net/url" "net/url"
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests"
ap "github.com/go-ap/activitypub" ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -23,86 +24,61 @@ import (
) )
func TestActivityPubPerson(t *testing.T) { func TestActivityPubPerson(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() { defer tests.PrepareTestEnv(t)()
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) { userID := 2
userID := 2 username := "user2"
username := "user2" req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID))
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID)) resp := MakeRequest(t, req, http.StatusOK)
resp := MakeRequest(t, req, http.StatusOK) assert.Contains(t, resp.Body.String(), "@context")
body := resp.Body.Bytes()
assert.Contains(t, string(body), "@context")
var person ap.Person var person ap.Person
err := person.UnmarshalJSON(body) err := person.UnmarshalJSON(resp.Body.Bytes())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, ap.PersonType, person.Type) assert.Equal(t, ap.PersonType, person.Type)
assert.Equal(t, username, person.PreferredUsername.String()) assert.Equal(t, username, person.PreferredUsername.String())
keyID := person.GetID().String() keyID := person.GetID().String()
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v$", userID), keyID) assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v$", userID), keyID)
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/outbox$", userID), person.Outbox.GetID().String()) assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/outbox$", userID), person.Outbox.GetID().String())
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/inbox$", userID), person.Inbox.GetID().String()) assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/inbox$", userID), person.Inbox.GetID().String())
pubKey := person.PublicKey pubKey := person.PublicKey
assert.NotNil(t, pubKey) assert.NotNil(t, pubKey)
publicKeyID := keyID + "#main-key" publicKeyID := keyID + "#main-key"
assert.Equal(t, pubKey.ID.String(), publicKeyID) assert.Equal(t, pubKey.ID.String(), publicKeyID)
pubKeyPem := pubKey.PublicKeyPem pubKeyPem := pubKey.PublicKeyPem
assert.NotNil(t, pubKeyPem) assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem) assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
} }
func TestActivityPubMissingPerson(t *testing.T) { func TestActivityPubMissingPerson(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() { defer tests.PrepareTestEnv(t)()
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) { req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999")
req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999") resp := MakeRequest(t, req, http.StatusNotFound)
resp := MakeRequest(t, req, http.StatusNotFound) assert.Contains(t, resp.Body.String(), "user does not exist")
assert.Contains(t, resp.Body.String(), "user does not exist")
})
} }
func TestActivityPubPersonInbox(t *testing.T) { func TestActivityPubPersonInbox(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
srv := httptest.NewServer(testWebRoutes) onGiteaRun(t, func(t *testing.T, u *url.URL) {
defer srv.Close() defer test.MockVariableValue(&setting.AppURL, u.String())()
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
onGiteaRun(t, func(*testing.T, *url.URL) { user1url := u.JoinPath("/api/v1/activitypub/user-id/1").String() + "#main-key"
appURL := setting.AppURL cf, err := activitypub.GetClientFactory(db.DefaultContext)
setting.AppURL = srv.URL + "/"
defer func() {
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
username1 := "user1"
ctx := context.Background()
user1, err := user_model.GetUserByName(ctx, username1)
require.NoError(t, err)
user1url := fmt.Sprintf("%s/api/v1/activitypub/user-id/1#main-key", srv.URL)
cf, err := activitypub.GetClientFactory(ctx)
require.NoError(t, err) require.NoError(t, err)
c, err := cf.WithKeys(db.DefaultContext, user1, user1url) c, err := cf.WithKeys(db.DefaultContext, user1, user1url)
require.NoError(t, err) require.NoError(t, err)
user2inboxurl := fmt.Sprintf("%s/api/v1/activitypub/user-id/2/inbox", srv.URL) user2inboxurl := u.JoinPath("/api/v1/activitypub/user-id/2/inbox").String()
// Signed request succeeds // Signed request succeeds
resp, err := c.Post([]byte{}, user2inboxurl) resp, err := c.Post([]byte{}, user2inboxurl)

View File

@ -18,111 +18,90 @@ import (
"code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/activitypub"
forgefed_modules "code.gitea.io/gitea/modules/forgefed" forgefed_modules "code.gitea.io/gitea/modules/forgefed"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestActivityPubRepository(t *testing.T) { func TestActivityPubRepository(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() { defer tests.PrepareTestEnv(t)()
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) { repositoryID := 2
repositoryID := 2 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/repository-id/%v", repositoryID))
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/repository-id/%v", repositoryID)) resp := MakeRequest(t, req, http.StatusOK)
resp := MakeRequest(t, req, http.StatusOK) assert.Contains(t, resp.Body.String(), "@context")
body := resp.Body.Bytes()
assert.Contains(t, string(body), "@context")
var repository forgefed_modules.Repository var repository forgefed_modules.Repository
err := repository.UnmarshalJSON(body) err := repository.UnmarshalJSON(resp.Body.Bytes())
require.NoError(t, err) require.NoError(t, err)
assert.Regexp(t, fmt.Sprintf("activitypub/repository-id/%v$", repositoryID), repository.GetID().String()) assert.Regexp(t, fmt.Sprintf("activitypub/repository-id/%v$", repositoryID), repository.GetID().String())
})
} }
func TestActivityPubMissingRepository(t *testing.T) { func TestActivityPubMissingRepository(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() { defer tests.PrepareTestEnv(t)()
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) { repositoryID := 9999999
repositoryID := 9999999 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/repository-id/%v", repositoryID))
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/repository-id/%v", repositoryID)) resp := MakeRequest(t, req, http.StatusNotFound)
resp := MakeRequest(t, req, http.StatusNotFound) assert.Contains(t, resp.Body.String(), "repository does not exist")
assert.Contains(t, resp.Body.String(), "repository does not exist")
})
} }
func TestActivityPubRepositoryInboxValid(t *testing.T) { func TestActivityPubRepositoryInboxValid(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
srv := httptest.NewServer(testWebRoutes)
defer srv.Close()
federatedRoutes := http.NewServeMux() federatedRoutes := http.NewServeMux()
federatedRoutes.HandleFunc("/.well-known/nodeinfo", federatedRoutes.HandleFunc("/.well-known/nodeinfo",
func(res http.ResponseWriter, req *http.Request) { func(res http.ResponseWriter, req *http.Request) {
// curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/.well-known/nodeinfo // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/.well-known/nodeinfo
responseBody := fmt.Sprintf(`{"links":[{"href":"http://%s/api/v1/nodeinfo","rel":"http://nodeinfo.diaspora.software/ns/schema/2.1"}]}`, req.Host)
t.Logf("response: %s", responseBody)
// TODO: as soon as content-type will become important: content-type: application/json;charset=utf-8 // TODO: as soon as content-type will become important: content-type: application/json;charset=utf-8
fmt.Fprint(res, responseBody) fmt.Fprintf(res, `{"links":[{"href":"http://%s/api/v1/nodeinfo","rel":"http://nodeinfo.diaspora.software/ns/schema/2.1"}]}`, req.Host)
}) })
federatedRoutes.HandleFunc("/api/v1/nodeinfo", federatedRoutes.HandleFunc("/api/v1/nodeinfo",
func(res http.ResponseWriter, req *http.Request) { func(res http.ResponseWriter, req *http.Request) {
// curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/nodeinfo // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/nodeinfo
responseBody := fmt.Sprintf(`{"version":"2.1","software":{"name":"forgejo","version":"1.20.0+dev-3183-g976d79044",` + fmt.Fprint(res, `{"version":"2.1","software":{"name":"forgejo","version":"1.20.0+dev-3183-g976d79044",`+
`"repository":"https://codeberg.org/forgejo/forgejo.git","homepage":"https://forgejo.org/"},` + `"repository":"https://codeberg.org/forgejo/forgejo.git","homepage":"https://forgejo.org/"},`+
`"protocols":["activitypub"],"services":{"inbound":[],"outbound":["rss2.0"]},` + `"protocols":["activitypub"],"services":{"inbound":[],"outbound":["rss2.0"]},`+
`"openRegistrations":true,"usage":{"users":{"total":14,"activeHalfyear":2}},"metadata":{}}`) `"openRegistrations":true,"usage":{"users":{"total":14,"activeHalfyear":2}},"metadata":{}}`)
fmt.Fprint(res, responseBody)
}) })
federatedRoutes.HandleFunc("/api/v1/activitypub/user-id/15", federatedRoutes.HandleFunc("/api/v1/activitypub/user-id/15",
func(res http.ResponseWriter, req *http.Request) { func(res http.ResponseWriter, req *http.Request) {
// curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/2 // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/2
responseBody := fmt.Sprintf(`{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],` + fmt.Fprint(res, `{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],`+
`"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15","type":"Person",` + `"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15","type":"Person",`+
`"icon":{"type":"Image","mediaType":"image/png","url":"https://federated-repo.prod.meissa.de/avatars/1bb05d9a5f6675ed0272af9ea193063c"},` + `"icon":{"type":"Image","mediaType":"image/png","url":"https://federated-repo.prod.meissa.de/avatars/1bb05d9a5f6675ed0272af9ea193063c"},`+
`"url":"https://federated-repo.prod.meissa.de/stargoose1","inbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15/inbox",` + `"url":"https://federated-repo.prod.meissa.de/stargoose1","inbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15/inbox",`+
`"outbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15/outbox","preferredUsername":"stargoose1",` + `"outbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15/outbox","preferredUsername":"stargoose1",`+
`"publicKey":{"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15#main-key","owner":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15",` + `"publicKey":{"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15#main-key","owner":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/15",`+
`"publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA18H5s7N6ItZUAh9tneII\nIuZdTTa3cZlLa/9ejWAHTkcp3WLW+/zbsumlMrWYfBy2/yTm56qasWt38iY4D6ul\n` + `"publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA18H5s7N6ItZUAh9tneII\nIuZdTTa3cZlLa/9ejWAHTkcp3WLW+/zbsumlMrWYfBy2/yTm56qasWt38iY4D6ul\n`+
`CPiwhAqX3REvVq8tM79a2CEqZn9ka6vuXoDgBg/sBf/BUWqf7orkjUXwk/U0Egjf\nk5jcurF4vqf1u+rlAHH37dvSBaDjNj6Qnj4OP12bjfaY/yvs7+jue/eNXFHjzN4E\n` + `CPiwhAqX3REvVq8tM79a2CEqZn9ka6vuXoDgBg/sBf/BUWqf7orkjUXwk/U0Egjf\nk5jcurF4vqf1u+rlAHH37dvSBaDjNj6Qnj4OP12bjfaY/yvs7+jue/eNXFHjzN4E\n`+
`T2H4B/yeKTJ4UuAwTlLaNbZJul2baLlHelJPAsxiYaziVuV5P+IGWckY6RSerRaZ\nAkc4mmGGtjAyfN9aewe+lNVfwS7ElFx546PlLgdQgjmeSwLX8FWxbPE5A/PmaXCs\n` + `T2H4B/yeKTJ4UuAwTlLaNbZJul2baLlHelJPAsxiYaziVuV5P+IGWckY6RSerRaZ\nAkc4mmGGtjAyfN9aewe+lNVfwS7ElFx546PlLgdQgjmeSwLX8FWxbPE5A/PmaXCs\n`+
`nx+nou+3dD7NluULLtdd7K+2x02trObKXCAzmi5/Dc+yKTzpFqEz+hLNCz7TImP/\ncK//NV9Q+X67J9O27baH9R9ZF4zMw8rv2Pg0WLSw1z7lLXwlgIsDapeMCsrxkVO4\n` + `nx+nou+3dD7NluULLtdd7K+2x02trObKXCAzmi5/Dc+yKTzpFqEz+hLNCz7TImP/\ncK//NV9Q+X67J9O27baH9R9ZF4zMw8rv2Pg0WLSw1z7lLXwlgIsDapeMCsrxkVO4\n`+
`LXX5AQ1xQNtlssnVoUBqBrvZsX2jUUKUocvZqMGuE4hfAgMBAAE=\n-----END PUBLIC KEY-----\n"}}`) `LXX5AQ1xQNtlssnVoUBqBrvZsX2jUUKUocvZqMGuE4hfAgMBAAE=\n-----END PUBLIC KEY-----\n"}}`)
fmt.Fprint(res, responseBody)
}) })
federatedRoutes.HandleFunc("/api/v1/activitypub/user-id/30", federatedRoutes.HandleFunc("/api/v1/activitypub/user-id/30",
func(res http.ResponseWriter, req *http.Request) { func(res http.ResponseWriter, req *http.Request) {
// curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/3 // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/3
responseBody := fmt.Sprintf(`{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],` + fmt.Fprint(res, `{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],`+
`"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30","type":"Person",` + `"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30","type":"Person",`+
`"icon":{"type":"Image","mediaType":"image/png","url":"https://federated-repo.prod.meissa.de/avatars/9c03f03d1c1f13f21976a22489326fe1"},` + `"icon":{"type":"Image","mediaType":"image/png","url":"https://federated-repo.prod.meissa.de/avatars/9c03f03d1c1f13f21976a22489326fe1"},`+
`"url":"https://federated-repo.prod.meissa.de/stargoose2","inbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30/inbox",` + `"url":"https://federated-repo.prod.meissa.de/stargoose2","inbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30/inbox",`+
`"outbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30/outbox","preferredUsername":"stargoose2",` + `"outbox":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30/outbox","preferredUsername":"stargoose2",`+
`"publicKey":{"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30#main-key","owner":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30",` + `"publicKey":{"id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30#main-key","owner":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/30",`+
`"publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyv5NytsfqpWXSrwuk8a3\n0W1zE13QJioXb/e3opgN2CfKZkdm3hb+4+mGKoU/rCqegnL9/AO0Aw+R8fCHXx44\n` + `"publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyv5NytsfqpWXSrwuk8a3\n0W1zE13QJioXb/e3opgN2CfKZkdm3hb+4+mGKoU/rCqegnL9/AO0Aw+R8fCHXx44\n`+
`iNkdVpdY8Dzq+tQ9IetPWbyVIBvSzGgvpqfS05JuVPsy8cBX9wByODjr5kq7k1/v\nY1G7E3uh0a/XJc+mZutwGC3gPgR93NSrqsvTPN4wdhCCu9uj02S8OBoKuSYaPkU+\n` + `iNkdVpdY8Dzq+tQ9IetPWbyVIBvSzGgvpqfS05JuVPsy8cBX9wByODjr5kq7k1/v\nY1G7E3uh0a/XJc+mZutwGC3gPgR93NSrqsvTPN4wdhCCu9uj02S8OBoKuSYaPkU+\n`+
`tZ4CEDpnclAOw/eNiH4x2irMvVtruEgtlTA5K2I4YJrmtGLidus47FCyc8/zEKUh\nAeiD8KWDvqsQgOhUwcQgRxAnYVCoMD9cnE+WFFRHTuQecNlmdNFs3Cr0yKcWjDde\n` + `tZ4CEDpnclAOw/eNiH4x2irMvVtruEgtlTA5K2I4YJrmtGLidus47FCyc8/zEKUh\nAeiD8KWDvqsQgOhUwcQgRxAnYVCoMD9cnE+WFFRHTuQecNlmdNFs3Cr0yKcWjDde\n`+
`trvnehW7LfPveGb0tHRHPuVAJpncTOidUR5h/7pqMyvKHzuAHWomm9rEaGUxd/7a\nL1CFjAf39+QIEgu0Anj8mIc7CTiz+DQhDz+0jBOsQ0iDXc5GeBz7X9Xv4Jp966nq\n` + `trvnehW7LfPveGb0tHRHPuVAJpncTOidUR5h/7pqMyvKHzuAHWomm9rEaGUxd/7a\nL1CFjAf39+QIEgu0Anj8mIc7CTiz+DQhDz+0jBOsQ0iDXc5GeBz7X9Xv4Jp966nq\n`+
`MUR0GQGXvfZQN9IqMO+WoUVy10Ddhns1EWGlA0x4fecnAgMBAAE=\n-----END PUBLIC KEY-----\n"}}`) `MUR0GQGXvfZQN9IqMO+WoUVy10Ddhns1EWGlA0x4fecnAgMBAAE=\n-----END PUBLIC KEY-----\n"}}`)
fmt.Fprint(res, responseBody)
}) })
federatedRoutes.HandleFunc("/", federatedRoutes.HandleFunc("/",
func(res http.ResponseWriter, req *http.Request) { func(res http.ResponseWriter, req *http.Request) {
@ -131,32 +110,24 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) {
federatedSrv := httptest.NewServer(federatedRoutes) federatedSrv := httptest.NewServer(federatedRoutes)
defer federatedSrv.Close() defer federatedSrv.Close()
onGiteaRun(t, func(*testing.T, *url.URL) { onGiteaRun(t, func(t *testing.T, u *url.URL) {
appURL := setting.AppURL
setting.AppURL = srv.URL + "/"
defer func() {
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
actionsUser := user.NewActionsUser() actionsUser := user.NewActionsUser()
repositoryID := 2 repositoryID := 2
timeNow := time.Now().UTC()
cf, err := activitypub.GetClientFactory(db.DefaultContext) cf, err := activitypub.GetClientFactory(db.DefaultContext)
require.NoError(t, err) require.NoError(t, err)
c, err := cf.WithKeys(db.DefaultContext, actionsUser, "not used") c, err := cf.WithKeys(db.DefaultContext, actionsUser, "not used")
require.NoError(t, err) require.NoError(t, err)
repoInboxURL := fmt.Sprintf( repoInboxURL := u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d/inbox", repositoryID)).String()
"%s/api/v1/activitypub/repository-id/%v/inbox",
srv.URL, repositoryID)
timeNow := time.Now().UTC()
activity1 := []byte(fmt.Sprintf( activity1 := []byte(fmt.Sprintf(
`{"type":"Like",`+ `{"type":"Like",`+
`"startTime":"%s",`+ `"startTime":"%s",`+
`"actor":"%s/api/v1/activitypub/user-id/15",`+ `"actor":"%s/api/v1/activitypub/user-id/15",`+
`"object":"%s/api/v1/activitypub/repository-id/%v"}`, `"object":"%s"}`,
timeNow.Format(time.RFC3339), timeNow.Format(time.RFC3339),
federatedSrv.URL, srv.URL, repositoryID)) federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String()))
t.Logf("activity: %s", activity1) t.Logf("activity: %s", activity1)
resp, err := c.Post(activity1, repoInboxURL) resp, err := c.Post(activity1, repoInboxURL)
@ -172,10 +143,10 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) {
`{"type":"Like",`+ `{"type":"Like",`+
`"startTime":"%s",`+ `"startTime":"%s",`+
`"actor":"%s/api/v1/activitypub/user-id/30",`+ `"actor":"%s/api/v1/activitypub/user-id/30",`+
`"object":"%s/api/v1/activitypub/repository-id/%v"}`, `"object":"%s"}`,
// Make sure this activity happens later then the one before // Make sure this activity happens later then the one before
timeNow.Add(time.Second).Format(time.RFC3339), timeNow.Add(time.Second).Format(time.RFC3339),
federatedSrv.URL, srv.URL, repositoryID)) federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", repositoryID)).String()))
t.Logf("activity: %s", activity2) t.Logf("activity: %s", activity2)
resp, err = c.Post(activity2, repoInboxURL) resp, err = c.Post(activity2, repoInboxURL)
@ -187,17 +158,15 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) {
// The same user sends another like activity // The same user sends another like activity
otherRepositoryID := 3 otherRepositoryID := 3
otherRepoInboxURL := fmt.Sprintf( otherRepoInboxURL := u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d/inbox", otherRepositoryID)).String()
"%s/api/v1/activitypub/repository-id/%v/inbox",
srv.URL, otherRepositoryID)
activity3 := []byte(fmt.Sprintf( activity3 := []byte(fmt.Sprintf(
`{"type":"Like",`+ `{"type":"Like",`+
`"startTime":"%s",`+ `"startTime":"%s",`+
`"actor":"%s/api/v1/activitypub/user-id/30",`+ `"actor":"%s/api/v1/activitypub/user-id/30",`+
`"object":"%s/api/v1/activitypub/repository-id/%v"}`, `"object":"%s"}`,
// Make sure this activity happens later then the ones before // Make sure this activity happens later then the ones before
timeNow.Add(time.Second*2).Format(time.RFC3339), timeNow.Add(time.Second*2).Format(time.RFC3339),
federatedSrv.URL, srv.URL, otherRepositoryID)) federatedSrv.URL, u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%d", otherRepositoryID)).String()))
t.Logf("activity: %s", activity3) t.Logf("activity: %s", activity3)
resp, err = c.Post(activity3, otherRepoInboxURL) resp, err = c.Post(activity3, otherRepoInboxURL)
@ -215,32 +184,18 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) {
} }
func TestActivityPubRepositoryInboxInvalid(t *testing.T) { func TestActivityPubRepositoryInboxInvalid(t *testing.T) {
setting.Federation.Enabled = true defer test.MockVariableValue(&setting.Federation.Enabled, true)()
testWebRoutes = routers.NormalRoutes() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
srv := httptest.NewServer(testWebRoutes) onGiteaRun(t, func(t *testing.T, u *url.URL) {
defer srv.Close()
onGiteaRun(t, func(*testing.T, *url.URL) {
appURL := setting.AppURL
setting.AppURL = srv.URL + "/"
defer func() {
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
actionsUser := user.NewActionsUser() actionsUser := user.NewActionsUser()
repositoryID := 2 repositoryID := 2
cf, err := activitypub.GetClientFactory(db.DefaultContext) cf, err := activitypub.GetClientFactory(db.DefaultContext)
require.NoError(t, err) require.NoError(t, err)
c, err := cf.WithKeys(db.DefaultContext, actionsUser, "not used") c, err := cf.WithKeys(db.DefaultContext, actionsUser, "not used")
require.NoError(t, err) require.NoError(t, err)
repoInboxURL := fmt.Sprintf("%s/api/v1/activitypub/repository-id/%v/inbox",
srv.URL, repositoryID)
repoInboxURL := u.JoinPath(fmt.Sprintf("/api/v1/activitypub/repository-id/%v/inbox", repositoryID)).String()
activity := []byte(`{"type":"Wrong"}`) activity := []byte(`{"type":"Wrong"}`)
resp, err := c.Post(activity, repoInboxURL) resp, err := c.Post(activity, repoInboxURL)
require.NoError(t, err) require.NoError(t, err)