diff --git a/models/forgefed/forgefed.go b/models/forgefed/forgefed.go index 39872fa74d..d9f12f2a33 100644 --- a/models/forgefed/forgefed.go +++ b/models/forgefed/forgefed.go @@ -13,7 +13,7 @@ const ForgeFedNamespaceURI = "https://forgefed.org/ns" // GetItemByType instantiates a new ForgeFed object if the type matches // otherwise it defaults to existing activitypub package typer function. func GetItemByType(typ ap.ActivityVocabularyType) (ap.Item, error) { - switch typ { + switch typ { case CommitType: return CommitNew(), nil case BranchType: diff --git a/models/forgefed/push.go b/models/forgefed/push.go index 82ef45c0d4..937b206ae5 100644 --- a/models/forgefed/push.go +++ b/models/forgefed/push.go @@ -50,18 +50,18 @@ func (p Push) MarshalJSON() ([]byte, error) { return b, nil } -func (c *Push) UnmarshalJSON(data []byte) error { - p := fastjson.Parser{} - val, err := p.ParseBytes(data) +func (p *Push) UnmarshalJSON(data []byte) error { + ps := fastjson.Parser{} + val, err := ps.ParseBytes(data) if err != nil { return err } - c.Target = ap.JSONGetItem(val, "target") - c.HashBefore = ap.JSONGetItem(val, "hashBefore") - c.HashAfter = ap.JSONGetItem(val, "hashAfter") + p.Target = ap.JSONGetItem(val, "target") + p.HashBefore = ap.JSONGetItem(val, "hashBefore") + p.HashAfter = ap.JSONGetItem(val, "hashAfter") - return ap.OnObject(&c.Object, func(a *ap.Object) error { + return ap.OnObject(&p.Object, func(a *ap.Object) error { return ap.LoadObject(val, a) }) } diff --git a/models/forgefed/repository_test.go b/models/forgefed/repository_test.go index 4bf36a66ce..b5f7dc9e73 100644 --- a/models/forgefed/repository_test.go +++ b/models/forgefed/repository_test.go @@ -1,11 +1,12 @@ package forgefed import ( - "encoding/json" "fmt" "reflect" "testing" + "code.gitea.io/gitea/modules/json" + ap "github.com/go-ap/activitypub" ) diff --git a/modules/activitypub/authorize_interaction.go b/modules/activitypub/authorize_interaction.go index 9ee8c0f74a..af783d8954 100644 --- a/modules/activitypub/authorize_interaction.go +++ b/modules/activitypub/authorize_interaction.go @@ -22,38 +22,42 @@ func AuthorizeInteraction(c *context.Context) { } resp, err := Fetch(uri) if err != nil { - c.ServerError("Could not fetch remote URI", err) + c.ServerError("Fetch", err) return } var object map[string]interface{} err = json.Unmarshal(resp, &object) if err != nil { - c.ServerError("Could not unmarshal response into JSON", err) + c.ServerError("Unmarshal", err) return } switch object["type"] { case "Person": var person ap.Person - person.UnmarshalJSON(resp) - err = FederatedUserNew(c, person) - /*if err != nil { - c.ServerError("Could not create new federated user", err) + err = person.UnmarshalJSON(resp) + if err != nil { + c.ServerError("UnmarshalJSON", err) return - }*/ + } + err = FederatedUserNew(c, person) + if err != nil { + c.ServerError("FederatedUserNew", err) + return + } name, err := personIRIToName(person.GetLink()) if err != nil { c.ServerError("personIRIToName", err) return } c.Redirect(name) - /*case "organization": - // Do something idk - case "repository": - FederatedRepoNew() // TODO - case "ticket": - // TODO*/ + /*case "organization": + // Do something idk + case "repository": + FederatedRepoNew() // TODO + case "ticket": + // TODO*/ } c.Status(http.StatusOK) -} \ No newline at end of file +} diff --git a/modules/activitypub/comment.go b/modules/activitypub/comment.go index d241ada7f9..8e76c24c42 100644 --- a/modules/activitypub/comment.go +++ b/modules/activitypub/comment.go @@ -11,17 +11,15 @@ import ( "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/log" ap "github.com/go-ap/activitypub" ) // Create a comment -func Comment(ctx context.Context, note ap.Note) { +func Comment(ctx context.Context, note ap.Note) error { actorUser, err := personIRIToUser(ctx, note.AttributedTo.GetLink()) if err != nil { - log.Warn("Couldn't find actor", err) - return + return err } // TODO: Move IRI processing stuff to iri.go @@ -33,10 +31,11 @@ func Comment(ctx context.Context, note ap.Note) { idx, _ := strconv.ParseInt(contextSplit[len(contextSplit)-1], 10, 64) issue, _ := issues.GetIssueByIndex(repo.ID, idx) - issues.CreateCommentCtx(ctx, &issues.CreateCommentOptions{ + _, err = issues.CreateCommentCtx(ctx, &issues.CreateCommentOptions{ Doer: actorUser, Repo: repo, Issue: issue, Content: note.Content.String(), }) + return err } diff --git a/modules/activitypub/follow.go b/modules/activitypub/follow.go index 509635690e..f606e59df9 100644 --- a/modules/activitypub/follow.go +++ b/modules/activitypub/follow.go @@ -9,19 +9,17 @@ import ( "strings" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" ap "github.com/go-ap/activitypub" ) // Process a Follow activity -func Follow(ctx context.Context, follow ap.Follow) { +func Follow(ctx context.Context, follow ap.Follow) error { // Actor is the user performing the follow actorIRI := follow.Actor.GetID() actorUser, err := personIRIToUser(ctx, actorIRI) if err != nil { - log.Warn("Couldn't find actor user for follow", err) - return + return err } // Object is the user being followed @@ -29,29 +27,30 @@ func Follow(ctx context.Context, follow ap.Follow) { objectUser, err := personIRIToUser(ctx, objectIRI) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { - log.Warn("Couldn't find object user for follow", err) - return + return err } - user_model.FollowUser(actorUser.ID, objectUser.ID) + err = user_model.FollowUser(actorUser.ID, objectUser.ID) + if err != nil { + return err + } // Send back an Accept activity accept := ap.AcceptNew(objectIRI, follow) accept.Actor = ap.Person{ID: objectIRI} accept.To = ap.ItemCollection{ap.IRI(actorIRI.String() + "/inbox")} accept.Object = follow - Send(objectUser, accept) + return Send(objectUser, accept) } // Process a Undo follow activity -func Unfollow(ctx context.Context, unfollow ap.Undo) { +func Unfollow(ctx context.Context, unfollow ap.Undo) error { follow := unfollow.Object.(*ap.Follow) // Actor is the user performing the undo follow actorIRI := follow.Actor.GetID() actorUser, err := personIRIToUser(ctx, actorIRI) if err != nil { - log.Warn("Couldn't find actor user for follow", err) - return + return err } // Object is the user being unfollowed @@ -59,9 +58,8 @@ func Unfollow(ctx context.Context, unfollow ap.Undo) { objectUser, err := personIRIToUser(ctx, objectIRI) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { - log.Warn("Couldn't find object user for follow", err) - return + return err } - user_model.UnfollowUser(actorUser.ID, objectUser.ID) + return user_model.UnfollowUser(actorUser.ID, objectUser.ID) } diff --git a/modules/activitypub/fork.go b/modules/activitypub/fork.go index e848e3f52a..209a59a675 100644 --- a/modules/activitypub/fork.go +++ b/modules/activitypub/fork.go @@ -19,7 +19,7 @@ import ( ap "github.com/go-ap/activitypub" ) -func Fork(ctx context.Context, instance, username, reponame, destUsername string) { +func Fork(ctx context.Context, instance, username, reponame, destUsername string) error { // TODO: Clean this up // Migrate repository code @@ -42,10 +42,10 @@ func Fork(ctx context.Context, instance, username, reponame, destUsername string // repo.ForkedFrom = forgefed.RepositoryNew(ap.IRI()) create.Object = repo - Send(user, &create) + return Send(user, &create) } -func ForkFromCreate(ctx context.Context, repository forgefed.Repository) { +func ForkFromCreate(ctx context.Context, repository forgefed.Repository) error { // TODO: Clean this up // Don't create an actual copy of the remote repo! @@ -66,5 +66,5 @@ func ForkFromCreate(ctx context.Context, repository forgefed.Repository) { repo, _ := repo_model.GetRepositoryByOwnerAndName("Ta180m", reponame) // hardcoded for now :( _, err := repo_service.ForkRepository(ctx, user, user, repo_service.ForkRepoOptions{BaseRepo: repo, Name: reponame, Description: "this is a remote fork"}) - log.Warn("Couldn't create copy of remote fork", err) + return err } diff --git a/modules/activitypub/iri.go b/modules/activitypub/iri.go index 1ef12239ac..235545cd20 100644 --- a/modules/activitypub/iri.go +++ b/modules/activitypub/iri.go @@ -28,11 +28,10 @@ func personIRIToName(personIRI ap.IRI) (string, error) { if instance == setting.Domain { // Local user return name, nil - } else { - // Remote user - // Get name in username@instance.com format - return name + "@" + instance, nil } + // Remote user + // Get name in username@instance.com format + return name + "@" + instance, nil } // Returns the user corresponding to a Person actor IRI @@ -63,10 +62,9 @@ func repositoryIRIToName(repoIRI ap.IRI) (string, string, error) { if instance == setting.Domain { // Local repo return username, reponame, nil - } else { - // Remote repo - return username + "@" + instance, reponame, nil } + // Remote repo + return username + "@" + instance, reponame, nil } // Returns the repository corresponding to a Repository actor IRI diff --git a/modules/activitypub/repo.go b/modules/activitypub/repo.go index 44bd34b157..a52a4d155e 100644 --- a/modules/activitypub/repo.go +++ b/modules/activitypub/repo.go @@ -13,7 +13,7 @@ import ( ap "github.com/go-ap/activitypub" ) -func FederatedRepoNew(user *user_model.User, name string, IRI ap.IRI) (*repo_model.Repository, error) { +func FederatedRepoNew(user *user_model.User, name string, iri ap.IRI) (*repo_model.Repository, error) { // TODO: also handle forks return repository.CreateRepository(user, user, models.CreateRepoOptions{ Name: name, diff --git a/modules/activitypub/transport.go b/modules/activitypub/transport.go index f0aa12f1f3..4d860f4314 100644 --- a/modules/activitypub/transport.go +++ b/modules/activitypub/transport.go @@ -40,15 +40,14 @@ func Fetch(iri *url.URL) (b []byte, err error) { } // Send an activity -func Send(user *user_model.User, activity *ap.Activity) { +func Send(user *user_model.User, activity *ap.Activity) error { binary, err := jsonld.WithContext( jsonld.IRI(ap.ActivityBaseURI), jsonld.IRI(ap.SecurityContextURI), jsonld.IRI(forgefed.ForgeFedNamespaceURI), ).Marshal(activity) if err != nil { - log.Warn("Marshal", err) - return + return err } for _, to := range activity.To { @@ -57,4 +56,5 @@ func Send(user *user_model.User, activity *ap.Activity) { respBody, _ := io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize)) log.Trace("Response from sending activity", string(respBody)) } + return err } diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index 019b084b20..85230c0d83 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -129,14 +129,18 @@ func PersonInbox(ctx *context.APIContext) { // Process activity switch activity.Type { case ap.FollowType: - activitypub.Follow(ctx, activity) + err = activitypub.Follow(ctx, activity) case ap.UndoType: - activitypub.Unfollow(ctx, activity) + err = activitypub.Unfollow(ctx, activity) default: log.Info("Incoming unsupported ActivityStreams type: %s", activity.GetType()) ctx.PlainText(http.StatusNotImplemented, "ActivityStreams type not supported") return } + if err != nil { + ctx.ServerError("Could not process activity", err) + return + } ctx.Status(http.StatusNoContent) } @@ -180,7 +184,11 @@ func PersonOutbox(ctx *context.APIContext) { object := ap.Note{Type: ap.NoteType, Content: ap.NaturalLanguageValuesNew()} object.Content.Set("en", ap.Content(action.GetRepoName())) create := ap.Create{Type: ap.CreateType, Object: object} - outbox.OrderedItems.Append(create) + err := outbox.OrderedItems.Append(create) + if err != nil { + ctx.ServerError("OrderedItems.Append", err) + return + } } } @@ -194,7 +202,11 @@ func PersonOutbox(ctx *context.APIContext) { object := ap.Note{Type: ap.NoteType, Content: ap.NaturalLanguageValuesNew()} object.Content.Set("en", ap.Content("Starred "+star.Name)) create := ap.Create{Type: ap.CreateType, Object: object} - outbox.OrderedItems.Append(create) + err := outbox.OrderedItems.Append(create) + if err != nil { + ctx.ServerError("OrderedItems.Append", err) + return + } } outbox.TotalItems = uint(len(outbox.OrderedItems)) @@ -233,7 +245,11 @@ func PersonFollowing(ctx *context.APIContext) { for _, user := range users { // TODO: handle non-Federated users person := ap.PersonNew(ap.IRI(user.Website)) - following.OrderedItems.Append(person) + err := following.OrderedItems.Append(person) + if err != nil { + ctx.ServerError("OrderedItems.Append", err) + return + } } response(ctx, following) @@ -270,7 +286,11 @@ func PersonFollowers(ctx *context.APIContext) { for _, user := range users { // TODO: handle non-Federated users person := ap.PersonNew(ap.IRI(user.Website)) - followers.OrderedItems.Append(person) + err := followers.OrderedItems.Append(person) + if err != nil { + ctx.ServerError("OrderedItems.Append", err) + return + } } response(ctx, followers) @@ -311,7 +331,11 @@ func PersonLiked(ctx *context.APIContext) { for _, repo := range repos { // TODO: Handle remote starred repos repo := forgefed.RepositoryNew(ap.IRI(setting.AppURL + "api/v1/activitypub/repo/" + repo.OwnerName + "/" + repo.Name)) - liked.OrderedItems.Append(repo) + err := liked.OrderedItems.Append(repo) + if err != nil { + ctx.ServerError("OrderedItems.Append", err) + return + } } response(ctx, liked) diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go index f8a6360621..e427ce8dd5 100644 --- a/routers/api/v1/activitypub/reqsignature.go +++ b/routers/api/v1/activitypub/reqsignature.go @@ -81,7 +81,7 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er var person ap.Person person.UnmarshalJSON(b) err = activitypub.FederatedUserNew(ctx, person) - return + return authenticated, err } // ReqHTTPSignature function