diff --git a/models/user/activitypub.go b/models/user/activitypub.go index c4db0518e3..490615239c 100644 --- a/models/user/activitypub.go +++ b/models/user/activitypub.go @@ -10,11 +10,12 @@ import ( "forgejo.org/models/db" "forgejo.org/modules/setting" + "forgejo.org/modules/validation" ) // APActorID returns the IRI to the api endpoint of the user func (u *User) APActorID() string { - if u.ID == APActorUserID { + if u.IsAPServerActor() { return fmt.Sprintf("%sapi/v1/activitypub/actor", setting.AppURL) } @@ -35,5 +36,9 @@ func GetUserByFederatedURI(ctx context.Context, federatedURI string) (*User, err return nil, nil } + if res, err := validation.IsValid(*user); !res { + return nil, err + } + return user, nil } diff --git a/models/user/federated_user.go b/models/user/federated_user.go index dc503380ab..d32f42867d 100644 --- a/models/user/federated_user.go +++ b/models/user/federated_user.go @@ -41,6 +41,10 @@ func getFederatedUserFromDB(ctx context.Context, searchKey, searchValue any) (*F return nil, nil } + if res, err := validation.IsValid(*federatedUser); !res { + return nil, err + } + return federatedUser, nil } diff --git a/models/user/user_system.go b/models/user/user_system.go index f1585b512a..82805cc8ee 100644 --- a/models/user/user_system.go +++ b/models/user/user_system.go @@ -73,30 +73,30 @@ func (u *User) IsActions() bool { } const ( - APActorUserID = -3 - APActorUserName = "actor" - APActorEmail = "noreply@forgejo.org" + APServerActorUserID = -3 + APServerActorUserName = "actor" + APServerActorEmail = "noreply@forgejo.org" ) -func NewAPActorUser() *User { +func NewAPServerActor() *User { return &User{ - ID: APActorUserID, - Name: APActorUserName, - LowerName: APActorUserName, + ID: APServerActorUserID, + Name: APServerActorUserName, + LowerName: APServerActorUserName, IsActive: true, - Email: APActorEmail, + Email: APServerActorEmail, KeepEmailPrivate: true, - LoginName: APActorUserName, + LoginName: APServerActorUserName, Type: UserTypeIndividual, Visibility: structs.VisibleTypePublic, } } -func APActorUserAPActorID() string { +func APServerActorID() string { path, _ := url.JoinPath(setting.AppURL, "/api/v1/activitypub/actor") return path } -func (u *User) IsAPActor() bool { - return u != nil && u.ID == APActorUserID +func (u *User) IsAPServerActor() bool { + return u != nil && u.ID == APServerActorUserID } diff --git a/models/user/user_test.go b/models/user/user_test.go index 35a1081178..52ebe2e204 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -143,7 +143,7 @@ func TestAPActorID(t *testing.T) { } func TestAPActorID_APActorID(t *testing.T) { - user := user_model.User{ID: user_model.APActorUserID} + user := user_model.User{ID: user_model.APServerActorUserID} url := user.APActorID() expected := "https://try.gitea.io/api/v1/activitypub/actor" assert.Equal(t, expected, url) diff --git a/routers/api/v1/activitypub/actor.go b/routers/api/v1/activitypub/actor.go index 7568a2a7c8..e49f277842 100644 --- a/routers/api/v1/activitypub/actor.go +++ b/routers/api/v1/activitypub/actor.go @@ -28,7 +28,7 @@ func Actor(ctx *context.APIContext) { // "200": // "$ref": "#/responses/ActivityPub" - link := user_model.APActorUserAPActorID() + link := user_model.APServerActorID() actor := ap.ActorNew(ap.IRI(link), ap.ApplicationType) actor.PreferredUsername = ap.NaturalLanguageValuesNew() @@ -46,7 +46,7 @@ func Actor(ctx *context.APIContext) { actor.PublicKey.ID = ap.IRI(link + "#main-key") actor.PublicKey.Owner = ap.IRI(link) - publicKeyPem, err := activitypub.GetPublicKey(ctx, user_model.NewAPActorUser()) + publicKeyPem, err := activitypub.GetPublicKey(ctx, user_model.NewAPServerActor()) if err != nil { ctx.ServerError("GetPublicKey", err) return diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go index 85d2f348cb..5872d951cf 100644 --- a/routers/api/v1/activitypub/reqsignature.go +++ b/routers/api/v1/activitypub/reqsignature.go @@ -191,7 +191,7 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er } // Fetch missing public key - actionsUser := user.NewAPActorUser() + actionsUser := user.NewAPServerActor() clientFactory, err := activitypub.GetClientFactory(ctx) if err != nil { return false, err diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index e51d143ede..32b3490ab4 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1313,7 +1313,7 @@ func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *use } // Special user that can't have associated contributions and permissions in the repo. - if poster.IsGhost() || poster.IsActions() || poster.IsAPActor() { + if poster.IsGhost() || poster.IsActions() || poster.IsAPServerActor() { return roleDescriptor, nil } diff --git a/services/federation/federation_service.go b/services/federation/federation_service.go index 55543fcddf..b8c471bfbb 100644 --- a/services/federation/federation_service.go +++ b/services/federation/federation_service.go @@ -98,7 +98,7 @@ func ProcessLikeActivity(ctx context.Context, form any, repositoryID int64) (int } func CreateFederationHostFromAP(ctx context.Context, actorID fm.ActorID) (*forgefed.FederationHost, error) { - actionsUser := user.NewAPActorUser() + actionsUser := user.NewAPServerActor() clientFactory, err := activitypub.GetClientFactory(ctx) if err != nil { return nil, err @@ -163,7 +163,7 @@ func GetFederationHostForURI(ctx context.Context, actorURI string) (*forgefed.Fe } func CreateUserFromAP(ctx context.Context, personID fm.PersonID, federationHostID int64) (*user.User, *user.FederatedUser, error) { - actionsUser := user.NewAPActorUser() + actionsUser := user.NewAPServerActor() clientFactory, err := activitypub.GetClientFactory(ctx) if err != nil { return nil, nil, err diff --git a/tests/integration/api_activitypub_repository_test.go b/tests/integration/api_activitypub_repository_test.go index 771e60db92..fd19b4ce33 100644 --- a/tests/integration/api_activitypub_repository_test.go +++ b/tests/integration/api_activitypub_repository_test.go @@ -32,7 +32,7 @@ func TestActivityPubRepository(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { repositoryID := 2 - apServerActor := user.NewAPActorUser() + apServerActor := user.NewAPServerActor() cf, err := activitypub.GetClientFactory(db.DefaultContext) require.NoError(t, err) @@ -72,7 +72,7 @@ func TestActivityPubRepositoryInboxValid(t *testing.T) { defer federatedSrv.Close() onGiteaRun(t, func(t *testing.T, u *url.URL) { - apServerActor := user.NewAPActorUser() + apServerActor := user.NewAPServerActor() repositoryID := 2 timeNow := time.Now().UTC() @@ -151,7 +151,7 @@ func TestActivityPubRepositoryInboxInvalid(t *testing.T) { defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() onGiteaRun(t, func(t *testing.T, u *url.URL) { - apServerActor := user.NewAPActorUser() + apServerActor := user.NewAPServerActor() repositoryID := 2 cf, err := activitypub.GetClientFactory(db.DefaultContext) diff --git a/tests/integration/user_federationhost_xorm_test.go b/tests/integration/user_federationhost_xorm_test.go index d6dbc331ef..ed29a23ab7 100644 --- a/tests/integration/user_federationhost_xorm_test.go +++ b/tests/integration/user_federationhost_xorm_test.go @@ -5,107 +5,105 @@ package integration import ( "database/sql" - "net/url" "testing" "forgejo.org/models/db" "forgejo.org/models/forgefed" "forgejo.org/models/user" + "forgejo.org/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestStoreFederationHost(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - t.Run("ExplicitNull", func(t *testing.T) { - federationHost := forgefed.FederationHost{ - HostFqdn: "ExplicitNull", - // Explicit null on KeyID and PublicKey - KeyID: sql.NullString{Valid: false}, - PublicKey: sql.Null[sql.RawBytes]{Valid: false}, - } + defer tests.PrepareTestEnv(t)() + t.Run("ExplicitNull", func(t *testing.T) { + federationHost := forgefed.FederationHost{ + HostFqdn: "ExplicitNull", + // Explicit null on KeyID and PublicKey + KeyID: sql.NullString{Valid: false}, + PublicKey: sql.Null[sql.RawBytes]{Valid: false}, + } - _, err := db.GetEngine(db.DefaultContext).Insert(&federationHost) - require.NoError(t, err) + _, err := db.GetEngine(db.DefaultContext).Insert(&federationHost) + require.NoError(t, err) - dbFederationHost := new(forgefed.FederationHost) - has, err := db.GetEngine(db.DefaultContext).Where("host_fqdn=?", "ExplicitNull").Get(dbFederationHost) - require.NoError(t, err) - assert.True(t, has) + dbFederationHost := new(forgefed.FederationHost) + has, err := db.GetEngine(db.DefaultContext).Where("host_fqdn=?", "ExplicitNull").Get(dbFederationHost) + require.NoError(t, err) + assert.True(t, has) - assert.False(t, dbFederationHost.KeyID.Valid) - assert.False(t, dbFederationHost.PublicKey.Valid) - }) + assert.False(t, dbFederationHost.KeyID.Valid) + assert.False(t, dbFederationHost.PublicKey.Valid) + }) - t.Run("NotNull", func(t *testing.T) { - federationHost := forgefed.FederationHost{ - HostFqdn: "ImplicitNull", - KeyID: sql.NullString{Valid: true, String: "meow"}, - PublicKey: sql.Null[sql.RawBytes]{Valid: true, V: sql.RawBytes{0x23, 0x42}}, - } + t.Run("NotNull", func(t *testing.T) { + federationHost := forgefed.FederationHost{ + HostFqdn: "ImplicitNull", + KeyID: sql.NullString{Valid: true, String: "meow"}, + PublicKey: sql.Null[sql.RawBytes]{Valid: true, V: sql.RawBytes{0x23, 0x42}}, + } - _, err := db.GetEngine(db.DefaultContext).Insert(&federationHost) - require.NoError(t, err) + _, err := db.GetEngine(db.DefaultContext).Insert(&federationHost) + require.NoError(t, err) - dbFederationHost := new(forgefed.FederationHost) - has, err := db.GetEngine(db.DefaultContext).Where("host_fqdn=?", "ImplicitNull").Get(dbFederationHost) - require.NoError(t, err) - assert.True(t, has) + dbFederationHost := new(forgefed.FederationHost) + has, err := db.GetEngine(db.DefaultContext).Where("host_fqdn=?", "ImplicitNull").Get(dbFederationHost) + require.NoError(t, err) + assert.True(t, has) - assert.True(t, dbFederationHost.KeyID.Valid) - assert.Equal(t, "meow", dbFederationHost.KeyID.String) + assert.True(t, dbFederationHost.KeyID.Valid) + assert.Equal(t, "meow", dbFederationHost.KeyID.String) - assert.True(t, dbFederationHost.PublicKey.Valid) - assert.Equal(t, sql.RawBytes{0x23, 0x42}, dbFederationHost.PublicKey.V) - }) + assert.True(t, dbFederationHost.PublicKey.Valid) + assert.Equal(t, sql.RawBytes{0x23, 0x42}, dbFederationHost.PublicKey.V) }) } func TestStoreFederatedUser(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - t.Run("ExplicitNull", func(t *testing.T) { - federatedUser := user.FederatedUser{ - UserID: 0, - ExternalID: "ExplicitNull", - FederationHostID: 0, - KeyID: sql.NullString{Valid: false}, - PublicKey: sql.Null[sql.RawBytes]{Valid: false}, - } + defer tests.PrepareTestEnv(t)() + t.Run("ExplicitNull", func(t *testing.T) { + federatedUser := user.FederatedUser{ + UserID: 0, + ExternalID: "ExplicitNull", + FederationHostID: 0, + KeyID: sql.NullString{Valid: false}, + PublicKey: sql.Null[sql.RawBytes]{Valid: false}, + } - _, err := db.GetEngine(db.DefaultContext).Insert(&federatedUser) - require.NoError(t, err) + _, err := db.GetEngine(db.DefaultContext).Insert(&federatedUser) + require.NoError(t, err) - dbFederatedUser := new(user.FederatedUser) - has, err := db.GetEngine(db.DefaultContext).Where("user_id=?", 0).Get(dbFederatedUser) - require.NoError(t, err) - assert.True(t, has) + dbFederatedUser := new(user.FederatedUser) + has, err := db.GetEngine(db.DefaultContext).Where("user_id=?", 0).Get(dbFederatedUser) + require.NoError(t, err) + assert.True(t, has) - assert.False(t, dbFederatedUser.KeyID.Valid) - assert.False(t, dbFederatedUser.PublicKey.Valid) - }) + assert.False(t, dbFederatedUser.KeyID.Valid) + assert.False(t, dbFederatedUser.PublicKey.Valid) + }) - t.Run("NotNull", func(t *testing.T) { - federatedUser := user.FederatedUser{ - UserID: 1, - ExternalID: "ImplicitNull", - FederationHostID: 1, - KeyID: sql.NullString{Valid: true, String: "woem"}, - PublicKey: sql.Null[sql.RawBytes]{Valid: true, V: sql.RawBytes{0x42, 0x23}}, - } + t.Run("NotNull", func(t *testing.T) { + federatedUser := user.FederatedUser{ + UserID: 1, + ExternalID: "ImplicitNull", + FederationHostID: 1, + KeyID: sql.NullString{Valid: true, String: "woem"}, + PublicKey: sql.Null[sql.RawBytes]{Valid: true, V: sql.RawBytes{0x42, 0x23}}, + } - _, err := db.GetEngine(db.DefaultContext).Insert(&federatedUser) - require.NoError(t, err) + _, err := db.GetEngine(db.DefaultContext).Insert(&federatedUser) + require.NoError(t, err) - dbFederatedUser := new(user.FederatedUser) - has, err := db.GetEngine(db.DefaultContext).Where("user_id=?", 1).Get(dbFederatedUser) - require.NoError(t, err) - assert.True(t, has) + dbFederatedUser := new(user.FederatedUser) + has, err := db.GetEngine(db.DefaultContext).Where("user_id=?", 1).Get(dbFederatedUser) + require.NoError(t, err) + assert.True(t, has) - assert.True(t, dbFederatedUser.KeyID.Valid) - assert.Equal(t, "woem", dbFederatedUser.KeyID.String) - assert.True(t, dbFederatedUser.PublicKey.Valid) - assert.Equal(t, sql.RawBytes{0x42, 0x23}, dbFederatedUser.PublicKey.V) - }) + assert.True(t, dbFederatedUser.KeyID.Valid) + assert.Equal(t, "woem", dbFederatedUser.KeyID.String) + assert.True(t, dbFederatedUser.PublicKey.Valid) + assert.Equal(t, sql.RawBytes{0x42, 0x23}, dbFederatedUser.PublicKey.V) }) }