package main import ( "flag" "log" "net/http" "net/url" "os" "os/signal" "path" "strings" "syscall" ) var baseURL string = "/" type ResponseWriterPrefix struct { real http.ResponseWriter prefix string } func (r ResponseWriterPrefix) Header() http.Header { return r.real.Header() } func (r ResponseWriterPrefix) WriteHeader(s int) { if v, exists := r.real.Header()["Location"]; exists && len(v) > 0 && !strings.HasPrefix(v[0], "https://") && !strings.HasPrefix(v[0], "http://") { r.real.Header().Set("Location", r.prefix+v[0]) } r.real.WriteHeader(s) } func (r ResponseWriterPrefix) Write(z []byte) (int, error) { return r.real.Write(z) } func StripPrefix(prefix string, h http.Handler) http.Handler { if prefix == "" { return h } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if prefix != "/" && r.URL.Path == "/" { http.Redirect(w, r, prefix+"/", http.StatusFound) } else if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) { r2 := new(http.Request) *r2 = *r r2.URL = new(url.URL) *r2.URL = *r.URL r2.URL.Path = p h.ServeHTTP(ResponseWriterPrefix{w, prefix}, r2) } else { h.ServeHTTP(w, r) } }) } func main() { var bind = flag.String("bind", ":8081", "Bind port/socket") var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server") var dummyauth = flag.Bool("dummy-auth", false, "If set, allow any authentication credentials") flag.StringVar(&mainBanner, "banner-message", mainBanner, "Display a message to connected user, at the top of the screen") flag.StringVar(&DevProxy, "dev", DevProxy, "Proxify traffic to this host for static assets") flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL") flag.UintVar(¤tPromo, "current-promo", currentPromo, "Year of the current promotion") flag.UintVar(&OffsetQuestionTimer, "offset-question-timer", OffsetQuestionTimer, "Duration to wait before sending pause msg in direct mode (in milliseconds)") flag.BoolVar(&allowLocalAuth, "allow-local-auth", false, "Allow local authentication for all users (bypass OIDC).") flag.Var(&localAuthUsers, "local-auth-user", "Allow local authentication for this user (bypass OIDC).") flag.Parse() // Sanitize options var err error log.Println("Checking paths...") if err = sanitizeStaticOptions(); err != nil { log.Fatal(err) } if baseURL != "/" { baseURL = path.Clean(baseURL) } else { baseURL = "" } if dummyauth != nil && *dummyauth == true { LocalAuthFunc = dummyAuth } // Initialize contents log.Println("Opening database...") if err := DBInit(*dsn); err != nil { log.Fatal("Cannot open the database: ", err) } defer DBClose() log.Println("Creating database...") if err := DBCreate(); err != nil { log.Fatal("Cannot create database: ", err) } a := NewApp() go a.Start(*bind) initializeOIDC(a.router) initializeDroneOauth() // Prepare graceful shutdown interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) // Wait shutdown signal <-interrupt log.Print("The service is shutting down...") a.Stop() if gitlabToken != nil { saveOAuth2Token(OAUTH_GITLAB_FILE, gitlabToken()) } log.Println("done") }