From c4dbe6328640f8ac43518a642e77dec061bfdd03 Mon Sep 17 00:00:00 2001 From: sanine-a Date: Wed, 10 May 2023 14:15:30 -0500 Subject: add hacky command parser --- conf/create.go | 81 ++++++++++++++++++++ conf/endpoint.go | 98 ------------------------- conf/endpoint.go.bak | 98 +++++++++++++++++++++++++ conf/list.go | 68 +++++++++++++++++ conf/main.go | 204 ++++++++++++++------------------------------------- conf/user.go | 127 -------------------------------- conf/user.go.bak | 127 ++++++++++++++++++++++++++++++++ db/db.go | 2 +- 8 files changed, 432 insertions(+), 373 deletions(-) create mode 100644 conf/create.go delete mode 100644 conf/endpoint.go create mode 100644 conf/endpoint.go.bak create mode 100644 conf/list.go delete mode 100644 conf/user.go create mode 100644 conf/user.go.bak diff --git a/conf/create.go b/conf/create.go new file mode 100644 index 0000000..ec732d2 --- /dev/null +++ b/conf/create.go @@ -0,0 +1,81 @@ +package main + + +import ( + "fmt" + "log" + "strings" + "syscall" + "golang.org/x/term" +) + + +func hiddenPrompt(prompt string) (string, error) { + fmt.Print(prompt) + bytes, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err + } + + return strings.TrimSpace(string(bytes)), nil +} + + +var createUser = &Command{ + Name: "user", + Execute: func(args []string) { + if len(args) < 1 { + fmt.Println("error: no username provided") + return; + } + username := args[0] + var password string + if len(args) == 1 { + password, err := hiddenPrompt("Enter password: ") + if err != nil { log.Fatal(err) } + confirm, err := hiddenPrompt("Confirm password: ") + if err != nil { log.Fatal(err) } + if password != confirm { + fmt.Println("passwords do not match!") + return + } + } else { + password = args[1] + } + + _, err := p.CreateUser(username, password) + if err != nil { log.Fatal(err) } + fmt.Printf("created user %v\n", username) + }, +} + + +var createEndpoint = &Command{ + Name: "endpoint", + Execute: func(args []string) { + if len(args) < 3 { + fmt.Println("error: name, URI, and address must be specified!") + return + } + + name := args[0] + path := args[1] + addr := args[2] + + _, err := p.CreateEndpoint(name, path, addr) + if err != nil { log.Fatal(err) } + fmt.Printf("created endpoint %v\n", name) + }, +} + + +func CreateInit(parser *Command) { + create := &Command{ + Name: "create", + Branch: true, + } + + create.AddCommand(createUser) + create.AddCommand(createEndpoint) + parser.AddCommand(create) +} diff --git a/conf/endpoint.go b/conf/endpoint.go deleted file mode 100644 index 1f8fa11..0000000 --- a/conf/endpoint.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "fmt" - "log" - db "sanine.net/git/phlox/db" -) - - -func CreateEndpoint() *Command { - return &Command{ - Flag: "create-endpoint", - Usage: "create a new endpoint", - Invoke: func() { - OpenDb() - - name := ReadLine("Endpoint Name: ") - path := ReadLine("Endpoint Path: ") - address := ReadLine("Endpoint Address: ") - _, err := p.CreateEndpoint(name, path, address) - if err != nil { log.Fatal(err) } - fmt.Printf("created endpoint %v\n", name) - }, - } -} - - -func GetEndpoint() db.Endpoint { - OpenDb() - name := ReadLine("Endpoint Name: ") - endpoint, err := p.GetEndpointByName(name) - if err != nil { log.Fatal(err) } - return endpoint -} - - -func DeleteEndpoint() *Command { - return &Command{ - Flag: "delete-endpoint", - Usage: "delete an existing endpoint", - Invoke: func() { - endpoint := GetEndpoint() - err := p.DeleteEndpoint(endpoint) - if err != nil { log.Fatal(err) } - fmt.Printf("deleted endpoint %v\n", endpoint.Name) - }, - } -} - - -func SetPath() *Command { - return &Command{ - Flag: "set-endpoint-path", - Usage: "set the path of an existing endpoint", - Invoke: func() { - endpoint := GetEndpoint() - fmt.Printf("Current Path: %v\n", endpoint.Path) - path := ReadLine("New Path: ") - err := p.SetEndpointPath(endpoint, path) - if err != nil { log.Fatal(err) } - fmt.Printf("updated path for endpoint %v\n", endpoint.Name) - }, - } -} - - -func SetAddress() *Command { - return &Command{ - Flag: "set-endpoint-address", - Usage: "set the address of an existing endpoint", - Invoke: func() { - endpoint := GetEndpoint() - fmt.Printf("Current Address: %v\n", endpoint.Address) - address := ReadLine("New Address: ") - err := p.SetEndpointAddress(endpoint, address) - if err != nil { log.Fatal(err) } - fmt.Printf("updated address for endpoint %v\n", endpoint.Name) - }, - } -} - - -func ListEndpoints() *Command { - return &Command{ - Flag: "list-endpoints", - Usage: "list all endpoints", - Invoke: func() { - OpenDb() - endpoints, err := p.AllEndpoints() - if err != nil { log.Fatal(err) } - fmt.Println("id\t\tname\t\tpath\t\taddress") - fmt.Println("================================================================================") - for _, endpoint := range endpoints { - fmt.Printf("%v\t\t%v\t\t%v\t\t%v\n", endpoint.Id, endpoint.Name, endpoint.Path, endpoint.Address) - } - }, - } -} diff --git a/conf/endpoint.go.bak b/conf/endpoint.go.bak new file mode 100644 index 0000000..1f8fa11 --- /dev/null +++ b/conf/endpoint.go.bak @@ -0,0 +1,98 @@ +package main + +import ( + "fmt" + "log" + db "sanine.net/git/phlox/db" +) + + +func CreateEndpoint() *Command { + return &Command{ + Flag: "create-endpoint", + Usage: "create a new endpoint", + Invoke: func() { + OpenDb() + + name := ReadLine("Endpoint Name: ") + path := ReadLine("Endpoint Path: ") + address := ReadLine("Endpoint Address: ") + _, err := p.CreateEndpoint(name, path, address) + if err != nil { log.Fatal(err) } + fmt.Printf("created endpoint %v\n", name) + }, + } +} + + +func GetEndpoint() db.Endpoint { + OpenDb() + name := ReadLine("Endpoint Name: ") + endpoint, err := p.GetEndpointByName(name) + if err != nil { log.Fatal(err) } + return endpoint +} + + +func DeleteEndpoint() *Command { + return &Command{ + Flag: "delete-endpoint", + Usage: "delete an existing endpoint", + Invoke: func() { + endpoint := GetEndpoint() + err := p.DeleteEndpoint(endpoint) + if err != nil { log.Fatal(err) } + fmt.Printf("deleted endpoint %v\n", endpoint.Name) + }, + } +} + + +func SetPath() *Command { + return &Command{ + Flag: "set-endpoint-path", + Usage: "set the path of an existing endpoint", + Invoke: func() { + endpoint := GetEndpoint() + fmt.Printf("Current Path: %v\n", endpoint.Path) + path := ReadLine("New Path: ") + err := p.SetEndpointPath(endpoint, path) + if err != nil { log.Fatal(err) } + fmt.Printf("updated path for endpoint %v\n", endpoint.Name) + }, + } +} + + +func SetAddress() *Command { + return &Command{ + Flag: "set-endpoint-address", + Usage: "set the address of an existing endpoint", + Invoke: func() { + endpoint := GetEndpoint() + fmt.Printf("Current Address: %v\n", endpoint.Address) + address := ReadLine("New Address: ") + err := p.SetEndpointAddress(endpoint, address) + if err != nil { log.Fatal(err) } + fmt.Printf("updated address for endpoint %v\n", endpoint.Name) + }, + } +} + + +func ListEndpoints() *Command { + return &Command{ + Flag: "list-endpoints", + Usage: "list all endpoints", + Invoke: func() { + OpenDb() + endpoints, err := p.AllEndpoints() + if err != nil { log.Fatal(err) } + fmt.Println("id\t\tname\t\tpath\t\taddress") + fmt.Println("================================================================================") + for _, endpoint := range endpoints { + fmt.Printf("%v\t\t%v\t\t%v\t\t%v\n", endpoint.Id, endpoint.Name, endpoint.Path, endpoint.Address) + } + }, + } +} diff --git a/conf/list.go b/conf/list.go new file mode 100644 index 0000000..bf3fd80 --- /dev/null +++ b/conf/list.go @@ -0,0 +1,68 @@ +package main + +import( + "fmt" + "log" + "time" +) + + +var listUsers = Command{ + Name: "users", + Execute: func([]string) { + users, err := p.AllUsers() + if err != nil { + log.Fatal(err) + } + fmt.Printf("id\tname\n========================================\n") + for _, user := range users { + fmt.Printf("%v\t%v\n", user.Id, user.Name) + } + }, +} + + +var listSessions = Command{ + Name: "sessions", + Execute: func([]string) { + sessions, err := p.AllSessions() + if err != nil { + log.Fatal(err) + } + fmt.Printf("id\tuser\tcreated\tmodified\n========================================\n") + for _, session := range sessions { + user, err := p.GetById(session.UserId) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%v\t%v\n", session.Id, user.Name, session.Created.Format(time.RFC3339), session.Modified.Format(time.RFC3339)) + } + }, +} + + +var listEndpoints = Command{ + Name: "endpoints", + Execute: func([]string) { + endpoints, err := p.AllEndpoints() + if err != nil { log.Fatal(err) } + + fmt.Printf("name\tpath\taddress\n========================================\n") + for _, endpoint := range endpoints { + fmt.Printf("%v\t%v\t%v\n", endpoint.Name, endpoint.Path, endpoint.Address) + } + }, +} + + +func ListInit(parser *Command) { + list := &Command{ + Name: "list", + Branch: true, + } + + list.AddCommand(&listUsers) + list.AddCommand(&listSessions) + list.AddCommand(&listEndpoints) + parser.AddCommand(list) +} diff --git a/conf/main.go b/conf/main.go index d0785f8..a768bac 100644 --- a/conf/main.go +++ b/conf/main.go @@ -5,181 +5,91 @@ import ( "fmt" "log" "flag" - "strings" - "bufio" +// "strings" +// "bufio" db "sanine.net/git/phlox/db" ) -var p *db.Phlox - - -type Params struct { - DbFilename string +var Params struct { + InitDb string + Db string } -var params Params -type Command struct { - Set bool - Value int - Flag string - Usage string - Invoke func() -} - - -func RegisterCommand(val int, cmd *Command) { - cmd.Value = val - flag.BoolVar(&(*cmd).Set, cmd.Flag, false, cmd.Usage) -} - +var p *db.Phlox -func OpenDb() { - err := p.Open(params.DbFilename) - if err != nil { log.Fatal(err) } +type Command struct { + Name string + Help string + subcommands map[string]*Command + Branch bool + Execute func([]string) } - -func ReadLine(prompt string) string { - reader := bufio.NewReader(os.Stdin) - - fmt.Print(prompt) - line, err := reader.ReadString('\n') - if err != nil { - log.Fatal(err) +func (c *Command) errNoSubCommand() { + fmt.Println("error: a subcommand was required but not provided.") + fmt.Println("available options are:\n") + for name := range c.subcommands { + fmt.Printf("\t* %v\n", name) } - - return strings.TrimSpace(line) + fmt.Println() } - -func main() { - p = &db.Phlox{} - - cmds := map[int]*Command{ - 1: Create(), - 2: SchemaVersion(), - - 3: CreateUser(), - 4: DeleteUser(), - 5: UpdatePassword(), - 6: ListUsers(), - - 7: CreateEndpoint(), - 8: DeleteEndpoint(), - 9: SetPath(), - 10: SetAddress(), - 11: ListEndpoints(), - - 12: SetHost(), - 13: GetHost(), - 14: SetLogin(), - 15: GetLogin(), - } - - for val, cmd := range cmds { - RegisterCommand(val, cmd) - } - - flag.StringVar(¶ms.DbFilename, "db", "phlox.conf", "select the db file to operate on") - flag.Parse() - - for _, cmd := range cmds { - if cmd.Set { cmd.Invoke(); os.Exit(0); } +func (c *Command) Parse(args []string) { + if !c.Branch { + c.Execute(args) + } else { + if len(args) > 0 { + cn, ok := c.subcommands[args[0]] + if ok { + cn.Parse(args[1:]) + } else { + c.errNoSubCommand() + } + } else { + c.errNoSubCommand() + } } - - log.Fatal("no command specified!") } -func Create() *Command { - return &Command{ - Flag: "create", - Usage: "create a new database", - Invoke: func() { - err := p.Create(params.DbFilename) - if err != nil { - log.Fatal(err) - } - fmt.Printf("created database %v\n", params.DbFilename) - }, +func (c *Command) AddCommand(cn *Command) { + if c.subcommands == nil { + c.subcommands = make(map[string]*Command) } + c.subcommands[cn.Name] = cn } -func SchemaVersion() *Command { - return &Command{ - Flag: "schema-version", - Usage: "get the schema version", - Invoke: func() { - err := p.Open(params.DbFilename) - if err != nil { log.Fatal(err) } - version, err := p.GetSchemaVersion() - if err != nil { log.Fatal(err) } - fmt.Printf("schema version: %v\n", version) - }, - } -} +var parser *Command -func SetHost() *Command { - return &Command{ - Flag: "set-host-address", - Usage: "set the address to serve the reverse proxy on", - Invoke: func() { - OpenDb() - defer p.Close() - address := ReadLine("Address: ") - err := p.SetHostAddress(address) - if err != nil { log.Fatal(err) } - fmt.Printf("set host address to %v\n", address) - }, - } -} +func main() { + p = &db.Phlox{} + flag.StringVar(&Params.InitDb, "init", "", "initialize a new database at the given path") + flag.StringVar(&Params.Db, "db", "/etc/phlox/phlox.conf", "open the database at the given path for processing") + flag.Parse() -func GetHost() *Command { - return &Command{ - Flag: "get-host-address", - Usage: "get the address to serve the reverse proxy on", - Invoke: func() { - OpenDb() - defer p.Close() - address, err := p.GetHostAddress() - if err != nil { log.Fatal(err) } - fmt.Printf("host address is %v\n", address) - }, + if Params.InitDb != "" { + // initialize a new db + err := p.Create(Params.InitDb) + if err != nil { log.Fatal(err) } + fmt.Printf("created new database at %v\n", Params.InitDb) + p.Close() + os.Exit(0) } -} - -func SetLogin() *Command { - return &Command{ - Flag: "set-login-page", - Usage: "set the file to serve as the login page", - Invoke: func() { - OpenDb() - defer p.Close() - path := ReadLine("File Path (blank for internal default): ") - err := p.SetLoginPage(path) - if err != nil { log.Fatal(err) } - fmt.Printf("set login page to %v\n", path) - }, + err := p.Open(Params.Db) + if err != nil { + log.Fatal(err) } -} + defer p.Close() + parser = &Command{Branch: true} + ListInit(parser) + CreateInit(parser) -func GetLogin() *Command { - return &Command{ - Flag: "get-login-page", - Usage: "get the file to serve the reverse proxy on", - Invoke: func() { - OpenDb() - defer p.Close() - path, err := p.GetLoginPage() - if err != nil { log.Fatal(err) } - fmt.Printf("login page is at %v\n", path) - }, - } + parser.Parse(flag.Args()) } diff --git a/conf/user.go b/conf/user.go deleted file mode 100644 index 5ceaefb..0000000 --- a/conf/user.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "os" - "fmt" - "log" - "strings" - "bufio" - "syscall" - "golang.org/x/term" - db "sanine.net/git/phlox/db" -) - - -func GetUsername(prompt string) (string, error) { - reader := bufio.NewReader(os.Stdin) - - fmt.Print(prompt) - username, err := reader.ReadString('\n') - if err != nil { - return "", err - } - - return strings.TrimSpace(username), nil -} - - -func GetPassword(prompt string) (string, error) { - fmt.Print(prompt) - bytes, err := term.ReadPassword(int(syscall.Stdin)) - if err != nil { - return "", err - } - - password := strings.TrimSpace(string(bytes)) - return password, nil -} - - -func ConfirmPassword() string { - password, err := GetPassword("Enter Password: ") - if err != nil { log.Fatal(err) } - fmt.Println() - password1, err := GetPassword("Confirm Password: ") - if err != nil { log.Fatal(err) } - fmt.Println() - if password != password1 { log.Fatal("passwords do not match!") } - return password -} - - -func GetUser() db.User { - OpenDb() - username, err := GetUsername("Username: ") - if err != nil { log.Fatal(err) } - user, err := p.GetByUsername(username) - if err != nil { log.Fatal(err) } - return user -} - - -func CreateUser() *Command { - return &Command{ - Flag: "create-user", - Usage: "create a new user", - Invoke: func() { - OpenDb() - - username, err := GetUsername("Enter Username: ") - if err != nil { log.Fatal(err) } - password := ConfirmPassword() - - _, err = p.CreateUser(username, password) - if err != nil { log.Fatal(err) } - fmt.Printf("created user %v\n", username) - }, - } -} - - -func DeleteUser() *Command { - return &Command{ - Flag: "delete-user", - Usage: "delete an existing user", - Invoke: func() { - user := GetUser() - err := p.DeleteUser(user) - if err != nil { log.Fatal(err) } - fmt.Printf("deleted user %v\n", user.Name) - }, - } -} - - -func UpdatePassword() *Command { - return &Command{ - Flag: "update-password", - Usage: "update a user's password", - Invoke: func() { - user := GetUser() - password := ConfirmPassword() - err := p.SetPassword(user, password) - if err != nil { log.Fatal(err) } - fmt.Printf("updated password for user %v\n", user.Name) - }, - } -} - - -func ListUsers() *Command { - return &Command{ - Flag: "list-users", - Usage: "list all users", - Invoke: func() { - OpenDb() - users, err := p.AllUsers() - if err != nil { log.Fatal(err) } - fmt.Println("id\t\tname") - fmt.Println("========================================") - for _, user := range users { - fmt.Printf( - "%v\t\t%v\n", user.Id, user.Name, - ) - } - }, - } -} diff --git a/conf/user.go.bak b/conf/user.go.bak new file mode 100644 index 0000000..5ceaefb --- /dev/null +++ b/conf/user.go.bak @@ -0,0 +1,127 @@ +package main + +import ( + "os" + "fmt" + "log" + "strings" + "bufio" + "syscall" + "golang.org/x/term" + db "sanine.net/git/phlox/db" +) + + +func GetUsername(prompt string) (string, error) { + reader := bufio.NewReader(os.Stdin) + + fmt.Print(prompt) + username, err := reader.ReadString('\n') + if err != nil { + return "", err + } + + return strings.TrimSpace(username), nil +} + + +func GetPassword(prompt string) (string, error) { + fmt.Print(prompt) + bytes, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err + } + + password := strings.TrimSpace(string(bytes)) + return password, nil +} + + +func ConfirmPassword() string { + password, err := GetPassword("Enter Password: ") + if err != nil { log.Fatal(err) } + fmt.Println() + password1, err := GetPassword("Confirm Password: ") + if err != nil { log.Fatal(err) } + fmt.Println() + if password != password1 { log.Fatal("passwords do not match!") } + return password +} + + +func GetUser() db.User { + OpenDb() + username, err := GetUsername("Username: ") + if err != nil { log.Fatal(err) } + user, err := p.GetByUsername(username) + if err != nil { log.Fatal(err) } + return user +} + + +func CreateUser() *Command { + return &Command{ + Flag: "create-user", + Usage: "create a new user", + Invoke: func() { + OpenDb() + + username, err := GetUsername("Enter Username: ") + if err != nil { log.Fatal(err) } + password := ConfirmPassword() + + _, err = p.CreateUser(username, password) + if err != nil { log.Fatal(err) } + fmt.Printf("created user %v\n", username) + }, + } +} + + +func DeleteUser() *Command { + return &Command{ + Flag: "delete-user", + Usage: "delete an existing user", + Invoke: func() { + user := GetUser() + err := p.DeleteUser(user) + if err != nil { log.Fatal(err) } + fmt.Printf("deleted user %v\n", user.Name) + }, + } +} + + +func UpdatePassword() *Command { + return &Command{ + Flag: "update-password", + Usage: "update a user's password", + Invoke: func() { + user := GetUser() + password := ConfirmPassword() + err := p.SetPassword(user, password) + if err != nil { log.Fatal(err) } + fmt.Printf("updated password for user %v\n", user.Name) + }, + } +} + + +func ListUsers() *Command { + return &Command{ + Flag: "list-users", + Usage: "list all users", + Invoke: func() { + OpenDb() + users, err := p.AllUsers() + if err != nil { log.Fatal(err) } + fmt.Println("id\t\tname") + fmt.Println("========================================") + for _, user := range users { + fmt.Printf( + "%v\t\t%v\n", user.Id, user.Name, + ) + } + }, + } +} diff --git a/db/db.go b/db/db.go index c58f6ad..55ef81b 100644 --- a/db/db.go +++ b/db/db.go @@ -119,7 +119,7 @@ func (p *Phlox) Create(filename string) error { insert into config values("hostaddress", "localhost:3333"); insert into config values("loginpage", ""); - create table users (userid integer not null primary key, username string, passwordhash string, salt string); + create table users (userid integer not null primary key, username string unique, passwordhash string, salt string); create table sessions (sessionid string not null primary key, userid integer, created string, modified string, foreign key(userid) references users(userid)); create table endpoints (endpointid integer not null primary key, name string, path string, address string); `) -- cgit v1.2.1