diff --git a/go.mod b/go.mod index 7a09fe7bba..24de250644 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/felixge/fgprof v0.9.5 github.com/fsnotify/fsnotify v1.9.0 github.com/gliderlabs/ssh v0.3.8 - github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 + github.com/go-ap/activitypub v0.0.0-20260208110334-902f6cf8c2cc github.com/go-ap/jsonld v0.0.0-20251216162253-e38fa664ea77 github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 @@ -168,7 +168,7 @@ require ( github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect + github.com/go-ap/errors v0.0.0-20260208110149-e1b309365966 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-errors/errors v1.4.2 // indirect diff --git a/go.sum b/go.sum index fb74d8b500..11678e62ab 100644 --- a/go.sum +++ b/go.sum @@ -253,11 +253,10 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI= -github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9/go.mod h1:cJ9Ye0ZNSMN7RzZDBRY3E+8M3Bpf/R1JX22Ir9yX6WI= -github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 h1:I2nuhyVI/48VXoRCCZR2hYBgnSXa+EuDJf/VyX06TC0= -github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7/go.mod h1:5x8a6P/dhmMGFxWLcyYlyOuJ2lRNaHGhRv+yu8BaTSI= -github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA= +github.com/go-ap/activitypub v0.0.0-20260208110334-902f6cf8c2cc h1:yLe7YJhK+XNjNV4SqDxAjpWAgft+KU+XwKZS4AKEUV0= +github.com/go-ap/activitypub v0.0.0-20260208110334-902f6cf8c2cc/go.mod h1:jUs8eczo1EAT4ByRpZ4mQmNvjarw9eNf7Nm5udpMRhY= +github.com/go-ap/errors v0.0.0-20260208110149-e1b309365966 h1:tV+3kZgqFMKVUf+JPKBV400ISM8440+6y/SQCS0WZwQ= +github.com/go-ap/errors v0.0.0-20260208110149-e1b309365966/go.mod h1:zkp58Q5yXpCxZbh3d0GDvwqiYclfVuHEHjc9SZKAj6I= github.com/go-ap/jsonld v0.0.0-20251216162253-e38fa664ea77 h1:yHAmoR6avNy84PlLmjHt1z9flAp2Qs2ens5QDE/CNWk= github.com/go-ap/jsonld v0.0.0-20251216162253-e38fa664ea77/go.mod h1:4h93IBxgfnE/DEleMLgJ/XCeu/RtQ+MUh3ucANseeXA= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= @@ -664,7 +663,6 @@ github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI= github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= -github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= diff --git a/modules/forgefed/activity_follow.go b/modules/forgefed/activity_follow.go index 5cb45ca885..928321a00a 100644 --- a/modules/forgefed/activity_follow.go +++ b/modules/forgefed/activity_follow.go @@ -48,8 +48,8 @@ func (follow *ForgeFollow) UnmarshalJSON(data []byte) error { func (follow ForgeFollow) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(follow.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(follow.Type), []any{"Follow"}, "type")...) + result = append(result, validation.ValidateNotEmpty(follow.Type, "type")...) + result = append(result, validation.ValidateOneOf(follow.Type, []any{ap.FollowType}, "type")...) result = append(result, validation.ValidateIDExists(follow.Actor, "actor")...) result = append(result, validation.ValidateIDExists(follow.Object, "object")...) diff --git a/modules/forgefed/activity_follow_test.go b/modules/forgefed/activity_follow_test.go index 18fbef33aa..e0142a39f2 100644 --- a/modules/forgefed/activity_follow_test.go +++ b/modules/forgefed/activity_follow_test.go @@ -15,7 +15,7 @@ import ( func Test_NewForgeFollowValidation(t *testing.T) { sut := forgefed.ForgeFollow{} - sut.Type = "Follow" + sut.Type = ap.FollowType sut.Actor = ap.IRI("example.org/alice") sut.Object = ap.IRI("example.org/bob") diff --git a/modules/forgefed/activity_like.go b/modules/forgefed/activity_like.go index e52d0a9af6..7849aec568 100644 --- a/modules/forgefed/activity_like.go +++ b/modules/forgefed/activity_like.go @@ -44,8 +44,8 @@ func (like ForgeLike) IsNewer(compareTo time.Time) bool { func (like ForgeLike) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(like.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(like.Type), []any{"Like"}, "type")...) + result = append(result, validation.ValidateNotEmpty(like.Type, "type")...) + result = append(result, validation.ValidateOneOf(like.Type, []any{ap.LikeType}, "type")...) if like.Actor == nil { result = append(result, "Actor should not be nil.") diff --git a/modules/forgefed/activity_like_test.go b/modules/forgefed/activity_like_test.go index c0b565f4db..dc2d8efdc7 100644 --- a/modules/forgefed/activity_like_test.go +++ b/modules/forgefed/activity_like_test.go @@ -51,7 +51,7 @@ func Test_LikeMarshalJSON(t *testing.T) { item: forgefed.ForgeLike{ Activity: ap.Activity{ Actor: ap.IRI("https://repo.prod.meissa.de/api/v1/activitypub/user-id/1"), - Type: "Like", + Type: ap.LikeType, Object: ap.IRI("https://codeberg.org/api/v1/activitypub/repository-id/1"), }, }, @@ -80,7 +80,7 @@ func Test_LikeUnmarshalJSON(t *testing.T) { item: []byte(`{"type":"Like","actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1","object":"https://codeberg.org/api/activitypub/repository-id/1"}`), want: &forgefed.ForgeLike{ Activity: ap.Activity{ - Type: "Like", + Type: ap.LikeType, Actor: ap.IRI("https://repo.prod.meissa.de/api/activitypub/user-id/1"), Object: ap.IRI("https://codeberg.org/api/activitypub/repository-id/1"), }, @@ -124,7 +124,7 @@ func Test_ForgeLikeValidation(t *testing.T) { validate := sut.Validate() assert.Len(t, validate, 2) assert.Equal(t, - "Field type contains the value , which is not in allowed subset [Like]", + "Field type contains the value , which is not in allowed subset [Like]", validate[1]) sut.UnmarshalJSON([]byte(`{"type":"bad-type", diff --git a/modules/forgefed/activity_undo_like.go b/modules/forgefed/activity_undo_like.go index 8b7df582ad..eaf32ab09f 100644 --- a/modules/forgefed/activity_undo_like.go +++ b/modules/forgefed/activity_undo_like.go @@ -42,8 +42,8 @@ func (undo *ForgeUndoLike) UnmarshalJSON(data []byte) error { func (undo ForgeUndoLike) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(undo.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(undo.Type), []any{"Undo"}, "type")...) + result = append(result, validation.ValidateNotEmpty(undo.Type, "type")...) + result = append(result, validation.ValidateOneOf(undo.Type, []any{ap.UndoType}, "type")...) if undo.Actor == nil { result = append(result, "Actor should not be nil.") @@ -61,8 +61,8 @@ func (undo ForgeUndoLike) Validate() []string { } else if activity, ok := undo.Object.(*ap.Activity); !ok { result = append(result, "object is not of type Activity") } else { - result = append(result, validation.ValidateNotEmpty(string(activity.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(activity.Type), []any{"Like"}, "type")...) + result = append(result, validation.ValidateNotEmpty(activity.Type, "type")...) + result = append(result, validation.ValidateOneOf(activity.Type, []any{ap.LikeType}, "type")...) if activity.Actor == nil { result = append(result, "Object.Actor should not be nil.") diff --git a/modules/forgefed/activity_undo_like_test.go b/modules/forgefed/activity_undo_like_test.go index 18db688c48..cbb309afc5 100644 --- a/modules/forgefed/activity_undo_like_test.go +++ b/modules/forgefed/activity_undo_like_test.go @@ -64,7 +64,7 @@ func Test_UndoLikeMarshalJSON(t *testing.T) { Activity: ap.Activity{ StartTime: startTime, Actor: ap.IRI("https://repo.prod.meissa.de/api/v1/activitypub/user-id/1"), - Type: "Undo", + Type: ap.UndoType, Object: like, }, }, @@ -117,7 +117,7 @@ func Test_UndoLikeUnmarshalJSON(t *testing.T) { Activity: ap.Activity{ StartTime: startTime, Actor: ap.IRI("https://repo.prod.meissa.de/api/v1/activitypub/user-id/1"), - Type: "Undo", + Type: ap.UndoType, Object: like, }, }, diff --git a/modules/forgefed/activity_user_activity.go b/modules/forgefed/activity_user_activity.go index 82353245c9..69e7bc3ead 100644 --- a/modules/forgefed/activity_user_activity.go +++ b/modules/forgefed/activity_user_activity.go @@ -60,8 +60,8 @@ func NewForgeUserActivity(doer *user_model.User, actionID int64, content string) func (userActivity ForgeUserActivity) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(userActivity.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(userActivity.Type), []any{"Create"}, "type")...) + result = append(result, validation.ValidateNotEmpty(userActivity.Type, "type")...) + result = append(result, validation.ValidateOneOf(userActivity.Type, []any{ap.CreateType}, "type")...) result = append(result, validation.ValidateIDExists(userActivity.Actor, "actor")...) if len(userActivity.To) == 0 { diff --git a/modules/forgefed/activity_user_activity_test.go b/modules/forgefed/activity_user_activity_test.go index 49137c7ab4..106f0ac73c 100644 --- a/modules/forgefed/activity_user_activity_test.go +++ b/modules/forgefed/activity_user_activity_test.go @@ -15,17 +15,14 @@ import ( func Test_ForgeUserActivityValidation(t *testing.T) { note := forgefed.ForgeUserActivityNote{} - note.Type = "Note" + note.Type = ap.NoteType note.Content = ap.NaturalLanguageValues{ - { - Ref: ap.NilLangRef, - Value: ap.Content("Any Content!"), - }, + ap.NilLangRef: ap.Content("Any Content!"), } note.URL = ap.IRI("example.org/user-id/57") sut := forgefed.ForgeUserActivity{} - sut.Type = "Create" + sut.Type = ap.CreateType sut.Actor = ap.IRI("example.org/user-id/23") sut.CC = ap.ItemCollection{ ap.IRI("example.org/registration/public#2nd"), diff --git a/modules/forgefed/actor_person.go b/modules/forgefed/actor_person.go index 72768f4815..cde2dea9ce 100644 --- a/modules/forgefed/actor_person.go +++ b/modules/forgefed/actor_person.go @@ -115,8 +115,8 @@ func (s *ForgePerson) UnmarshalJSON(data []byte) error { func (s ForgePerson) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(s.Type), "Type")...) - result = append(result, validation.ValidateOneOf(string(s.Type), []any{string(ap.PersonType)}, "Type")...) + result = append(result, validation.ValidateNotEmpty(s.Type, "Type")...) + result = append(result, validation.ValidateOneOf(s.Type, []any{ap.PersonType}, "Type")...) result = append(result, validation.ValidateNotEmpty(s.PreferredUsername.String(), "PreferredUsername")...) return result diff --git a/modules/forgefed/actor_person_test.go b/modules/forgefed/actor_person_test.go index 82bd9fabc3..f673aabba1 100644 --- a/modules/forgefed/actor_person_test.go +++ b/modules/forgefed/actor_person_test.go @@ -194,9 +194,9 @@ func TestShouldThrowErrorOnInvalidInput(t *testing.T) { func Test_PersonMarshalJSON(t *testing.T) { sut := forgefed.ForgePerson{} - sut.Type = "Person" + sut.Type = ap.PersonType sut.PreferredUsername = ap.NaturalLanguageValuesNew() - sut.PreferredUsername.Set("en", ap.Content("MaxMuster")) + sut.PreferredUsername.Set(ap.English, ap.Content("MaxMuster")) result, _ := sut.MarshalJSON() assert.JSONEq(t, `{"type":"Person","preferredUsername":"MaxMuster"}`, string(result), "Expected string is not equal") } @@ -204,9 +204,9 @@ func Test_PersonMarshalJSON(t *testing.T) { func Test_PersonUnmarshalJSON(t *testing.T) { expected := &forgefed.ForgePerson{ Actor: ap.Actor{ - Type: "Person", + Type: ap.PersonType, PreferredUsername: ap.NaturalLanguageValues{ - ap.LangRefValue{Ref: "en", Value: []byte("MaxMuster")}, + ap.English: []byte("MaxMuster"), }, }, } diff --git a/modules/forgefed/object_user_activity_note.go b/modules/forgefed/object_user_activity_note.go index 758c25aef8..b8e09ecf94 100644 --- a/modules/forgefed/object_user_activity_note.go +++ b/modules/forgefed/object_user_activity_note.go @@ -35,10 +35,7 @@ func newNote(doer *user_model.User, content, id string, published time.Time) (Fo note.Type = ap.NoteType note.AttributedTo = ap.IRI(doer.APActorID()) note.Content = ap.NaturalLanguageValues{ - { - Ref: ap.NilLangRef, - Value: ap.Content(content), - }, + ap.NilLangRef: ap.Content(content), } note.ID = ap.IRI(id) note.Published = published @@ -59,8 +56,8 @@ func newNote(doer *user_model.User, content, id string, published time.Time) (Fo func (note ForgeUserActivityNote) Validate() []string { var result []string - result = append(result, validation.ValidateNotEmpty(string(note.Type), "type")...) - result = append(result, validation.ValidateOneOf(string(note.Type), []any{"Note"}, "type")...) + result = append(result, validation.ValidateNotEmpty(note.Type, "type")...) + result = append(result, validation.ValidateOneOf(note.Type, []any{ap.NoteType}, "type")...) result = append(result, validation.ValidateNotEmpty(note.Content.String(), "content")...) result = append(result, validation.ValidateIDExists(note.URL, "url")...) diff --git a/modules/forgefed/object_user_activity_note_test.go b/modules/forgefed/object_user_activity_note_test.go index 4f790033bc..e559ce84f7 100644 --- a/modules/forgefed/object_user_activity_note_test.go +++ b/modules/forgefed/object_user_activity_note_test.go @@ -15,12 +15,9 @@ import ( func Test_UserActivityNoteValidation(t *testing.T) { sut := forgefed.ForgeUserActivityNote{} - sut.Type = "Note" + sut.Type = ap.NoteType sut.Content = ap.NaturalLanguageValues{ - { - Ref: ap.NilLangRef, - Value: ap.Content("Any Content!"), - }, + ap.NilLangRef: ap.Content("Any Content!"), } sut.URL = ap.IRI("example.org/user-id/57") diff --git a/modules/validation/validatable.go b/modules/validation/validatable.go index 1751e727f3..6c58a9148e 100644 --- a/modules/validation/validatable.go +++ b/modules/validation/validatable.go @@ -70,6 +70,8 @@ func ValidateNotEmpty(value any, name string) []string { if v == 0 { isValid = false } + case ap.Typer: + isValid = len(value.(ap.Typer).AsTypes()) > 0 default: isValid = false } diff --git a/routers/api/v1/activitypub/actor.go b/routers/api/v1/activitypub/actor.go index f8b08e92c3..4bbeb7e7f2 100644 --- a/routers/api/v1/activitypub/actor.go +++ b/routers/api/v1/activitypub/actor.go @@ -32,7 +32,7 @@ func Actor(ctx *context.APIContext) { actor := ap.ActorNew(ap.IRI(link), ap.ApplicationType) actor.PreferredUsername = ap.NaturalLanguageValuesNew() - err := actor.PreferredUsername.Set("en", ap.Content("ghost")) + err := actor.PreferredUsername.Set(ap.NilLangRef, ap.Content("ghost")) if err != nil { ctx.ServerError("PreferredUsername.Set", err) return diff --git a/routers/api/v1/activitypub/repository.go b/routers/api/v1/activitypub/repository.go index 178f4b246f..153719478f 100644 --- a/routers/api/v1/activitypub/repository.go +++ b/routers/api/v1/activitypub/repository.go @@ -45,7 +45,7 @@ func Repository(ctx *context.APIContext) { repo.Outbox = ap.IRI(link + "/outbox") repo.Name = ap.NaturalLanguageValuesNew() - err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name)) + err := repo.Name.Set(ap.NilLangRef, ap.Content(ctx.Repo.Repository.Name)) if err != nil { ctx.Error(http.StatusInternalServerError, "Set Name", err) return diff --git a/services/convert/activitypub_person.go b/services/convert/activitypub_person.go index 2c05f8c1c0..e4186cf30d 100644 --- a/services/convert/activitypub_person.go +++ b/services/convert/activitypub_person.go @@ -16,7 +16,7 @@ import ( func ToActivityPubPersonFeedItem(item *activities.FederatedUserActivity) ap.Note { return ap.Note{ AttributedTo: ap.IRI(item.ActorURI), - Content: ap.NaturalLanguageValues{{Value: ap.Content(item.NoteContent), Ref: ap.NilLangRef}}, + Content: ap.NaturalLanguageValues{ap.NilLangRef: ap.Content(item.NoteContent)}, ID: ap.IRI(item.NoteURL), URL: ap.IRI(item.OriginalNote), } @@ -27,13 +27,13 @@ func ToActivityPubPerson(ctx context.Context, user *user_model.User) (*ap.Person person := ap.PersonNew(ap.IRI(link)) person.Name = ap.NaturalLanguageValuesNew() - err := person.Name.Set("en", ap.Content(user.FullName)) + err := person.Name.Set(ap.NilLangRef, ap.Content(user.FullName)) if err != nil { return nil, err } person.PreferredUsername = ap.NaturalLanguageValuesNew() - err = person.PreferredUsername.Set("en", ap.Content(user.Name)) + err = person.PreferredUsername.Set(ap.NilLangRef, ap.Content(user.Name)) if err != nil { return nil, err } diff --git a/tests/integration/repo_star_federation_test.go b/tests/integration/repo_star_federation_test.go index d6f31ed246..3b5fc0d802 100644 --- a/tests/integration/repo_star_federation_test.go +++ b/tests/integration/repo_star_federation_test.go @@ -18,6 +18,8 @@ import ( "forgejo.org/modules/test" "forgejo.org/modules/validation" "forgejo.org/tests" + + ap "github.com/go-ap/activitypub" ) func TestActivityPubRepoFollowing(t *testing.T) { @@ -69,7 +71,7 @@ func TestActivityPubRepoFollowing(t *testing.T) { } activityType := like.Type object := like.Object.GetLink().String() - isLikeType := activityType == "Like" + isLikeType := activityType == ap.LikeType isCorrectObject := strings.HasSuffix(object, "/api/v1/activitypub/repository-id/1") if !isLikeType || !isCorrectObject { t.Error("Activity is not a like for this repo")