feat: allow unlinking auth providers
This commit is contained in:
parent
8f6e280367
commit
b2bc608ec8
7 changed files with 201 additions and 4 deletions
|
@ -141,6 +141,28 @@ func (u *User) UpdateFromFedi(ctx context.Context, ex Execer, userID, username s
|
|||
return nil
|
||||
}
|
||||
|
||||
func (u *User) UnlinkFedi(ctx context.Context, ex Execer) error {
|
||||
sql, args, err := sq.Update("users").
|
||||
Set("fediverse", nil).
|
||||
Set("fediverse_username", nil).
|
||||
Set("fediverse_app_id", nil).
|
||||
Where("id = ?", u.ID).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "building sql")
|
||||
}
|
||||
|
||||
_, err = ex.Exec(ctx, sql, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "executing query")
|
||||
}
|
||||
|
||||
u.Fediverse = nil
|
||||
u.FediverseUsername = nil
|
||||
u.FediverseAppID = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiscordUser fetches a user by Discord user ID.
|
||||
func (db *DB) DiscordUser(ctx context.Context, discordID string) (u User, err error) {
|
||||
sql, args, err := sq.Select("*", "(SELECT instance FROM fediverse_apps WHERE id = users.fediverse_app_id) AS fediverse_instance").
|
||||
|
@ -182,6 +204,27 @@ func (u *User) UpdateFromDiscord(ctx context.Context, ex Execer, du *discordgo.U
|
|||
return nil
|
||||
}
|
||||
|
||||
func (u *User) UnlinkDiscord(ctx context.Context, ex Execer) error {
|
||||
sql, args, err := sq.Update("users").
|
||||
Set("discord", nil).
|
||||
Set("discord_username", nil).
|
||||
Where("id = ?", u.ID).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "building sql")
|
||||
}
|
||||
|
||||
_, err = ex.Exec(ctx, sql, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "executing query")
|
||||
}
|
||||
|
||||
u.Discord = nil
|
||||
u.DiscordUsername = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// User gets a user by ID.
|
||||
func (db *DB) User(ctx context.Context, id xid.ID) (u User, err error) {
|
||||
sql, args, err := sq.Select("*", "(SELECT instance FROM fediverse_apps WHERE id = users.fediverse_app_id) AS fediverse_instance").
|
||||
|
|
|
@ -203,6 +203,39 @@ func (s *Server) discordLink(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) discordUnlink(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
|
||||
claims, _ := server.ClaimsFromContext(ctx)
|
||||
|
||||
// only site tokens can be used for this endpoint
|
||||
if claims.APIToken || !claims.TokenWrite {
|
||||
return server.APIError{Code: server.ErrInvalidToken}
|
||||
}
|
||||
|
||||
u, err := s.DB.User(ctx, claims.UserID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
if u.Discord == nil {
|
||||
return server.APIError{Code: server.ErrNotLinked}
|
||||
}
|
||||
|
||||
err = u.UnlinkDiscord(ctx, s.DB)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "updating user in db")
|
||||
}
|
||||
|
||||
fields, err := s.DB.UserFields(ctx, u.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting user fields")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dbUserToUserResponse(u, fields))
|
||||
return nil
|
||||
}
|
||||
|
||||
type discordSignupRequest struct {
|
||||
Ticket string `json:"ticket"`
|
||||
Username string `json:"username"`
|
||||
|
|
|
@ -230,6 +230,39 @@ func (s *Server) mastodonLink(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) mastodonUnlink(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
|
||||
claims, _ := server.ClaimsFromContext(ctx)
|
||||
|
||||
// only site tokens can be used for this endpoint
|
||||
if claims.APIToken || !claims.TokenWrite {
|
||||
return server.APIError{Code: server.ErrInvalidToken}
|
||||
}
|
||||
|
||||
u, err := s.DB.User(ctx, claims.UserID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
if u.Fediverse == nil {
|
||||
return server.APIError{Code: server.ErrNotLinked}
|
||||
}
|
||||
|
||||
err = u.UnlinkFedi(ctx, s.DB)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "updating user in db")
|
||||
}
|
||||
|
||||
fields, err := s.DB.UserFields(ctx, u.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting user fields")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dbUserToUserResponse(u, fields))
|
||||
return nil
|
||||
}
|
||||
|
||||
type fediSignupRequest struct {
|
||||
Instance string `json:"instance"`
|
||||
Ticket string `json:"ticket"`
|
||||
|
|
|
@ -80,12 +80,15 @@ func Mount(srv *server.Server, r chi.Router) {
|
|||
r.Post("/signup", server.WrapHandler(s.discordSignup))
|
||||
// takes discord signup ticket to link to existing account
|
||||
r.With(server.MustAuth).Post("/add-provider", server.WrapHandler(s.discordLink))
|
||||
// removes discord link from existing account
|
||||
r.With(server.MustAuth).Post("/remove-provider", server.WrapHandler(s.discordUnlink))
|
||||
})
|
||||
|
||||
r.Route("/mastodon", func(r chi.Router) {
|
||||
r.Post("/callback", server.WrapHandler(s.mastodonCallback))
|
||||
r.Post("/signup", server.WrapHandler(s.mastodonSignup))
|
||||
r.With(server.MustAuth).Post("/add-provider", server.WrapHandler(s.mastodonLink))
|
||||
r.With(server.MustAuth).Post("/remove-provider", server.WrapHandler(s.mastodonUnlink))
|
||||
})
|
||||
|
||||
// invite routes
|
||||
|
|
|
@ -95,6 +95,7 @@ const (
|
|||
ErrRecentExport = 1012 // latest export is too recent
|
||||
ErrUnsupportedInstance = 1013 // unsupported fediverse software
|
||||
ErrAlreadyLinked = 1014 // user already has linked account of the same type
|
||||
ErrNotLinked = 1015 // user already doesn't have a linked account
|
||||
|
||||
// User-related error codes
|
||||
ErrUserNotFound = 2001
|
||||
|
@ -132,6 +133,7 @@ var errCodeMessages = map[int]string{
|
|||
ErrRecentExport: "Your latest data export is less than 1 day old",
|
||||
ErrUnsupportedInstance: "Unsupported instance software",
|
||||
ErrAlreadyLinked: "Your account is already linked to an account of this type",
|
||||
ErrNotLinked: "Your account is already not linked to an account of this type",
|
||||
|
||||
ErrUserNotFound: "User not found",
|
||||
|
||||
|
@ -166,6 +168,7 @@ var errCodeStatuses = map[int]int{
|
|||
ErrRecentExport: http.StatusBadRequest,
|
||||
ErrUnsupportedInstance: http.StatusBadRequest,
|
||||
ErrAlreadyLinked: http.StatusBadRequest,
|
||||
ErrNotLinked: http.StatusBadRequest,
|
||||
|
||||
ErrUserNotFound: http.StatusNotFound,
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue