mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Filter UI requests through API
API is now the central control point for making authorized requests. The current architecture is: * db simply returns all data * api uses tokens to filter data from db. It includes methods for returning objects, and HTTP endpoints for return JSON. * ui calls the api functions to get filtered data.
This commit is contained in:
parent
df6daa5bbd
commit
cfcd781276
51
api.go
51
api.go
@ -10,20 +10,19 @@ import (
|
||||
|
||||
type Api struct {
|
||||
config *BoringProxyConfig
|
||||
db *Database
|
||||
auth *Auth
|
||||
tunMan *TunnelManager
|
||||
mux *http.ServeMux
|
||||
}
|
||||
|
||||
func NewApi(config *BoringProxyConfig, auth *Auth, tunMan *TunnelManager) *Api {
|
||||
|
||||
api := &Api{config, auth, tunMan, nil}
|
||||
func NewApi(config *BoringProxyConfig, db *Database, auth *Auth, tunMan *TunnelManager) *Api {
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
|
||||
api := &Api{config, db, auth, tunMan, mux}
|
||||
|
||||
api.mux = mux
|
||||
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
|
||||
|
||||
return api
|
||||
}
|
||||
@ -32,12 +31,48 @@ func (a *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
a.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (a *Api) GetTunnels(tokenData TokenData) map[string]Tunnel {
|
||||
|
||||
user, _ := a.db.GetUser(tokenData.Owner)
|
||||
|
||||
var tunnels map[string]Tunnel
|
||||
|
||||
if user.IsAdmin {
|
||||
tunnels = a.db.GetTunnels()
|
||||
} else {
|
||||
tunnels = make(map[string]Tunnel)
|
||||
|
||||
for domain, tun := range a.db.GetTunnels() {
|
||||
if tokenData.Owner == tun.Owner {
|
||||
tunnels[domain] = tun
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tunnels
|
||||
}
|
||||
|
||||
func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
token, err := extractToken("access_token", r)
|
||||
if err != nil {
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte("No token provided"))
|
||||
return
|
||||
}
|
||||
|
||||
tokenData, exists := a.db.GetTokenData(token)
|
||||
if !exists {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("Not authorized"))
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
query := r.URL.Query()
|
||||
|
||||
tunnels := a.tunMan.GetTunnels()
|
||||
tunnels := a.GetTunnels(tokenData)
|
||||
|
||||
if len(query["client-name"]) == 1 {
|
||||
clientName := query["client-name"][0]
|
||||
@ -62,9 +97,9 @@ func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Write([]byte(body))
|
||||
case "POST":
|
||||
a.validateToken(http.HandlerFunc(a.handleCreateTunnel)).ServeHTTP(w, r)
|
||||
a.handleCreateTunnel(w, r)
|
||||
case "DELETE":
|
||||
a.validateToken(http.HandlerFunc(a.handleDeleteTunnel)).ServeHTTP(w, r)
|
||||
a.handleDeleteTunnel(w, r)
|
||||
default:
|
||||
w.WriteHeader(405)
|
||||
w.Write([]byte("Invalid method for /tunnels"))
|
||||
|
@ -59,6 +59,8 @@ func Listen() {
|
||||
log.Println("Admin token: " + token)
|
||||
}
|
||||
|
||||
auth := NewAuth(db)
|
||||
|
||||
certmagic.DefaultACME.DisableHTTPChallenge = true
|
||||
//certmagic.DefaultACME.DisableTLSALPNChallenge = true
|
||||
//certmagic.DefaultACME.CA = certmagic.LetsEncryptStagingCA
|
||||
@ -72,17 +74,15 @@ func Listen() {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
auth := NewAuth(db)
|
||||
api := NewApi(config, db, auth, tunMan)
|
||||
http.Handle("/api/", http.StripPrefix("/api", api))
|
||||
|
||||
webUiHandler := NewWebUiHandler(config, db, auth, tunMan)
|
||||
webUiHandler := NewWebUiHandler(config, db, api, auth, tunMan)
|
||||
|
||||
httpClient := &http.Client{}
|
||||
|
||||
p := &BoringProxy{tunMan, httpClient}
|
||||
|
||||
api := NewApi(config, auth, tunMan)
|
||||
http.Handle("/api/", http.StripPrefix("/api", api))
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
GetCertificate: certConfig.GetCertificate,
|
||||
NextProtos: []string{"h2", "acme-tls/1"},
|
||||
|
3
todo.md
3
todo.md
@ -6,3 +6,6 @@
|
||||
after login and submitting a new tunnel too.
|
||||
* Save next port in db
|
||||
* On unknown page, redirect to referer if possible
|
||||
* Properly pick unused ports for tunnels
|
||||
* Apparently multiple tunnels can bind to a single server port. Looks like
|
||||
maybe only the first one is used to actually tunnel to the clients?
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
type WebUiHandler struct {
|
||||
config *BoringProxyConfig
|
||||
db *Database
|
||||
api *Api
|
||||
auth *Auth
|
||||
tunMan *TunnelManager
|
||||
box *rice.Box
|
||||
@ -66,10 +67,11 @@ type TokensData struct {
|
||||
Users map[string]User
|
||||
}
|
||||
|
||||
func NewWebUiHandler(config *BoringProxyConfig, db *Database, auth *Auth, tunMan *TunnelManager) *WebUiHandler {
|
||||
func NewWebUiHandler(config *BoringProxyConfig, db *Database, api *Api, auth *Auth, tunMan *TunnelManager) *WebUiHandler {
|
||||
return &WebUiHandler{
|
||||
config: config,
|
||||
db: db,
|
||||
api: api,
|
||||
auth: auth,
|
||||
tunMan: tunMan,
|
||||
}
|
||||
@ -185,24 +187,10 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
var tunnels map[string]Tunnel
|
||||
|
||||
if user.IsAdmin {
|
||||
tunnels = h.db.GetTunnels()
|
||||
} else {
|
||||
tunnels = make(map[string]Tunnel)
|
||||
|
||||
for domain, tun := range h.db.GetTunnels() {
|
||||
if tokenData.Owner == tun.Owner {
|
||||
tunnels[domain] = tun
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
indexData := IndexData{
|
||||
Head: h.headHtml,
|
||||
Menu: h.menuHtml,
|
||||
Tunnels: tunnels,
|
||||
Tunnels: h.api.GetTunnels(tokenData),
|
||||
}
|
||||
|
||||
tmpl.Execute(w, indexData)
|
||||
|
Loading…
Reference in New Issue
Block a user