From aed44d25665e076f2c6cc5a527bc8a3dbc0e7645 Mon Sep 17 00:00:00 2001 From: Jaz Volpert Date: Mon, 18 Sep 2023 18:25:44 +0000 Subject: [PATCH 1/3] Handle conflicts with handles, newer DIDs with valid handles invalidate existing DIDs with the same handle --- bgs/bgs.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/bgs/bgs.go b/bgs/bgs.go index 8b15218db..f44a15032 100644 --- a/bgs/bgs.go +++ b/bgs/bgs.go @@ -407,13 +407,14 @@ func (bgs *BGS) checkAdminAuth(next echo.HandlerFunc) echo.HandlerFunc { } type User struct { - ID models.Uid `gorm:"primarykey"` - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt gorm.DeletedAt `gorm:"index"` - Handle string `gorm:"uniqueIndex"` - Did string `gorm:"uniqueIndex"` - PDS uint + ID models.Uid `gorm:"primarykey"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` + Handle string `gorm:"uniqueIndex"` + Did string `gorm:"uniqueIndex"` + PDS uint + ValidHandle bool `gorm:"default:true"` // TakenDown is set to true if the user in question has been taken down. // A user in this state will have all future events related to it dropped @@ -992,7 +993,20 @@ func (s *BGS) createExternalUser(ctx context.Context, did string) (*models.Actor } if err := s.db.Create(&u).Error; err != nil { - // some debugging... + // If the new user's handle conflicts with an existing user, + // since we just validated the handle for this user, we'll assume + // the existing user no longer has control of the handle + if errors.Is(err, gorm.ErrDuplicatedKey) { + // Set the existing user's handle to NULL and set the valid_handle flag to false + if err := s.db.Model(User{}).Where("handle = ?", handle).Update("handle", nil).Update("valid_handle", false).Error; err != nil { + return nil, fmt.Errorf("failed to update outdated user's handle: %w", err) + } + + // Create the new user + if err := s.db.Create(&u).Error; err != nil { + return nil, fmt.Errorf("failed to create user after handle conflict: %w", err) + } + } return nil, fmt.Errorf("failed to create other pds user: %w", err) } From 6c2225e195bb36ec70dde543ff0c7acc5a15f9d3 Mon Sep 17 00:00:00 2001 From: Jaz Volpert Date: Mon, 18 Sep 2023 18:30:20 +0000 Subject: [PATCH 2/3] Handle ActorInfos too --- bgs/bgs.go | 15 ++++++++++++++- models/models.go | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bgs/bgs.go b/bgs/bgs.go index f44a15032..1231199d7 100644 --- a/bgs/bgs.go +++ b/bgs/bgs.go @@ -997,11 +997,24 @@ func (s *BGS) createExternalUser(ctx context.Context, did string) (*models.Actor // since we just validated the handle for this user, we'll assume // the existing user no longer has control of the handle if errors.Is(err, gorm.ErrDuplicatedKey) { + // Get the UID of the existing user + var existingUser User + if err := s.db.Find(&existingUser, "handle = ?", handle).Error; err != nil { + return nil, fmt.Errorf("failed to find existing user: %w", err) + } + // Set the existing user's handle to NULL and set the valid_handle flag to false - if err := s.db.Model(User{}).Where("handle = ?", handle).Update("handle", nil).Update("valid_handle", false).Error; err != nil { + if err := s.db.Model(User{}).Where("id = ?", existingUser.ID).Update("handle", nil).Update("valid_handle", false).Error; err != nil { return nil, fmt.Errorf("failed to update outdated user's handle: %w", err) } + // Do the same thing for the ActorInfo if it exists + if err := s.db.Model(models.ActorInfo{}).Where("uid = ?", existingUser.ID).Update("handle", nil).Update("valid_handle", false).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fmt.Errorf("failed to update outdated actorInfo's handle: %w", err) + } + } + // Create the new user if err := s.db.Create(&u).Error; err != nil { return nil, fmt.Errorf("failed to create user after handle conflict: %w", err) diff --git a/models/models.go b/models/models.go index 6eb56d277..d856980be 100644 --- a/models/models.go +++ b/models/models.go @@ -44,6 +44,7 @@ type ActorInfo struct { Posts int64 Type string PDS uint + ValidHandle bool `gorm:"default:true"` } func (ai *ActorInfo) ActorRef() *bsky.ActorDefs_ProfileViewBasic { From 054b8c4712eac1a3df0dae7538db4fdb7f458a51 Mon Sep 17 00:00:00 2001 From: Jaz Volpert Date: Mon, 18 Sep 2023 18:40:44 +0000 Subject: [PATCH 3/3] Dont't return an error if we resolved the conflict --- bgs/bgs.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgs/bgs.go b/bgs/bgs.go index 1231199d7..a90b8d238 100644 --- a/bgs/bgs.go +++ b/bgs/bgs.go @@ -1019,8 +1019,9 @@ func (s *BGS) createExternalUser(ctx context.Context, did string) (*models.Actor if err := s.db.Create(&u).Error; err != nil { return nil, fmt.Errorf("failed to create user after handle conflict: %w", err) } + } else { + return nil, fmt.Errorf("failed to create other pds user: %w", err) } - return nil, fmt.Errorf("failed to create other pds user: %w", err) } // okay cool, its a user on a server we are peered with