From 0777ca0d2916e03a6007ffe389fd9039442d4ec4 Mon Sep 17 00:00:00 2001 From: gildarts Date: Fri, 24 Jun 2022 17:22:01 -0400 Subject: [PATCH] Add ability for a user to delete themselves Adds user self delete Adds confirmation of user deletion --- doc/soju.1.scd | 6 ++++-- service.go | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/doc/soju.1.scd b/doc/soju.1.scd index adf6f62..8c1dc70 100644 --- a/doc/soju.1.scd +++ b/doc/soju.1.scd @@ -437,8 +437,10 @@ abbreviated form, for instance *network* can be abbreviated as *net* or just user. - The _-admin_ flag is only valid when updating another user. -*user delete* - Delete a soju user. Only admins can delete accounts. +*user delete* [confirmation token] + Delete a soju user. + + Only admins can delete other users. *server status* Show some bouncer statistics. Only admins can query this information. diff --git a/service.go b/service.go index 29424c0..7cc110b 100644 --- a/service.go +++ b/service.go @@ -273,10 +273,9 @@ func init() { handle: handleUserUpdate, }, "delete": { - usage: "", + usage: " [confirmation token]", desc: "delete a user", handle: handleUserDelete, - admin: true, }, }, }, @@ -945,23 +944,49 @@ func handleUserUpdate(ctx context.Context, dc *downstreamConn, params []string) } func handleUserDelete(ctx context.Context, dc *downstreamConn, params []string) error { - if len(params) != 1 { - return fmt.Errorf("expected exactly one argument") + if len(params) != 1 && len(params) != 2 { + return fmt.Errorf("expected one or two arguments") } + username := params[0] + hashBytes := sha1.Sum([]byte(username)) + hash := fmt.Sprintf("%x", hashBytes[0:3]) + + self := dc.user.Username == username + + if !dc.user.Admin && !self { + return fmt.Errorf("only admins may delete other users") + } u := dc.srv.getUser(username) if u == nil { return fmt.Errorf("unknown username %q", username) } + if len(params) < 2 { + sendServicePRIVMSG(dc, fmt.Sprintf(`To confirm user deletion, send "user delete %s %s"`, username, hash)) + return nil + } + + if token := params[1]; token != hash { + return fmt.Errorf("provided confirmation token doesn't match user") + } + + if self { + sendServicePRIVMSG(dc, fmt.Sprintf("Goodbye %s, deleting your account. There will be no further confirmation.", username)) + ctx = context.TODO() + } + u.stop() if err := dc.srv.db.DeleteUser(ctx, u.ID); err != nil { return fmt.Errorf("failed to delete user: %v", err) } - sendServicePRIVMSG(dc, fmt.Sprintf("deleted user %q", username)) + if !self { + sendServicePRIVMSG(dc, fmt.Sprintf("deleted user %q", username)) + } + return nil }