Changes
29 changed files (+392/-376)
-
modules/activitypub/comment.go (deleted)
-
@@ -1,42 +0,0 @@// 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" "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" ap "github.com/go-ap/activitypub" ) // Create a comment func Comment(ctx context.Context, note *ap.Note) error { actorUser, err := PersonIRIToUser(ctx, note.AttributedTo.GetLink()) if err != nil { return err } username, reponame, idx, err := TicketIRIToName(note.Context.GetLink()) if err != nil { return err } repo, err := repo_model.GetRepositoryByOwnerAndNameCtx(ctx, username, reponame) if err != nil { return err } issue, err := issues.GetIssueByIndex(repo.ID, idx) if err != nil { return err } _, err = issues.CreateCommentCtx(ctx, &issues.CreateCommentOptions{ Doer: actorUser, Repo: repo, Issue: issue, Content: note.Content.String(), }) return err }
-
-
modules/activitypub/issue.go (deleted)
-
@@ -1,47 +0,0 @@// 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" "fmt" "strconv" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/forgefed" issue_service "code.gitea.io/gitea/services/issue" ap "github.com/go-ap/activitypub" ) // Create an issue func ReceiveIssue(ctx context.Context, ticket *forgefed.Ticket) error { // Construct issue user, err := PersonIRIToUser(ctx, ap.IRI(ticket.AttributedTo.GetLink().String())) if err != nil { return err } repo, err := RepositoryIRIToRepository(ctx, ap.IRI(ticket.Context.GetLink().String())) if err != nil { return err } fmt.Println(ticket) fmt.Println(ticket.Name.String()) idx, err := strconv.ParseInt(ticket.Name.String()[1:], 10, 64) if err != nil { return err } issue := &issues_model.Issue{ ID: idx, RepoID: repo.ID, Repo: repo, Title: ticket.Summary.String(), PosterID: user.ID, Poster: user, Content: ticket.Content.String(), } fmt.Println(issue) return issue_service.NewIssue(repo, issue, nil, nil, nil) }
-
-
modules/activitypub/repo.go (deleted)
-
@@ -1,44 +0,0 @@// 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" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/forgefed" repo_module "code.gitea.io/gitea/modules/repository" repo_service "code.gitea.io/gitea/services/repository" ) // Create a new federated repo from a Repository object func FederatedRepoNew(ctx context.Context, repository *forgefed.Repository) error { user, err := PersonIRIToUser(ctx, repository.AttributedTo.GetLink()) if err != nil { return err } _, err = repo_model.GetRepositoryByOwnerAndNameCtx(ctx, user.Name, repository.Name.String()) if err == nil { return nil } repo, err := repo_service.CreateRepository(user, user, repo_module.CreateRepoOptions{ Name: repository.Name.String(), }) if err != nil { return err } if repository.ForkedFrom != nil { repo.IsFork = true forkedFrom, err := RepositoryIRIToRepository(ctx, repository.ForkedFrom.GetLink()) if err != nil { return err } repo.ForkID = forkedFrom.ID } return nil }
-
-
-
@@ -2,17 +2,16 @@// Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package web package activitypub import ( "net/http" "net/url" "strconv" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/forgefed" user_service "code.gitea.io/gitea/services/user" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" )
-
@@ -45,7 +44,7 @@ func AuthorizeInteraction(ctx *context.Context) {ctx.ServerError("UnmarshalJSON", err) return } err = user_service.FederatedUserNew(ctx, object.(*ap.Person)) err = createPerson(ctx, object.(*ap.Person)) if err != nil { ctx.ServerError("FederatedUserNew", err) return
-
@@ -59,29 +58,7 @@ func AuthorizeInteraction(ctx *context.Context) {case forgefed.RepositoryType: // Federated repository err = forgefed.OnRepository(object, func(r *forgefed.Repository) error { ownerURL, err := url.Parse(r.AttributedTo.GetLink().String()) if err != nil { return err } // Fetch person object resp, err := activitypub.Fetch(ownerURL) if err != nil { return err } // Parse person object ap.ItemTyperFunc = forgefed.GetItemByType ap.JSONItemUnmarshal = forgefed.JSONUnmarshalerFn ap.NotEmptyChecker = forgefed.NotEmpty object, err := ap.UnmarshalJSON(resp) if err != nil { return err } // Create federated user err = user_service.FederatedUserNew(ctx, object.(*ap.Person)) if err != nil { return err } return activitypub.FederatedRepoNew(ctx, r) return createRepository(ctx, r) }) if err != nil { ctx.ServerError("FederatedRepoNew", err)
-
@@ -117,12 +94,12 @@ func AuthorizeInteraction(ctx *context.Context) {} // Create federated repo err = forgefed.OnRepository(object, func(r *forgefed.Repository) error { return activitypub.FederatedRepoNew(ctx, r) return createRepository(ctx, r) }) if err != nil { return err } return activitypub.ReceiveIssue(ctx, t) return createIssue(ctx, t) }) if err != nil { ctx.ServerError("ReceiveIssue", err)
-
-
-
@@ -0,0 +1,199 @@// 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" "errors" "net/url" "strconv" "strings" "code.gitea.io/gitea/models/auth" issue_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/forgefed" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/activitypub" issue_service "code.gitea.io/gitea/services/issue" repo_service "code.gitea.io/gitea/services/repository" user_service "code.gitea.io/gitea/services/user" ap "github.com/go-ap/activitypub" ) // Create a new federated user from a Person object func createPerson(ctx context.Context, person *ap.Person) error { name, err := activitypub.PersonIRIToName(person.GetLink()) if err != nil { return err } exists, err := user_model.IsUserExist(ctx, 0, name) if err != nil { return err } if exists { return nil } var email string if person.Location != nil { email = person.Location.GetLink().String() } else { // This might not even work email = strings.ReplaceAll(name, "@", "+") + "@" + setting.Service.NoReplyAddress } if person.PublicKey.PublicKeyPem == "" { return errors.New("person public key not found") } user := &user_model.User{ Name: name, FullName: person.Name.String(), // May not exist!! Email: email, LoginType: auth.Federated, LoginName: person.GetLink().String(), } err = user_model.CreateUser(user) if err != nil { return err } if person.Icon != nil { icon := person.Icon.(*ap.Image) iconURL, err := icon.URL.GetLink().URL() if err != nil { return err } body, err := activitypub.Fetch(iconURL) if err != nil { return err } err = user_service.UploadAvatar(user, body) if err != nil { return err } } err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, "") if err != nil { return err } return user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, person.PublicKey.PublicKeyPem) } // Create a new federated repo from a Repository object func createRepository(ctx context.Context, repository *forgefed.Repository) error { ownerURL, err := url.Parse(repository.AttributedTo.GetLink().String()) if err != nil { return err } // Fetch person object resp, err := activitypub.Fetch(ownerURL) if err != nil { return err } // Parse person object ap.ItemTyperFunc = forgefed.GetItemByType ap.JSONItemUnmarshal = forgefed.JSONUnmarshalerFn ap.NotEmptyChecker = forgefed.NotEmpty object, err := ap.UnmarshalJSON(resp) if err != nil { return err } // Create federated user err = createPerson(ctx, object.(*ap.Person)) if err != nil { return err } user, err := activitypub.PersonIRIToUser(ctx, repository.AttributedTo.GetLink()) if err != nil { return err } _, err = repo_model.GetRepositoryByOwnerAndNameCtx(ctx, user.Name, repository.Name.String()) if err == nil { return nil } repo, err := repo_service.CreateRepository(user, user, repo_module.CreateRepoOptions{ Name: repository.Name.String(), }) if err != nil { return err } if repository.ForkedFrom != nil { repo.IsFork = true forkedFrom, err := activitypub.RepositoryIRIToRepository(ctx, repository.ForkedFrom.GetLink()) if err != nil { return err } repo.ForkID = forkedFrom.ID } return nil } // Create an issue func createIssue(ctx context.Context, ticket *forgefed.Ticket) error { // Construct issue user, err := activitypub.PersonIRIToUser(ctx, ap.IRI(ticket.AttributedTo.GetLink().String())) if err != nil { return err } repo, err := activitypub.RepositoryIRIToRepository(ctx, ap.IRI(ticket.Context.GetLink().String())) if err != nil { return err } idx, err := strconv.ParseInt(ticket.Name.String()[1:], 10, 64) if err != nil { return err } issue := &issue_model.Issue{ ID: idx, RepoID: repo.ID, Repo: repo, Title: ticket.Summary.String(), PosterID: user.ID, Poster: user, Content: ticket.Content.String(), } return issue_service.NewIssue(repo, issue, nil, nil, nil) } // Create a comment func createComment(ctx context.Context, note *ap.Note) error { actorUser, err := activitypub.PersonIRIToUser(ctx, note.AttributedTo.GetLink()) if err != nil { return err } username, reponame, idx, err := activitypub.TicketIRIToName(note.Context.GetLink()) if err != nil { return err } repo, err := repo_model.GetRepositoryByOwnerAndNameCtx(ctx, username, reponame) if err != nil { return err } issue, err := issue_model.GetIssueByIndex(repo.ID, idx) if err != nil { return err } _, err = issue_model.CreateCommentCtx(ctx, &issue_model.CreateCommentOptions{ Doer: actorUser, Repo: repo, Issue: issue, Content: note.Content.String(), }) return err }
-
-
-
@@ -9,22 +9,23 @@ import ("strings" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" ) // Process a Follow activity func Follow(ctx context.Context, follow ap.Follow) error { // Process an incoming Follow activity func follow(ctx context.Context, follow ap.Follow) error { // Actor is the user performing the follow actorIRI := follow.Actor.GetLink() actorUser, err := PersonIRIToUser(ctx, actorIRI) actorUser, err := activitypub.PersonIRIToUser(ctx, actorIRI) if err != nil { return err } // Object is the user being followed objectIRI := follow.Object.GetLink() objectUser, err := PersonIRIToUser(ctx, objectIRI) objectUser, err := activitypub.PersonIRIToUser(ctx, objectIRI) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { return err
-
@@ -40,22 +41,27 @@ func Follow(ctx context.Context, follow ap.Follow) error {accept.Actor = ap.Person{ID: objectIRI} accept.To = ap.ItemCollection{ap.IRI(actorIRI.String() + "/inbox")} accept.Object = follow return Send(objectUser, accept) return activitypub.Send(objectUser, accept) } // Process a Undo follow activity func Unfollow(ctx context.Context, unfollow ap.Undo) error { follow := unfollow.Object.(*ap.Follow) // Process an incoming Undo follow activity func unfollow(ctx context.Context, unfollow ap.Undo) error { // Object contains the follow follow, err := ap.To[ap.Follow](unfollow.Object) if err != nil { return err } // Actor is the user performing the undo follow actorIRI := follow.Actor.GetLink() actorUser, err := PersonIRIToUser(ctx, actorIRI) actorUser, err := activitypub.PersonIRIToUser(ctx, actorIRI) if err != nil { return err } // Object is the user being unfollowed objectIRI := follow.Object.GetLink() objectUser, err := PersonIRIToUser(ctx, objectIRI) objectUser, err := activitypub.PersonIRIToUser(ctx, objectIRI) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { return err
-
-
-
@@ -0,0 +1,51 @@// 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" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/services/activitypub" repo_service "code.gitea.io/gitea/services/repository" ap "github.com/go-ap/activitypub" ) func fork(ctx context.Context, create ap.Create) error { // Object is the new fork repository repository, err := ap.To[forgefed.Repository](create.Object) if err != nil { return nil } // TODO: Clean this up actor, err := activitypub.PersonIRIToUser(ctx, create.Actor.GetLink()) if err != nil { return err } // Don't create an actual copy of the remote repo! // https://gitea.com/xy/gitea/issues/7 // Create the fork repoIRI := repository.GetLink() username, reponame, err := activitypub.RepositoryIRIToName(repoIRI) if err != nil { return err } // FederatedUserNew(username + "@" + instance, ) user, _ := user_model.GetUserByName(ctx, username) // var repo forgefed.Repository // repo = activity.Object repo, _ := repo_model.GetRepositoryByOwnerAndName(actor.Name, reponame) // hardcoded for now :( _, err = repo_service.ForkRepository(ctx, user, user, repo_service.ForkRepoOptions{BaseRepo: repo, Name: reponame, Description: "this is a remote fork"}) return err }
-
-
-
@@ -14,13 +14,13 @@ import ("code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" )
-
@@ -131,9 +131,9 @@ func PersonInbox(ctx *context.APIContext) {// Process activity switch activity.Type { case ap.FollowType: err = activitypub.Follow(ctx, activity) err = follow(ctx, activity) case ap.UndoType: err = activitypub.Unfollow(ctx, activity) err = unfollow(ctx, activity) default: log.Info("Incoming unsupported ActivityStreams type: %s", activity.GetType()) ctx.PlainText(http.StatusNotImplemented, "ActivityStreams type not supported")
-
-
-
@@ -12,13 +12,14 @@ import (repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/services/activitypub" pull_service "code.gitea.io/gitea/services/pull" ) func PullRequest(ctx context.Context, ticket *forgefed.Ticket) error { func createPullRequest(ctx context.Context, ticket *forgefed.Ticket) error { // TODO: Clean this up actorUser, err := PersonIRIToUser(ctx, ticket.AttributedTo.GetLink()) actorUser, err := activitypub.PersonIRIToUser(ctx, ticket.AttributedTo.GetLink()) if err != nil { log.Warn("Couldn't find ticket actor user", err) }
-
-
-
@@ -9,7 +9,6 @@ import ("net/http" "strings" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/log"
-
@@ -128,25 +127,25 @@ func RepoInbox(ctx *context.APIContext) {switch o.Type { case forgefed.RepositoryType: // Fork created by remote instance return activitypub.ReceiveFork(ctx, activity) return fork(ctx, activity) case forgefed.TicketType: // New issue or pull request return forgefed.OnTicket(o, func(t *forgefed.Ticket) error { if t.Origin != nil { // New pull request return activitypub.PullRequest(ctx, t) return createPullRequest(ctx, t) } // New issue return activitypub.ReceiveIssue(ctx, t) return createIssue(ctx, t) }) case ap.NoteType: // New comment return activitypub.Comment(ctx, o) return createComment(ctx, o) } return nil }) case ap.LikeType: err = activitypub.ReceiveStar(ctx, activity) err = star(ctx, activity) default: log.Info("Incoming unsupported ActivityStreams type: %s", activity.Type) ctx.PlainText(http.StatusNotImplemented, "ActivityStreams type not supported")
-
-
-
@@ -12,10 +12,9 @@ import ("net/http" "net/url" "code.gitea.io/gitea/modules/activitypub" gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" user_service "code.gitea.io/gitea/services/user" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" "github.com/go-fed/httpsig"
-
@@ -85,7 +84,7 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, erreturn } err = user_service.FederatedUserNew(ctx, &person) err = createPerson(ctx, &person) return authenticated, err }
-
-
-
@@ -7,10 +7,10 @@ package activitypubimport ( "net/http" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" "github.com/go-ap/jsonld"
-
-
-
@@ -9,17 +9,18 @@ import ("strings" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" ) // Process a Like activity to star a repository func ReceiveStar(ctx context.Context, like ap.Like) (err error) { user, err := PersonIRIToUser(ctx, like.Actor.GetLink()) func star(ctx context.Context, like ap.Like) (err error) { user, err := activitypub.PersonIRIToUser(ctx, like.Actor.GetLink()) if err != nil { return } repo, err := RepositoryIRIToRepository(ctx, like.Object.GetLink()) repo, err := activitypub.RepositoryIRIToRepository(ctx, like.Object.GetLink()) if err != nil || strings.Contains(repo.Name, "@") || repo.IsPrivate { return }
-
-
-
@@ -644,6 +644,7 @@ func Routes(ctx gocontext.Context) *web.Route {} m.Get("/version", misc.Version) if setting.Federation.Enabled { m.Get("/authorize_interaction", activitypub.AuthorizeInteraction) m.Get("/nodeinfo", misc.NodeInfo) m.Group("/activitypub", func() { m.Group("/user/{username}", func() {
-
-
-
@@ -1323,10 +1323,6 @@ func RegisterRoutes(m *web.Route) {m.Get("/new", user.NewAvailable) }, reqSignIn) if setting.Federation.Enabled { m.Get("/authorize_interaction", AuthorizeInteraction) } if setting.API.EnableSwagger { m.Get("/swagger.v1.json", SwaggerV1Json) }
-
-
-
-
-
@@ -0,0 +1,53 @@// 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" "code.gitea.io/gitea/modules/setting" ap "github.com/go-ap/activitypub" ) // Create and send Follow activity func Follow(userID, followID int64) error { followUser, err := user_model.GetUserByID(followID) if err != nil { return err } actorUser, err := user_model.GetUserByID(userID) if err != nil { return err } object := ap.PersonNew(ap.IRI(followUser.LoginName)) follow := ap.FollowNew("", object) follow.Type = ap.FollowType follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name)) follow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))} return Send(actorUser, follow) } // Create and send Undo Follow activity func Unfollow(userID, followID int64) error { followUser, err := user_model.GetUserByID(followID) if err != nil { return err } actorUser, err := user_model.GetUserByID(userID) if err != nil { return err } object := ap.PersonNew(ap.IRI(followUser.LoginName)) follow := ap.FollowNew("", object) follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name)) unfollow := ap.UndoNew("", follow) unfollow.Type = ap.UndoType unfollow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))} return Send(actorUser, unfollow) }
-
-
-
-
-
-
-
-
-
-
@@ -2,17 +2,15 @@// Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package activitypub package repository import ( "context" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/activitypub" "code.gitea.io/gitea/services/migrations" repo_service "code.gitea.io/gitea/services/repository" ap "github.com/go-ap/activitypub" )
-
@@ -44,36 +42,5 @@ func CreateFork(ctx context.Context, instance, username, reponame, destUsername// repo.ForkedFrom = forgefed.RepositoryNew(ap.IRI()) create.Object = repo return Send(user, &create) } func ReceiveFork(ctx context.Context, create ap.Create) error { // TODO: Clean this up repository := create.Object.(*forgefed.Repository) actor, err := PersonIRIToUser(ctx, create.Actor.GetLink()) if err != nil { return err } // Don't create an actual copy of the remote repo! // https://gitea.com/xy/gitea/issues/7 // Create the fork repoIRI := repository.GetLink() username, reponame, err := RepositoryIRIToName(repoIRI) if err != nil { return err } // FederatedUserNew(username + "@" + instance, ) user, _ := user_model.GetUserByName(ctx, username) // var repo forgefed.Repository // repo = activity.Object repo, _ := repo_model.GetRepositoryByOwnerAndName(actor.Name, reponame) // hardcoded for now :( _, err = repo_service.ForkRepository(ctx, user, user, repo_service.ForkRepoOptions{BaseRepo: repo, Name: reponame, Description: "this is a remote fork"}) return err return activitypub.Send(user, &create) }
-
-
services/user/activitypub.go (deleted)
-
@@ -1,145 +0,0 @@// 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 user import ( "context" "errors" "strings" "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/setting" ap "github.com/go-ap/activitypub" ) // FollowUser marks someone be another's follower. func FollowUser(userID, followID int64) (err error) { if userID == followID || user_model.IsFollowing(userID, followID) { return nil } followUser, err := user_model.GetUserByID(followID) if err != nil { return err } if followUser.LoginType == auth.Federated { // Following remote user actorUser, err := user_model.GetUserByID(userID) if err != nil { return err } object := ap.PersonNew(ap.IRI(followUser.LoginName)) follow := ap.FollowNew("", object) follow.Type = ap.FollowType follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name)) follow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))} err = activitypub.Send(actorUser, follow) if err != nil { return err } } return user_model.FollowUser(userID, followID) } // UnfollowUser unmarks someone as another's follower. func UnfollowUser(userID, followID int64) (err error) { if userID == followID || !user_model.IsFollowing(userID, followID) { return nil } followUser, err := user_model.GetUserByID(followID) if err != nil { return err } if followUser.LoginType == auth.Federated { // Unfollowing remote user actorUser, err := user_model.GetUserByID(userID) if err != nil { return err } object := ap.PersonNew(ap.IRI(followUser.LoginName)) follow := ap.FollowNew("", object) follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name)) unfollow := ap.UndoNew("", follow) unfollow.Type = ap.UndoType unfollow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))} err = activitypub.Send(actorUser, unfollow) if err != nil { return err } } return user_model.UnfollowUser(userID, followID) } // Create a new federated user from a Person object func FederatedUserNew(ctx context.Context, person *ap.Person) error { name, err := activitypub.PersonIRIToName(person.GetLink()) if err != nil { return err } exists, err := user_model.IsUserExist(ctx, 0, name) if err != nil { return err } if exists { return nil } var email string if person.Location != nil { email = person.Location.GetLink().String() } else { // This might not even work email = strings.ReplaceAll(name, "@", "+") + "@" + setting.Service.NoReplyAddress } if person.PublicKey.PublicKeyPem == "" { return errors.New("person public key not found") } user := &user_model.User{ Name: name, FullName: person.Name.String(), // May not exist!! Email: email, LoginType: auth.Federated, LoginName: person.GetLink().String(), } err = user_model.CreateUser(user) if err != nil { return err } if person.Icon != nil { icon := person.Icon.(*ap.Image) iconURL, err := icon.URL.GetLink().URL() if err != nil { return err } body, err := activitypub.Fetch(iconURL) if err != nil { return err } err = UploadAvatar(user, body) if err != nil { return err } } err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, "") if err != nil { return err } return user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, person.PublicKey.PublicKeyPem) }
-
-
-
@@ -14,6 +14,7 @@ import ("code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" packages_model "code.gitea.io/gitea/models/packages"
-
@@ -26,6 +27,7 @@ import ("code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/activitypub" "code.gitea.io/gitea/services/packages" )
-
@@ -280,3 +282,45 @@ func DeleteAvatar(u *user_model.User) error {} return nil } // FollowUser marks someone be another's follower. func FollowUser(userID, followID int64) (err error) { if userID == followID || user_model.IsFollowing(userID, followID) { return nil } followUser, err := user_model.GetUserByID(followID) if err != nil { return } if followUser.LoginType == auth.Federated { // Following remote user err = activitypub.Follow(userID, followID) if err != nil { return } } return user_model.FollowUser(userID, followID) } // UnfollowUser unmarks someone as another's follower. func UnfollowUser(userID, followID int64) (err error) { if userID == followID || !user_model.IsFollowing(userID, followID) { return nil } followUser, err := user_model.GetUserByID(followID) if err != nil { return } if followUser.LoginType == auth.Federated { // Unfollowing remote user err = activitypub.Unfollow(userID, followID) if err != nil { return } } return user_model.UnfollowUser(userID, followID) }
-
-
-
@@ -13,9 +13,9 @@ import ("testing" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/activitypub" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" "github.com/stretchr/testify/assert"
-