From 955aeed8b589ed8a7e9b8bf11a5ef1fca5673be6 Mon Sep 17 00:00:00 2001 From: equa Date: Fri, 21 Jul 2023 16:20:38 -0400 Subject: [PATCH] Port old renameuser script and integrate it with towndb --- cmd/rename/main.go | 113 +++++++++++++++++++++++++++++++++++++++++++++ towndb/towndb.go | 26 +++++++++++ 2 files changed, 139 insertions(+) create mode 100644 cmd/rename/main.go diff --git a/cmd/rename/main.go b/cmd/rename/main.go new file mode 100644 index 0000000..0c7ae19 --- /dev/null +++ b/cmd/rename/main.go @@ -0,0 +1,113 @@ +package main + + +import ( + "bufio" + "fmt" + "path" + "os" + "os/exec" + + "git.tilde.town/tildetown/town/towndb" +) + +func confirmRename() { + fmt.Println("this will kill all of the user's current processes. if you're doing this live you should give them a good contact if things break") + + var text string + + for text != "y\n" { + fmt.Print("enter 'y' to continue: ") + reader := bufio.NewReader(os.Stdin) + text, _ = reader.ReadString('\n') + } +} + +func killUser(name string) (err error) { + cmd := exec.Command("pkill", "-SIGKILL", "-u", name) + cmd.Stderr = os.Stderr + + if err = cmd.Run(); err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + if exiterr.ExitCode() == 1 { + return nil + } + } + + return err + } + + return nil +} + +func usermod(old_name string, new_name string) (err error) { + cmd := exec.Command( + "usermod", + "-l", new_name, + "-m", + "-d", path.Join("/home", new_name), + old_name, + ) + cmd.Stderr = os.Stderr + + if err = cmd.Run(); err != nil { + return err + } + + cmd = exec.Command("groupmod", "-n", new_name, old_name) + cmd.Stderr = os.Stderr + + if err = cmd.Run(); err != nil { + return err + } + + return +} + +func renameDb(old_name string, new_name string) (err error) { + db, err := towndb.ConnectDB() + if err != nil { + return err + } + + err = towndb.RenameUser(db, old_name, new_name) + if err != nil { + return err + } + + return nil +} + +func quit(text string) { + fmt.Println(text) + os.Exit(1) +} + +func main() { + if len(os.Args) != 3 { + quit("usage: rename username new_username") + } + + confirmRename() + old_name := os.Args[1] + new_name := os.Args[2] + + if err := killUser(old_name); err != nil { + quit(fmt.Sprintf("pkill failed: %v", err)) + } + + fmt.Println("killed old processes") + + if err := usermod(old_name, new_name); err != nil { + quit(fmt.Sprintf("unix user rename failed: %v", err)) + } + + fmt.Println("renamed unix user") + + if err := renameDb(old_name, new_name); err != nil { + fmt.Println(fmt.Sprintf("couldn't rename user in /town/var/town.db: %v", err)) + fmt.Println("something might be amiss with town.db") + } else { + fmt.Println("renamed user in /town/var/town.db") + } +} diff --git a/towndb/towndb.go b/towndb/towndb.go index 52d073a..179c826 100644 --- a/towndb/towndb.go +++ b/towndb/towndb.go @@ -2,6 +2,7 @@ package towndb import ( "database/sql" + "fmt" "time" _ "github.com/mattn/go-sqlite3" @@ -142,6 +143,31 @@ func (u *TownUser) Insert(db *sql.DB) (err error) { return tx.Commit() } +// TODO: really we should have like GetUser or something. but i don't want +// to have to populate the struct to do this operation for now ~equa +func RenameUser(db *sql.DB, old_name string, new_name string) (err error) { + stmt, err := db.Prepare(`UPDATE users SET username = ? WHERE username = ?`) + if err != nil { + return err + } + + result, err := stmt.Exec(new_name, old_name) + if err != nil { + return err + } + + rows, err := result.RowsAffected() + if err != nil { + return err + } + + if rows == 0 { + return fmt.Errorf("couldn't find user") + } + + return nil +} + func ConnectDB() (*sql.DB, error) { db, err := sql.Open("sqlite3", dsn) if err != nil {