diff options
-rw-r--r-- | pkg/backend/webapi.go | 38 | ||||
-rw-r--r-- | pkg/bitmask/auth.go | 52 |
2 files changed, 86 insertions, 4 deletions
diff --git a/pkg/backend/webapi.go b/pkg/backend/webapi.go index e3918c5..a8844e8 100644 --- a/pkg/backend/webapi.go +++ b/pkg/backend/webapi.go @@ -4,8 +4,35 @@ import ( "fmt" "log" "net/http" + "os" + + "0xacab.org/leap/bitmask-vpn/pkg/bitmask" ) +func Adapt(h http.Handler, adapters ...Adapter) http.Handler { + for _, adapter := range adapters { + h = adapter(h) + } + return h +} + +type Adapter func(http.Handler) http.Handler + +func CheckAuth(token string) Adapter { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t := r.Header.Get("X-Auth-Token") + if t == token { + h.ServeHTTP(w, r) + } else { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("401 - Unauthorized")) + } + + }) + } +} + func webOn(w http.ResponseWriter, r *http.Request) { log.Println("Web UI: on") SwitchOn() @@ -24,12 +51,15 @@ func webStatus(w http.ResponseWriter, r *http.Request) { func webQuit(w http.ResponseWriter, r *http.Request) { log.Println("Web UI: quit") Quit() + os.Exit(0) } func enableWebAPI() { - http.HandleFunc("/vpn/start", webOn) - http.HandleFunc("/vpn/stop", webOff) - http.HandleFunc("/vpn/status", webStatus) - http.HandleFunc("/vpn/quit", webQuit) + bitmask.GenerateAuthToken() + auth := CheckAuth(bitmask.ReadAuthToken()) + http.Handle("/vpn/start", Adapt(http.HandlerFunc(webOn), auth)) + http.Handle("/vpn/stop", Adapt(http.HandlerFunc(webOff), auth)) + http.Handle("/vpn/status", Adapt(http.HandlerFunc(webStatus), auth)) + http.Handle("/vpn/quit", Adapt(http.HandlerFunc(webQuit), auth)) http.ListenAndServe(":8080", nil) } diff --git a/pkg/bitmask/auth.go b/pkg/bitmask/auth.go new file mode 100644 index 0000000..519eaf1 --- /dev/null +++ b/pkg/bitmask/auth.go @@ -0,0 +1,52 @@ +package bitmask + +import ( + "io/ioutil" + "log" + "math/rand" + "os" + "runtime" + "strings" + "time" +) + +/* functions for local authentication of control endpoints */ + +const tokenPath = "/dev/shm/bitmask-token" + +func GenerateAuthToken() { + if runtime.GOOS != "linux" { + log.Println("Authentication token only implemented in linux at the moment.") + return + } + t := getRandomString() + err := ioutil.WriteFile(tokenPath, []byte(t), os.FileMode(int(0600))) + if err != nil { + log.Println("Could not write authentication token.") + } +} + +func ReadAuthToken() string { + if runtime.GOOS != "linux" { + log.Println("Authentication token only implemented in linux at the moment.") + return "" + } + token, err := ioutil.ReadFile(tokenPath) + if err != nil { + log.Println("Error reading token:", err) + } + return string(token) +} + +func getRandomString() string { + rand.Seed(time.Now().UnixNano()) + chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz" + + "0123456789") + length := 40 + var b strings.Builder + for i := 0; i < length; i++ { + b.WriteRune(chars[rand.Intn(len(chars))]) + } + return b.String() +} |