diff --git a/database.go b/database.go index e8f046a..5a53fd8 100644 --- a/database.go +++ b/database.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "io/ioutil" "log" "sync" @@ -10,6 +11,7 @@ import ( type Database struct { Tokens map[string]TokenData `json:"tokens"` Tunnels map[string]Tunnel `json:"tunnels"` + Users map[string]User `json:"users"` mutex *sync.Mutex } @@ -56,6 +58,10 @@ func NewDatabase() (*Database, error) { db.Tunnels = make(map[string]Tunnel) } + if db.Users == nil { + db.Users = make(map[string]User) + } + db.mutex = &sync.Mutex{} db.mutex.Lock() @@ -129,6 +135,38 @@ func (d *Database) DeleteTunnel(domain string) { d.persist() } +func (d *Database) GetUsers() map[string]User { + d.mutex.Lock() + defer d.mutex.Unlock() + + users := make(map[string]User) + + for k, v := range d.Users { + users[k] = v + } + + return users +} + +func (d *Database) AddUser(username string, isAdmin bool) error { + d.mutex.Lock() + defer d.mutex.Unlock() + + _, exists := d.Users[username] + + if exists { + return errors.New("User exists") + } + + d.Users[username] = User{ + isAdmin, + } + + d.persist() + + return nil +} + func (d *Database) persist() { saveJson(d, "boringproxy_db.json") } diff --git a/webui/users.tmpl b/webui/users.tmpl new file mode 100644 index 0000000..4512cdf --- /dev/null +++ b/webui/users.tmpl @@ -0,0 +1,33 @@ + + + + {{.Head}} + + + +
+ + + +
+ {{range $username, $user := .Users}} +
+ {{$username}} +
+ {{end}} +
+
+
+ + + + + +
+
+
+ + diff --git a/webui_handler.go b/webui_handler.go index 17ca091..f7cd210 100644 --- a/webui_handler.go +++ b/webui_handler.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "github.com/GeertJohan/go.rice" "html/template" @@ -40,6 +41,11 @@ type HeadData struct { Styles template.CSS } +type UsersData struct { + Head template.HTML + Users map[string]User +} + func NewWebUiHandler(config *BoringProxyConfig, db *Database, auth *Auth, tunMan *TunnelManager) *WebUiHandler { return &WebUiHandler{ config: config, @@ -303,4 +309,53 @@ func (h *WebUiHandler) sendLoginPage(w http.ResponseWriter, r *http.Request, cod } func (h *WebUiHandler) users(w http.ResponseWriter, r *http.Request) { + + if r.Method == "POST" { + r.ParseForm() + + if len(r.Form["username"]) != 1 { + w.WriteHeader(400) + w.Write([]byte("Invalid username parameter")) + return + } + username := r.Form["username"][0] + + isAdmin := len(r.Form["is-admin"]) == 1 && r.Form["is-admin"][0] == "on" + + err := h.db.AddUser(username, isAdmin) + if err != nil { + w.WriteHeader(500) + io.WriteString(w, err.Error()) + return + } + + http.Redirect(w, r, "/users", 303) + } + + tmpl, err := h.loadTemplate("users.tmpl") + if err != nil { + w.WriteHeader(500) + io.WriteString(w, err.Error()) + return + } + + tmpl.Execute(w, UsersData{ + Head: h.headHtml, + Users: h.db.GetUsers(), + }) +} + +func (h *WebUiHandler) loadTemplate(name string) (*template.Template, error) { + + tmplStr, err := h.box.String(name) + if err != nil { + return nil, errors.New("Error reading template " + name) + } + + tmpl, err := template.New(name).Parse(tmplStr) + if err != nil { + return nil, errors.New("Error compiling template " + name) + } + + return tmpl, nil }