/ cmd / cli.go
cli.go
  1  // SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2  //
  3  // SPDX-License-Identifier: Apache-2.0
  4  
  5  package main
  6  
  7  import (
  8  	"database/sql"
  9  	"fmt"
 10  	"os"
 11  	"syscall"
 12  
 13  	"git.sr.ht/~amolith/willow/users"
 14  	"github.com/microcosm-cc/bluemonday"
 15  	"golang.org/x/term"
 16  )
 17  
 18  var bmStrict = bluemonday.StrictPolicy()
 19  
 20  // createUser is a CLI that creates a new user with the specified username
 21  func createUser(dbConn *sql.DB, username string) {
 22  	fmt.Println("Creating user", username)
 23  
 24  	fmt.Print("Enter password: ")
 25  	password, err := term.ReadPassword(int(syscall.Stdin))
 26  	if err != nil {
 27  		fmt.Println("Error reading password:", err)
 28  		os.Exit(1)
 29  	}
 30  	fmt.Println()
 31  
 32  	fmt.Print("Confirm password: ")
 33  	passwordConfirmation, err := term.ReadPassword(int(syscall.Stdin))
 34  	if err != nil {
 35  		fmt.Println("Error reading password confirmation:", err)
 36  		os.Exit(1)
 37  	}
 38  	fmt.Println()
 39  
 40  	if string(password) != string(passwordConfirmation) {
 41  		fmt.Println("Passwords do not match")
 42  		os.Exit(1)
 43  	}
 44  
 45  	// Both frontend and backend need to sanitise the
 46  	// password the same way. This feel like a code
 47  	// smell; user creation should all be in the user
 48  	// package and the cli and frontend and API and
 49  	// everything should use that.
 50  	//
 51  	// TODO: Abstract this
 52  	sanitisedPassword := bmStrict.Sanitize(string(password))
 53  	err = users.Register(dbConn, username, sanitisedPassword)
 54  	if err != nil {
 55  		fmt.Println("Error creating user:", err)
 56  		os.Exit(1)
 57  	}
 58  
 59  	fmt.Println("\nUser", username, "created successfully")
 60  	os.Exit(0)
 61  }
 62  
 63  // deleteUser is a CLI that deletes a user with the specified username
 64  func deleteUser(dbConn *sql.DB, username string) {
 65  	fmt.Println("Deleting user", username)
 66  	err := users.Delete(dbConn, username)
 67  	if err != nil {
 68  		fmt.Println("Error deleting user:", err)
 69  		os.Exit(1)
 70  	}
 71  
 72  	fmt.Printf("User %s deleted successfully\n", username)
 73  	os.Exit(0)
 74  }
 75  
 76  // listUsers is a CLI that lists all users in the database
 77  func listUsers(dbConn *sql.DB) {
 78  	fmt.Println("Listing all users")
 79  
 80  	dbUsers, err := users.GetUsers(dbConn)
 81  	if err != nil {
 82  		fmt.Println("Error retrieving users from the database:", err)
 83  		os.Exit(1)
 84  	}
 85  
 86  	if len(dbUsers) == 0 {
 87  		fmt.Println("- No users found")
 88  	} else {
 89  		for _, u := range dbUsers {
 90  			fmt.Println("-", u)
 91  		}
 92  	}
 93  	os.Exit(0)
 94  }
 95  
 96  // checkAuthorised is a CLI that checks whether the provided user/password
 97  // combo is authorised.
 98  func checkAuthorised(dbConn *sql.DB, username string) {
 99  	fmt.Printf("Checking whether password for user %s is correct\n", username)
100  
101  	fmt.Print("Enter password: ")
102  	password, err := term.ReadPassword(int(syscall.Stdin))
103  	if err != nil {
104  		fmt.Println("Error reading password:", err)
105  		os.Exit(1)
106  	}
107  	fmt.Println()
108  
109  	// TODO: Abstract this, refer to note in createUser()
110  	sanitisedPassword := bmStrict.Sanitize(string(password))
111  	authorised, err := users.UserAuthorised(dbConn, username, sanitisedPassword)
112  	if err != nil {
113  		fmt.Println("Error checking authorisation:", err)
114  		os.Exit(1)
115  	}
116  
117  	if authorised {
118  		fmt.Println("User is authorised")
119  	} else {
120  		fmt.Println("User is not authorised")
121  	}
122  	os.Exit(0)
123  }