An atproto PDS written in Go

refactor: use a transaction for deleteAccount (#46)

This prevents a potential, although unlikely, issue where an account is left in an invalid state due to one or more delete operations failing. This would prevent a user from being able to delete their account on the network without manual intervention.

authored by Lyna and committed by GitHub 66a2e250 6ec2a2a5

Changed files
+29 -9
server
+29 -9
server/handle_server_delete_account.go
··· 66 66 }) 67 67 } 68 68 69 - if err := s.db.Exec("DELETE FROM blocks WHERE did = ?", nil, req.Did).Error; err != nil { 69 + tx := s.db.BeginDangerously() 70 + if tx.Error != nil { 71 + s.logger.Error("error starting transaction", "error", tx.Error) 72 + return helpers.ServerError(e, nil) 73 + } 74 + 75 + if err := tx.Exec("DELETE FROM blocks WHERE did = ?", nil, req.Did).Error; err != nil { 76 + tx.Rollback() 70 77 s.logger.Error("error deleting blocks", "error", err) 71 78 return helpers.ServerError(e, nil) 72 79 } 73 80 74 - if err := s.db.Exec("DELETE FROM records WHERE did = ?", nil, req.Did).Error; err != nil { 81 + if err := tx.Exec("DELETE FROM records WHERE did = ?", nil, req.Did).Error; err != nil { 82 + tx.Rollback() 75 83 s.logger.Error("error deleting records", "error", err) 76 84 return helpers.ServerError(e, nil) 77 85 } 78 86 79 - if err := s.db.Exec("DELETE FROM blobs WHERE did = ?", nil, req.Did).Error; err != nil { 87 + if err := tx.Exec("DELETE FROM blobs WHERE did = ?", nil, req.Did).Error; err != nil { 88 + tx.Rollback() 80 89 s.logger.Error("error deleting blobs", "error", err) 81 90 return helpers.ServerError(e, nil) 82 91 } 83 92 84 - if err := s.db.Exec("DELETE FROM tokens WHERE did = ?", nil, req.Did).Error; err != nil { 93 + if err := tx.Exec("DELETE FROM tokens WHERE did = ?", nil, req.Did).Error; err != nil { 94 + tx.Rollback() 85 95 s.logger.Error("error deleting tokens", "error", err) 86 96 return helpers.ServerError(e, nil) 87 97 } 88 98 89 - if err := s.db.Exec("DELETE FROM refresh_tokens WHERE did = ?", nil, req.Did).Error; err != nil { 99 + if err := tx.Exec("DELETE FROM refresh_tokens WHERE did = ?", nil, req.Did).Error; err != nil { 100 + tx.Rollback() 90 101 s.logger.Error("error deleting refresh tokens", "error", err) 91 102 return helpers.ServerError(e, nil) 92 103 } 93 104 94 - if err := s.db.Exec("DELETE FROM reserved_keys WHERE did = ?", nil, req.Did).Error; err != nil { 105 + if err := tx.Exec("DELETE FROM reserved_keys WHERE did = ?", nil, req.Did).Error; err != nil { 106 + tx.Rollback() 95 107 s.logger.Error("error deleting reserved keys", "error", err) 96 108 return helpers.ServerError(e, nil) 97 109 } 98 110 99 - if err := s.db.Exec("DELETE FROM invite_codes WHERE did = ?", nil, req.Did).Error; err != nil { 111 + if err := tx.Exec("DELETE FROM invite_codes WHERE did = ?", nil, req.Did).Error; err != nil { 112 + tx.Rollback() 100 113 s.logger.Error("error deleting invite codes", "error", err) 101 114 return helpers.ServerError(e, nil) 102 115 } 103 116 104 - if err := s.db.Exec("DELETE FROM actors WHERE did = ?", nil, req.Did).Error; err != nil { 117 + if err := tx.Exec("DELETE FROM actors WHERE did = ?", nil, req.Did).Error; err != nil { 118 + tx.Rollback() 105 119 s.logger.Error("error deleting actor", "error", err) 106 120 return helpers.ServerError(e, nil) 107 121 } 108 122 109 - if err := s.db.Exec("DELETE FROM repos WHERE did = ?", nil, req.Did).Error; err != nil { 123 + if err := tx.Exec("DELETE FROM repos WHERE did = ?", nil, req.Did).Error; err != nil { 124 + tx.Rollback() 110 125 s.logger.Error("error deleting repo", "error", err) 126 + return helpers.ServerError(e, nil) 127 + } 128 + 129 + if err := tx.Commit().Error; err != nil { 130 + s.logger.Error("error committing transaction", "error", err) 111 131 return helpers.ServerError(e, nil) 112 132 } 113 133