Changes
10 changed files (+101/-110)
-
-
@@ -9,6 +9,7 @@ "context""crypto/sha256" "crypto/subtle" "encoding/hex" "errors" "fmt" "net/url" "os"
-
@@ -1024,6 +1025,29 @@ if err != nil {return nil, err } else if !has { return nil, ErrUserNotExist{0, name, 0} } return u, nil } // GetUserByIRI returns user by given IRI. func GetUserByIRI(ctx context.Context, iri string) (*User, error) { if len(iri) == 0 { return nil, ErrUserNotExist{0, iri, 0} } iriSplit := strings.Split(iri, "/") if len(iriSplit) < 4 { return nil, errors.New("not a Person actor IRI") } if iriSplit[2] == setting.Domain { // Local user return GetUserByName(ctx, iriSplit[len(iriSplit)-1]) } u := &User{LoginName: iri} has, err := db.GetEngine(ctx).Get(u) if err != nil { return nil, err } else if !has { return nil, ErrUserNotExist{0, iri, 0} } return u, nil }
-
-
-
@@ -8,6 +8,7 @@ "net/http""net/url" "strconv" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/setting"
-
@@ -51,12 +52,12 @@ if err != nil {ctx.ServerError("FederatedUserNew", err) return } name, err := activitypub.PersonIRIToName(object.GetLink()) user, err := user_model.GetUserByIRI(ctx, object.GetLink().String()) if err != nil { ctx.ServerError("PersonIRIToName", err) ctx.ServerError("GetUserByIRI", err) return } ctx.Redirect(setting.AppURL + name) ctx.Redirect(setting.AppURL + user.Name) case forgefed.RepositoryType: // Federated repository err = forgefed.OnRepository(object, func(r *forgefed.Repository) error {
-
-
-
@@ -5,6 +5,7 @@ package activitypubimport ( "context" "encoding/json" "errors" "net/url" "strconv"
-
@@ -26,20 +27,46 @@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()) _, err := user_model.GetUserByIRI(ctx, person.GetLink().String()) if user_model.IsErrUserNotExist(err) { // User already exists return err } personIRISplit := strings.Split(person.GetLink().String(), "/") if len(personIRISplit) < 4 { return errors.New("not a Person actor IRI") } // Get instance by taking the domain of the IRI instance := personIRISplit[2] if instance == setting.Domain { // Local user return nil } // Send a WebFinger request to get the username uri, err := url.Parse("https://" + instance + "/.well-known/webfinger?resource=" + person.GetLink().String()) if err != nil { return err } resp, err := activitypub.Fetch(uri) if err != nil { return err } exists, err := user_model.IsUserExist(ctx, 0, name) var data activitypub.WebfingerJRD err = json.Unmarshal(resp, &data) if err != nil { return err } if exists { return nil subjectSplit := strings.Split(data.Subject, ":") if subjectSplit[0] != "acct" { return errors.New("subject is not an acct URI") } name := subjectSplit[1] var email string if person.Location != nil {
-
@@ -55,7 +82,6 @@ }user := &user_model.User{ Name: name, FullName: person.Name.String(), // May not exist!! Email: email, LoginType: auth.Federated, LoginName: person.GetLink().String(),
-
@@ -66,7 +92,11 @@ if err != nil {return err } if person.Name != nil { user.FullName = person.Name.String() } if person.Icon != nil { // Fetch and save user icon icon, err := ap.ToObject(person.Icon) if err != nil { return err
-
@@ -75,12 +105,10 @@ 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
-
@@ -91,44 +119,13 @@ err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, "")if err != nil { return err } // Set public key return user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, person.PublicKey.PublicKeyPem) } func createPersonFromIRI(ctx context.Context, personIRI ap.IRI) error { ownerURL, err := url.Parse(personIRI.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 person, err := ap.ToActor(object) if err != nil { return err } return createPerson(ctx, person) } // Create a new federated repo from a Repository object func createRepository(ctx context.Context, repository *forgefed.Repository) error { err := createPersonFromIRI(ctx, repository.AttributedTo.GetLink()) if err != nil { return err } user, err := activitypub.PersonIRIToUser(ctx, repository.AttributedTo.GetLink()) user, err := user_model.GetUserByIRI(ctx, repository.AttributedTo.GetLink().String()) if err != nil { return err }
-
@@ -200,7 +197,7 @@ return err} // Construct issue user, err := activitypub.PersonIRIToUser(ctx, ap.IRI(ticket.AttributedTo.GetLink().String())) user, err := user_model.GetUserByIRI(ctx, ticket.AttributedTo.GetLink().String()) if err != nil { return err }
-
@@ -233,7 +230,7 @@ if err != nil {return err } user, err := activitypub.PersonIRIToUser(ctx, ticket.AttributedTo.GetLink()) user, err := user_model.GetUserByIRI(ctx, ticket.AttributedTo.GetLink().String()) if err != nil { return err }
-
@@ -285,12 +282,7 @@ }// Create a comment func createComment(ctx context.Context, note *ap.Note) error { err := createPersonFromIRI(ctx, note.AttributedTo.GetLink()) if err != nil { return err } user, err := activitypub.PersonIRIToUser(ctx, note.AttributedTo.GetLink()) user, err := user_model.GetUserByIRI(ctx, note.AttributedTo.GetLink().String()) if err != nil { return err }
-
-
-
@@ -6,8 +6,8 @@import ( "context" user_model "code.gitea.io/gitea/models/user" user_service "code.gitea.io/gitea/services/user" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub" )
-
@@ -20,9 +20,9 @@ // Make sure actor matches the object getting deletedif actorIRI != objectIRI { return nil } // Object is the user getting deleted objectUser, err := activitypub.PersonIRIToUser(ctx, objectIRI) objectUser, err := user_model.GetUserByIRI(ctx, objectIRI.String()) if err != nil { return err }
-
-
-
@@ -18,14 +18,14 @@ // Process an incoming Follow activityfunc follow(ctx context.Context, follow ap.Follow) error { // Actor is the user performing the follow actorIRI := follow.Actor.GetLink() actorUser, err := activitypub.PersonIRIToUser(ctx, actorIRI) actorUser, err := user_model.GetUserByIRI(ctx, actorIRI.String()) if err != nil { return err } // Object is the user being followed objectIRI := follow.Object.GetLink() objectUser, err := activitypub.PersonIRIToUser(ctx, objectIRI) objectUser, err := user_model.GetUserByIRI(ctx, objectIRI.String()) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { return err
-
@@ -54,14 +54,14 @@ }// Actor is the user performing the undo follow actorIRI := follow.Actor.GetLink() actorUser, err := activitypub.PersonIRIToUser(ctx, actorIRI) actorUser, err := user_model.GetUserByIRI(ctx, actorIRI.String()) if err != nil { return err } // Object is the user being unfollowed objectIRI := follow.Object.GetLink() objectUser, err := activitypub.PersonIRIToUser(ctx, objectIRI) objectUser, err := user_model.GetUserByIRI(ctx, objectIRI.String()) // Must be a local user if err != nil || strings.Contains(objectUser.Name, "@") { return err
-
-
-
@@ -78,8 +78,6 @@ if !authenticated {return } // 4. Create a federated user for the actor // TODO: This is a very bad place for creating federated users // We end up creating way more users than necessary! var person ap.Person err = person.UnmarshalJSON(b) if err != nil {
-
-
-
@@ -9,6 +9,7 @@ "errors""strings" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/activitypub" ap "github.com/go-ap/activitypub"
-
@@ -16,7 +17,7 @@ )// Process a Like activity to star a repository func star(ctx context.Context, like ap.Like) (err error) { user, err := activitypub.PersonIRIToUser(ctx, like.Actor.GetLink()) user, err := user_model.GetUserByIRI(ctx, like.Actor.GetLink().String()) if err != nil { return }
-
@@ -33,7 +34,7 @@ like, ok := unlike.Object.(*ap.Like)if !ok { return errors.New("could not cast object to like") } user, err := activitypub.PersonIRIToUser(ctx, like.Actor.GetLink()) user, err := user_model.GetUserByIRI(ctx, like.Actor.GetLink().String()) if err != nil { return }
-
-
-
@@ -13,26 +13,11 @@ user_model "code.gitea.io/gitea/models/user""code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/activitypub" ) // https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-webfinger-14#section-4.4 type webfingerJRD struct { Subject string `json:"subject,omitempty"` Aliases []string `json:"aliases,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"` Links []*webfingerLink `json:"links,omitempty"` } type webfingerLink struct { Rel string `json:"rel,omitempty"` Type string `json:"type,omitempty"` Href string `json:"href,omitempty"` Template string `json:"template,omitempty"` Titles map[string]string `json:"titles,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"` } // WebfingerQuery returns information about a resource // https://datatracker.ietf.org/doc/html/rfc7565 func WebfingerQuery(ctx *context.Context) {
-
@@ -65,6 +50,8 @@ u, err = user_model.GetUserByEmailContext(ctx, resource.Opaque)if u != nil && u.KeepEmailPrivate { err = user_model.ErrUserNotExist{} } case "https": u, err = user_model.GetUserByIRI(ctx, ctx.FormString("resource")) default: ctx.Error(http.StatusBadRequest) return
-
@@ -92,7 +79,7 @@ if !u.KeepEmailPrivate {aliases = append(aliases, fmt.Sprintf("mailto:%s", u.Email)) } links := []*webfingerLink{ links := []*activitypub.WebfingerLink{ { Rel: "http://webfinger.net/rel/profile-page", Type: "text/html",
-
@@ -114,7 +101,7 @@ },} ctx.Resp.Header().Add("Access-Control-Allow-Origin", "*") ctx.JSON(http.StatusOK, &webfingerJRD{ ctx.JSON(http.StatusOK, &activitypub.WebfingerJRD{ Subject: fmt.Sprintf("acct:%s@%s", url.QueryEscape(u.Name), appURL.Host), Aliases: aliases, Links: links,
-
-
-
@@ -9,39 +9,10 @@ "strconv""strings" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" ap "github.com/go-ap/activitypub" ) // Returns the username corresponding to a Person actor IRI func PersonIRIToName(personIRI ap.IRI) (string, error) { personIRISplit := strings.Split(personIRI.String(), "/") if len(personIRISplit) < 4 { return "", errors.New("not a Person actor IRI") } instance := personIRISplit[2] name := personIRISplit[len(personIRISplit)-1] if instance == setting.Domain { // Local user return name, nil } // Remote user // Get name in username@instance.com format return name + "@" + instance, nil } // Returns the user corresponding to a Person actor IRI func PersonIRIToUser(ctx context.Context, personIRI ap.IRI) (*user_model.User, error) { name, err := PersonIRIToName(personIRI) if err != nil { return nil, err } return user_model.GetUserByName(ctx, name) } // Returns the owner and name corresponding to a Repository actor IRI func RepositoryIRIToName(repoIRI ap.IRI) (string, string, error) {
-
-
-
@@ -0,0 +1,17 @@package activitypub; type WebfingerJRD struct { Subject string `json:"subject,omitempty"` Aliases []string `json:"aliases,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"` Links []*WebfingerLink `json:"links,omitempty"` } type WebfingerLink struct { Rel string `json:"rel,omitempty"` Type string `json:"type,omitempty"` Href string `json:"href,omitempty"` Template string `json:"template,omitempty"` Titles map[string]string `json:"titles,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"` }
-