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
}