diff --git a/dashboard/app.go b/dashboard/app.go index 7dda3e8b..fa55b098 100644 --- a/dashboard/app.go +++ b/dashboard/app.go @@ -2,8 +2,12 @@ package main import ( "context" + "encoding/json" + "fmt" "log" "net/http" + "os" + "strings" "time" "github.com/gin-gonic/gin" @@ -13,9 +17,10 @@ type App struct { router *gin.Engine srv *http.Server bind string + ips []string } -func NewApp(htpasswd_file *string, baseURL string, bind string) App { +func NewApp(htpasswd_file *string, restrict_to_ips *string, baseURL string, bind string) App { gin.ForceConsoleColor() router := gin.Default() @@ -34,16 +39,58 @@ func NewApp(htpasswd_file *string, baseURL string, bind string) App { baserouter.Use(Htpassword(*htpasswd_file)) } - declareStaticRoutes(baserouter, baseURL) - app := App{ router: router, bind: bind, } + if restrict_to_ips != nil && len(*restrict_to_ips) > 0 { + var err error + app.ips, err = loadIPs(*restrict_to_ips) + if err != nil { + log.Fatal("Unable to parse ip restricting file: ", err) + } + baserouter.Use(app.Restrict2IPs) + } + + declareStaticRoutes(baserouter, baseURL) + return app } +func loadIPs(file string) ([]string, error) { + fd, err := os.Open(file) + if err != nil { + return nil, err + } + defer fd.Close() + + var ret []string + jdec := json.NewDecoder(fd) + + if err := jdec.Decode(&ret); err != nil { + return ret, err + } + + return ret, nil +} + +func (app *App) Restrict2IPs(c *gin.Context) { + found := false + for _, ip := range app.ips { + if strings.HasPrefix(c.Request.RemoteAddr, ip) { + found = true + break + } + } + + if found { + c.Next() + } else { + c.AbortWithError(http.StatusForbidden, fmt.Errorf("IP not authorized: %s", c.Request.RemoteAddr)) + } +} + func (app *App) Start() { app.srv = &http.Server{ Addr: app.bind, diff --git a/dashboard/main.go b/dashboard/main.go index 9a245ca5..f33272cb 100644 --- a/dashboard/main.go +++ b/dashboard/main.go @@ -70,6 +70,7 @@ func main() { // Read parameters from command line var bind = flag.String("bind", "127.0.0.1:8082", "Bind port/socket") htpasswd_file := flag.String("htpasswd", "", "Restrict access with password, Apache htpasswd format") + restrict_ip := flag.String("restrict-to-ips", "", "Restrict access to IP listed in this JSON array") flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL") staticDir := flag.String("static", "./htdocs-dashboard/", "Directory containing static files") flag.StringVar(&fic.FilesDir, "files", fic.FilesDir, "Base directory where found challenges files, local part") @@ -119,7 +120,7 @@ func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) - app := NewApp(htpasswd_file, baseURL, *bind) + app := NewApp(htpasswd_file, restrict_ip, baseURL, *bind) go app.Start() // Wait shutdown signal