You need to create an admin account for managing this instance of\n", - "LabCA. There can only be one admin account, but you can configure all its attributes once the\n", - "initial setup has completed.
")) - } else if stage == "setup" { - return template.HTML(fmt.Sprint("The fully qualified domain name (FQDN) is what end users will use\n", - "to connect to this server. It was provided in the initial setup and is shown here for reference.
\n", - "Please fill in a DNS server (and optionally port, default is ':53') that will be used to lookup\n", - "the domains for which a certificate is requested.
\n", - "LabCA is primarily intended for use inside an organization where all domains end in the same\n", - "domain, e.g. '.localdomain'. In lockdown mode only those domains are allowed. In whitelist mode\n", - "those domains are allowed next to all official, internet accessible domains and in standard\n", - "mode only the official domains are allowed.
")) - } else if stage == "root-ca" { - return template.HTML(fmt.Sprint("This is the top level certificate that will sign the issuer\n", - "certificate(s). You can either generate a fresh Root CA (Certificate Authority) or import an\n", - "existing one, e.g. a backup from another LabCA instance.
\n", - "If you want to generate a certificate, pick a key type and strength (the higher the number the\n", - "more secure, ECDSA is more modern than RSA), provide at least a country and organization name,\n", - "and the common name. It is recommended that the common name contains the word 'Root' as well\n", - "as your organization name so you can recognize it, and that's why that is automatically filled\n", - "once you leave the organization field.
")) - } else if stage == "ca-int" { - return template.HTML(fmt.Sprint("This is what end users will see as the issuing certificate. Again,\n", - "you can either generate a fresh certificate or import an existing one, as long as it is signed by\n", - "the Root CA from the previous step.
\n", - "If you want to generate a certificate, by default the same key type and strength is selected as\n", - "was choosen in the previous step when generating the root, but you may choose a different one. By\n", - "default the common name is the same as the CN for the Root CA, minus the word 'Root'.
")) - } else { - return template.HTML("") - } + if stage == "register" { + return template.HTML(fmt.Sprint("You need to create an admin account for managing this instance of\n", + "LabCA. There can only be one admin account, but you can configure all its attributes once the\n", + "initial setup has completed.
")) + } else if stage == "setup" { + return template.HTML(fmt.Sprint("The fully qualified domain name (FQDN) is what end users will use\n", + "to connect to this server. It was provided in the initial setup and is shown here for reference.
\n", + "Please fill in a DNS server (and optionally port, default is ':53') that will be used to lookup\n", + "the domains for which a certificate is requested.
\n", + "LabCA is primarily intended for use inside an organization where all domains end in the same\n", + "domain, e.g. '.localdomain'. In lockdown mode only those domains are allowed. In whitelist mode\n", + "those domains are allowed next to all official, internet accessible domains and in standard\n", + "mode only the official domains are allowed.
")) + } else if stage == "root-ca" { + return template.HTML(fmt.Sprint("This is the top level certificate that will sign the issuer\n", + "certificate(s). You can either generate a fresh Root CA (Certificate Authority) or import an\n", + "existing one, e.g. a backup from another LabCA instance.
\n", + "If you want to generate a certificate, pick a key type and strength (the higher the number the\n", + "more secure, ECDSA is more modern than RSA), provide at least a country and organization name,\n", + "and the common name. It is recommended that the common name contains the word 'Root' as well\n", + "as your organization name so you can recognize it, and that's why that is automatically filled\n", + "once you leave the organization field.
")) + } else if stage == "ca-int" { + return template.HTML(fmt.Sprint("This is what end users will see as the issuing certificate. Again,\n", + "you can either generate a fresh certificate or import an existing one, as long as it is signed by\n", + "the Root CA from the previous step.
\n", + "If you want to generate a certificate, by default the same key type and strength is selected as\n", + "was choosen in the previous step when generating the root, but you may choose a different one. By\n", + "default the common name is the same as the CN for the Root CA, minus the word 'Root'.
")) + } else { + return template.HTML("") + } } func setupHandler(w http.ResponseWriter, r *http.Request) { - if viper.GetBool("config.complete") == true { - render(w, r, "index:manage", map[string]interface{}{"Message": template.HTML("Setup already completed! Go home")}) - return - } + if viper.GetBool("config.complete") == true { + render(w, r, "index:manage", map[string]interface{}{"Message": template.HTML("Setup already completed! Go home")}) + return + } - // 1. Setup admin user - if viper.Get("user.password") == nil { - if r.Method == "GET" { - reg := &User{ - RequestBase: r.Header.Get("X-Request-Base"), - } - render(w, r, "register:manage", map[string]interface{}{"User": reg, "IsLogin": true, "Progress": _progress("register"), "HelpText": _helptext("register")}) - return - } else if r.Method == "POST" { - if err := r.ParseForm(); err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } + // 1. Setup admin user + if viper.Get("user.password") == nil { + if r.Method == "GET" { + reg := &User{ + RequestBase: r.Header.Get("X-Request-Base"), + } + render(w, r, "register:manage", map[string]interface{}{"User": reg, "IsLogin": true, "Progress": _progress("register"), "HelpText": _helptext("register")}) + return + } else if r.Method == "POST" { + if err := r.ParseForm(); err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } - reg := &User{ - Name: r.Form.Get("username"), - Email: r.Form.Get("email"), - Password: r.Form.Get("password"), - Confirm: r.Form.Get("confirm"), - RequestBase: r.Header.Get("X-Request-Base"), - } + reg := &User{ + Name: r.Form.Get("username"), + Email: r.Form.Get("email"), + Password: r.Form.Get("password"), + Confirm: r.Form.Get("confirm"), + RequestBase: r.Header.Get("X-Request-Base"), + } - if reg.Validate(true, false) == false { - render(w, r, "register:manage", map[string]interface{}{"User": reg, "IsLogin": true, "Progress": _progress("register"), "HelpText": _helptext("register")}) - return - } + if reg.Validate(true, false) == false { + render(w, r, "register:manage", map[string]interface{}{"User": reg, "IsLogin": true, "Progress": _progress("register"), "HelpText": _helptext("register")}) + return + } - hash, err := bcrypt.GenerateFromPassword([]byte(reg.Password), bcrypt.MinCost) - if err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } - viper.Set("user.name", reg.Name) - viper.Set("user.email", reg.Email) - viper.Set("user.password", string(hash)) - viper.WriteConfig() + hash, err := bcrypt.GenerateFromPassword([]byte(reg.Password), bcrypt.MinCost) + if err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } + viper.Set("user.name", reg.Name) + viper.Set("user.email", reg.Email) + viper.Set("user.password", string(hash)) + viper.WriteConfig() - session := getSession(w, r) - session.Values["user"] = reg.Name - session.Save(r, w) + session := getSession(w, r) + session.Values["user"] = reg.Name + session.Save(r, w) - // Fake the method to GET as we need to continue in the setupHandler() function - r.Method = "GET" - } else { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusSeeOther) - return - } - } + // Fake the method to GET as we need to continue in the setupHandler() function + r.Method = "GET" + } else { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusSeeOther) + return + } + } - // 2. Setup essential configuration - if viper.Get("labca.dns") == nil { - if r.Method == "GET" { - domain := viper.GetString("labca.fqdn") - pos := strings.Index(domain, ".") - if pos > -1 { - pos = pos + 1 - domain = domain[pos:] - } + // 2. Setup essential configuration + if viper.Get("labca.dns") == nil { + if r.Method == "GET" { + domain := viper.GetString("labca.fqdn") + pos := strings.Index(domain, ".") + if pos > -1 { + pos = pos + 1 + domain = domain[pos:] + } - cfg := &SetupConfig{ - Fqdn: viper.GetString("labca.fqdn"), - DomainMode: "lockdown", - LockdownDomains: domain, - WhitelistDomains: domain, - RequestBase: r.Header.Get("X-Request-Base"), - } + cfg := &SetupConfig{ + Fqdn: viper.GetString("labca.fqdn"), + DomainMode: "lockdown", + LockdownDomains: domain, + WhitelistDomains: domain, + RequestBase: r.Header.Get("X-Request-Base"), + } - render(w, r, "setup:manage", map[string]interface{}{"SetupConfig": cfg, "Progress": _progress("setup"), "HelpText": _helptext("setup")}) - return - } else if r.Method == "POST" { - if err := r.ParseForm(); err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } + render(w, r, "setup:manage", map[string]interface{}{"SetupConfig": cfg, "Progress": _progress("setup"), "HelpText": _helptext("setup")}) + return + } else if r.Method == "POST" { + if err := r.ParseForm(); err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } - cfg := &SetupConfig{ - Fqdn: r.Form.Get("fqdn"), - Dns: r.Form.Get("dns"), - DomainMode: r.Form.Get("domain_mode"), - LockdownDomains: r.Form.Get("lockdown_domains"), - WhitelistDomains: r.Form.Get("whitelist_domains"), - RequestBase: r.Header.Get("X-Request-Base"), - } + cfg := &SetupConfig{ + Fqdn: r.Form.Get("fqdn"), + Dns: r.Form.Get("dns"), + DomainMode: r.Form.Get("domain_mode"), + LockdownDomains: r.Form.Get("lockdown_domains"), + WhitelistDomains: r.Form.Get("whitelist_domains"), + RequestBase: r.Header.Get("X-Request-Base"), + } - if cfg.Validate(false) == false { - render(w, r, "setup:manage", map[string]interface{}{"SetupConfig": cfg, "Progress": _progress("setup"), "HelpText": _helptext("setup")}) - return - } + if cfg.Validate(false) == false { + render(w, r, "setup:manage", map[string]interface{}{"SetupConfig": cfg, "Progress": _progress("setup"), "HelpText": _helptext("setup")}) + return + } - matched, err := regexp.MatchString(":\\d+$", cfg.Dns) - if err == nil && !matched { - cfg.Dns += ":53" - } + matched, err := regexp.MatchString(":\\d+$", cfg.Dns) + if err == nil && !matched { + cfg.Dns += ":53" + } - viper.Set("labca.fqdn", cfg.Fqdn) - viper.Set("labca.dns", cfg.Dns) - viper.Set("labca.domain_mode", cfg.DomainMode) - if cfg.DomainMode == "lockdown" { - viper.Set("labca.lockdown", cfg.LockdownDomains) - } - if cfg.DomainMode == "whitelist" { - viper.Set("labca.whitelist", cfg.WhitelistDomains) - } - viper.WriteConfig() + viper.Set("labca.fqdn", cfg.Fqdn) + viper.Set("labca.dns", cfg.Dns) + viper.Set("labca.domain_mode", cfg.DomainMode) + if cfg.DomainMode == "lockdown" { + viper.Set("labca.lockdown", cfg.LockdownDomains) + } + if cfg.DomainMode == "whitelist" { + viper.Set("labca.whitelist", cfg.WhitelistDomains) + } + viper.WriteConfig() - // Fake the method to GET as we need to continue in the setupHandler() function - r.Method = "GET" - } else { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusSeeOther) - return - } - } + // Fake the method to GET as we need to continue in the setupHandler() function + r.Method = "GET" + } else { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusSeeOther) + return + } + } - // 3. Setup root CA certificate - if !_certCreate(w, r, "root-ca", true) { - return - } + // 3. Setup root CA certificate + if !_certCreate(w, r, "root-ca", true) { + return + } - // 4. Setup issuer certificate - if !_certCreate(w, r, "ca-int", false) { - return - } + // 4. Setup issuer certificate + if !_certCreate(w, r, "ca-int", false) { + return + } - // 5. Apply configuration / populate with certificate info - err := _applyConfig() - if err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } + // 5. Apply configuration / populate with certificate info + err := _applyConfig() + if err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } - if !viper.GetBool("config.restarted") { - // 6. Trust the new certs - if !_hostCommand(w, r, "trust-store") { - return - } + if !viper.GetBool("config.restarted") { + // 6. Trust the new certs + if !_hostCommand(w, r, "trust-store") { + return + } - // Don't let the retry mechanism generate new restartSecret! - if r.Header.Get("X-Requested-With") == "XMLHttpRequest" { - render(w, r, "index", map[string]interface{}{"Message": "Retry OK"}) - } else { - // 8. Restart application - restartSecret = randToken() - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/wait?restart="+restartSecret, http.StatusFound) - } - return + // Don't let the retry mechanism generate new restartSecret! + if r.Header.Get("X-Requested-With") == "XMLHttpRequest" { + render(w, r, "index", map[string]interface{}{"Message": "Retry OK"}) + } else { + // 8. Restart application + restartSecret = randToken() + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/wait?restart="+restartSecret, http.StatusFound) + } + return - } else { - render(w, r, "wrapup:manage", map[string]interface{}{"Progress": _progress("wrapup"), "HelpText": _helptext("wrapup")}) - } + } else { + render(w, r, "wrapup:manage", map[string]interface{}{"Progress": _progress("wrapup"), "HelpText": _helptext("wrapup")}) + } } func waitHandler(w http.ResponseWriter, r *http.Request) { - if viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) - return - } + if viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) + return + } - render(w, r, "polling:manage", map[string]interface{}{"Progress": _progress("polling"), "HelpText": _helptext("polling")}) + render(w, r, "polling:manage", map[string]interface{}{"Progress": _progress("polling"), "HelpText": _helptext("polling")}) } func restartHandler(w http.ResponseWriter, r *http.Request) { - if viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) - return - } + if viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) + return + } - if strings.Compare(r.URL.Query().Get("token"), restartSecret) != 0 { - log.Println("WARNING: Restart token ('" + r.URL.Query().Get("token") + "') does not match our secret ('" + restartSecret + "')!") - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if strings.Compare(r.URL.Query().Get("token"), restartSecret) != 0 { + log.Println("WARNING: Restart token ('" + r.URL.Query().Get("token") + "') does not match our secret ('" + restartSecret + "')!") + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - viper.Set("config.restarted", true) - viper.WriteConfig() + viper.Set("config.restarted", true) + viper.WriteConfig() - if !_hostCommand(w, r, "docker-restart") { - viper.Set("config.restarted", false) - viper.WriteConfig() - return - } + if !_hostCommand(w, r, "docker-restart") { + viper.Set("config.restarted", false) + viper.WriteConfig() + return + } } func finalHandler(w http.ResponseWriter, r *http.Request) { - if viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) - return - } + if viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/", http.StatusFound) + return + } - // Don't let the retry mechanism trigger a certificate request and restart! - if r.Header.Get("X-Requested-With") == "XMLHttpRequest" { - render(w, r, "index", map[string]interface{}{"Message": "Retry OK"}) - } else { - // 9. Setup our own web certificate - if !_hostCommand(w, r, "acme-request") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/logs/cert", http.StatusSeeOther) - return - } + // Don't let the retry mechanism trigger a certificate request and restart! + if r.Header.Get("X-Requested-With") == "XMLHttpRequest" { + render(w, r, "index", map[string]interface{}{"Message": "Retry OK"}) + } else { + // 9. Setup our own web certificate + if !_hostCommand(w, r, "acme-request") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/logs/cert", http.StatusSeeOther) + return + } - // 10. remove the temporary bit from nginx config - if !_hostCommand(w, r, "nginx-remove-redirect") { - return - } + // 10. remove the temporary bit from nginx config + if !_hostCommand(w, r, "nginx-remove-redirect") { + return + } - // 11. reload nginx - if !_hostCommand(w, r, "nginx-reload") { - return - } + // 11. reload nginx + if !_hostCommand(w, r, "nginx-reload") { + return + } - viper.Set("config.complete", true) - viper.WriteConfig() + viper.Set("config.complete", true) + viper.WriteConfig() - render(w, r, "final:manage", map[string]interface{}{"RequestBase": r.Header.Get("X-Request-Base"), "Progress": _progress("final"), "HelpText": _helptext("final")}) - } + render(w, r, "final:manage", map[string]interface{}{"RequestBase": r.Header.Get("X-Request-Base"), "Progress": _progress("final"), "HelpText": _helptext("final")}) + } } // RangeStructer takes the first argument, which must be a struct, and // returns the value of each field in a slice. It will return nil // if there are no arguments or first argument is not a struct func RangeStructer(args ...interface{}) []interface{} { - if len(args) == 0 { - return nil - } + if len(args) == 0 { + return nil + } - v := reflect.ValueOf(args[0]) - if v.Kind() != reflect.Struct { - return nil - } + v := reflect.ValueOf(args[0]) + if v.Kind() != reflect.Struct { + return nil + } - out := make([]interface{}, v.NumField()) - for i := 0; i < v.NumField(); i++ { - switch v.Field(i).Kind() { - case reflect.String: - if v.Field(i).Type().String() == "template.HTML" { - out[i] = template.HTML(v.Field(i).String()) - } else { - out[i] = v.Field(i).String() - } - case reflect.Bool: - out[i] = v.Field(i).Bool() - default: - out[i] = v.Field(i) - } - } + out := make([]interface{}, v.NumField()) + for i := 0; i < v.NumField(); i++ { + switch v.Field(i).Kind() { + case reflect.String: + if v.Field(i).Type().String() == "template.HTML" { + out[i] = template.HTML(v.Field(i).String()) + } else { + out[i] = v.Field(i).String() + } + case reflect.Bool: + out[i] = v.Field(i).Bool() + default: + out[i] = v.Field(i) + } + } - return out + return out } func accountsHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - Accounts, err := GetAccounts(w, r) - if err == nil { - render(w, r, "list:accounts", map[string]interface{}{"List": Accounts}) - } + Accounts, err := GetAccounts(w, r) + if err == nil { + render(w, r, "list:accounts", map[string]interface{}{"List": Accounts}) + } } func accountHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) - if err != nil { - errorHandler(w, r, err, http.StatusBadRequest) - return - } + vars := mux.Vars(r) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + errorHandler(w, r, err, http.StatusBadRequest) + return + } - AccountDetails, err := GetAccount(w, r, id) - if err == nil { - render(w, r, "show:accounts", map[string]interface{}{"Details": AccountDetails}) - } + AccountDetails, err := GetAccount(w, r, id) + if err == nil { + render(w, r, "show:accounts", map[string]interface{}{"Details": AccountDetails}) + } } func ordersHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - Orders, err := GetOrders(w, r) - if err == nil { - render(w, r, "list:orders", map[string]interface{}{"List": Orders}) - } + Orders, err := GetOrders(w, r) + if err == nil { + render(w, r, "list:orders", map[string]interface{}{"List": Orders}) + } } func orderHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) - if err != nil { - errorHandler(w, r, err, http.StatusBadRequest) - return - } + vars := mux.Vars(r) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + errorHandler(w, r, err, http.StatusBadRequest) + return + } - OrderDetails, err := GetOrder(w, r, id) - if err == nil { - render(w, r, "show:orders", map[string]interface{}{"Details": OrderDetails}) - } + OrderDetails, err := GetOrder(w, r, id) + if err == nil { + render(w, r, "show:orders", map[string]interface{}{"Details": OrderDetails}) + } } func authzHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - Authz, err := GetAuthz(w, r) - if err == nil { - render(w, r, "list:authz", map[string]interface{}{"List": Authz}) - } + Authz, err := GetAuthz(w, r) + if err == nil { + render(w, r, "list:authz", map[string]interface{}{"List": Authz}) + } } func authHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - vars := mux.Vars(r) - id := vars["id"] + vars := mux.Vars(r) + id := vars["id"] - AuthDetails, err := GetAuth(w, r, id) - if err == nil { - render(w, r, "show:authz", map[string]interface{}{"Details": AuthDetails}) - } + AuthDetails, err := GetAuth(w, r, id) + if err == nil { + render(w, r, "show:authz", map[string]interface{}{"Details": AuthDetails}) + } } func challengesHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - Challenges, err := GetChallenges(w, r) - if err == nil { - render(w, r, "list:challenges", map[string]interface{}{"List": Challenges}) - } + Challenges, err := GetChallenges(w, r) + if err == nil { + render(w, r, "list:challenges", map[string]interface{}{"List": Challenges}) + } } func challengeHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) - if err != nil { - errorHandler(w, r, err, http.StatusBadRequest) - return - } + vars := mux.Vars(r) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + errorHandler(w, r, err, http.StatusBadRequest) + return + } - ChallengeDetails, err := GetChallenge(w, r, id) - if err == nil { - render(w, r, "show:challenges", map[string]interface{}{"Details": ChallengeDetails}) - } + ChallengeDetails, err := GetChallenge(w, r, id) + if err == nil { + render(w, r, "show:challenges", map[string]interface{}{"Details": ChallengeDetails}) + } } func certificatesHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - Certificates, err := GetCertificates(w, r) - if err == nil { - render(w, r, "list:certificates", map[string]interface{}{"List": Certificates}) - } + Certificates, err := GetCertificates(w, r) + if err == nil { + render(w, r, "list:certificates", map[string]interface{}{"List": Certificates}) + } } func certificateHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) - return - } + if !viper.GetBool("config.complete") { + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/setup", http.StatusFound) + return + } - var serial string - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) - if err != nil { - serial = vars["id"] - } + var serial string + vars := mux.Vars(r) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + serial = vars["id"] + } - CertificateDetails, err := GetCertificate(w, r, id, serial) - if err == nil { - render(w, r, "show:certificates", map[string]interface{}{"Details": CertificateDetails}) - } + CertificateDetails, err := GetCertificate(w, r, id, serial) + if err == nil { + render(w, r, "show:certificates", map[string]interface{}{"Details": CertificateDetails}) + } } func certRevokeHandler(w http.ResponseWriter, r *http.Request) { - if !viper.GetBool("config.complete") { - errorHandler(w, r, errors.New("Method not allowed at this point"), http.StatusMethodNotAllowed) - return - } + if !viper.GetBool("config.complete") { + errorHandler(w, r, errors.New("Method not allowed at this point"), http.StatusMethodNotAllowed) + return + } - if r.Method == "POST" { - if err := r.ParseForm(); err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } + if r.Method == "POST" { + if err := r.ParseForm(); err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } - serial := r.Form.Get("serial") - reason, err := strconv.Atoi(r.Form.Get("reason")) - if err != nil { - errorHandler(w, r, err, http.StatusBadRequest) - return - } + serial := r.Form.Get("serial") + reason, err := strconv.Atoi(r.Form.Get("reason")) + if err != nil { + errorHandler(w, r, err, http.StatusBadRequest) + return + } - if !_hostCommand(w, r, "revoke-cert", serial, strconv.Itoa(reason)) { - return - } - } + if !_hostCommand(w, r, "revoke-cert", serial, strconv.Itoa(reason)) { + return + } + } } type navItem struct { - Name string - Icon string - Attrs map[template.HTMLAttr]string - IsActive bool - SubMenu []navItem + Name string + Icon string + Attrs map[template.HTMLAttr]string + IsActive bool + SubMenu []navItem } func activeNav(active string, uri string, requestBase string) []navItem { - isAcmeActive := (uri == "/accounts" || strings.HasPrefix(uri, "/accounts/") || - uri == "/orders" || strings.HasPrefix(uri, "/orders/") || - uri == "/authz" || strings.HasPrefix(uri, "/authz/") || - uri == "/challenges" || strings.HasPrefix(uri, "/challenges/") || - uri == "/certificates" || strings.HasPrefix(uri, "/certificates/") || - false) + isAcmeActive := (uri == "/accounts" || strings.HasPrefix(uri, "/accounts/") || + uri == "/orders" || strings.HasPrefix(uri, "/orders/") || + uri == "/authz" || strings.HasPrefix(uri, "/authz/") || + uri == "/challenges" || strings.HasPrefix(uri, "/challenges/") || + uri == "/certificates" || strings.HasPrefix(uri, "/certificates/") || + false) - // create menu items - home := navItem{ - Name: "Dashboard", - Icon: "fa-dashboard", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/", - "title": "Main page with the status of the system", - }, - } - accounts := navItem{ - Name: "Accounts", - Icon: "fa-list-alt", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/accounts", - "title": "ACME Accounts", - }, - } - orders := navItem{ - Name: "Orders", - Icon: "fa-tags", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/orders", - "title": "ACME Orders", - }, - } - authz := navItem{ - Name: "Authorizations", - Icon: "fa-chain", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/authz", - "title": "ACME Authorizations", - }, - } - challenges := navItem{ - Name: "Challenges", - Icon: "fa-exchange", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/challenges", - "title": "ACME Challenges", - }, - } - certificates := navItem{ - Name: "Certificates", - Icon: "fa-lock", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/certificates", - "title": "ACME Certificates", - }, - } - acme := navItem{ - Name: "ACME", - Icon: "fa-sitemap", - Attrs: map[template.HTMLAttr]string{ - "href": "#", - "title": "Automated Certificate Management Environment", - }, - IsActive: isAcmeActive, - SubMenu: []navItem{accounts, certificates, orders, authz, challenges}, - } - cert := navItem{ - Name: "Web Certificate", - Icon: "fa-lock", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/cert", - "title": "Log file for the certificate renewal for this server", - }, - } - boulder := navItem{ - Name: "ACME", - Icon: "fa-search-plus", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/boulder", - "title": "Live view on the backend ACME application logs", - }, - } - audit := navItem{ - Name: "ACME Audit Log", - Icon: "fa-paw", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/audit", - "title": "Live view on only the audit messages in the backend ACME application logs", - }, - } - labca := navItem{ - Name: "LabCA", - Icon: "fa-edit", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/labca", - "title": "Live view on the logs for this LabCA web application", - }, - } - web := navItem{ - Name: "Web Access", - Icon: "fa-globe", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/web", - "title": "Live view on the NGINX web server access log", - }, - } - weberr := navItem{ - Name: "Web Error", - Icon: "fa-times", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/logs/weberr", - "title": "Log file for the NGINX web server error log", - }, - } - logs := navItem{ - Name: "Logs", - Icon: "fa-files-o", - Attrs: map[template.HTMLAttr]string{ - "href": "#", - "title": "Log Files", - }, - SubMenu: []navItem{cert, boulder, audit, labca, web, weberr}, - } - manage := navItem{ - Name: "Manage", - Icon: "fa-wrench", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/manage", - "title": "Manage the system", - }, - } - about := navItem{ - Name: "About", - Icon: "fa-comments", - Attrs: map[template.HTMLAttr]string{ - "href": requestBase + "/about", - "title": "About LabCA", - }, - } - public := navItem{ - Name: "Public Area", - Icon: "fa-home", - Attrs: map[template.HTMLAttr]string{ - "href": "/", - "title": "The non-Admin pages of this LabCA instance", - }, - } + // create menu items + home := navItem{ + Name: "Dashboard", + Icon: "fa-dashboard", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/", + "title": "Main page with the status of the system", + }, + } + accounts := navItem{ + Name: "Accounts", + Icon: "fa-list-alt", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/accounts", + "title": "ACME Accounts", + }, + } + orders := navItem{ + Name: "Orders", + Icon: "fa-tags", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/orders", + "title": "ACME Orders", + }, + } + authz := navItem{ + Name: "Authorizations", + Icon: "fa-chain", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/authz", + "title": "ACME Authorizations", + }, + } + challenges := navItem{ + Name: "Challenges", + Icon: "fa-exchange", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/challenges", + "title": "ACME Challenges", + }, + } + certificates := navItem{ + Name: "Certificates", + Icon: "fa-lock", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/certificates", + "title": "ACME Certificates", + }, + } + acme := navItem{ + Name: "ACME", + Icon: "fa-sitemap", + Attrs: map[template.HTMLAttr]string{ + "href": "#", + "title": "Automated Certificate Management Environment", + }, + IsActive: isAcmeActive, + SubMenu: []navItem{accounts, certificates, orders, authz, challenges}, + } + cert := navItem{ + Name: "Web Certificate", + Icon: "fa-lock", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/cert", + "title": "Log file for the certificate renewal for this server", + }, + } + boulder := navItem{ + Name: "ACME", + Icon: "fa-search-plus", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/boulder", + "title": "Live view on the backend ACME application logs", + }, + } + audit := navItem{ + Name: "ACME Audit Log", + Icon: "fa-paw", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/audit", + "title": "Live view on only the audit messages in the backend ACME application logs", + }, + } + labca := navItem{ + Name: "LabCA", + Icon: "fa-edit", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/labca", + "title": "Live view on the logs for this LabCA web application", + }, + } + web := navItem{ + Name: "Web Access", + Icon: "fa-globe", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/web", + "title": "Live view on the NGINX web server access log", + }, + } + weberr := navItem{ + Name: "Web Error", + Icon: "fa-times", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/logs/weberr", + "title": "Log file for the NGINX web server error log", + }, + } + logs := navItem{ + Name: "Logs", + Icon: "fa-files-o", + Attrs: map[template.HTMLAttr]string{ + "href": "#", + "title": "Log Files", + }, + SubMenu: []navItem{cert, boulder, audit, labca, web, weberr}, + } + manage := navItem{ + Name: "Manage", + Icon: "fa-wrench", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/manage", + "title": "Manage the system", + }, + } + about := navItem{ + Name: "About", + Icon: "fa-comments", + Attrs: map[template.HTMLAttr]string{ + "href": requestBase + "/about", + "title": "About LabCA", + }, + } + public := navItem{ + Name: "Public Area", + Icon: "fa-home", + Attrs: map[template.HTMLAttr]string{ + "href": "/", + "title": "The non-Admin pages of this LabCA instance", + }, + } - // set active menu class - switch active { - case "about": - about.Attrs["class"] = "active" - case "accounts": - accounts.Attrs["class"] = "active" - case "orders": - orders.Attrs["class"] = "active" - case "authz": - authz.Attrs["class"] = "active" - case "challenges": - challenges.Attrs["class"] = "active" - case "certificates": - certificates.Attrs["class"] = "active" - case "index": - home.Attrs["class"] = "active" - case "manage": - manage.Attrs["class"] = "active" - case "logs": - logs.Attrs["class"] = "active" - } + // set active menu class + switch active { + case "about": + about.Attrs["class"] = "active" + case "accounts": + accounts.Attrs["class"] = "active" + case "orders": + orders.Attrs["class"] = "active" + case "authz": + authz.Attrs["class"] = "active" + case "challenges": + challenges.Attrs["class"] = "active" + case "certificates": + certificates.Attrs["class"] = "active" + case "index": + home.Attrs["class"] = "active" + case "manage": + manage.Attrs["class"] = "active" + case "logs": + logs.Attrs["class"] = "active" + } - return []navItem{home, acme, logs, manage, about, public} + return []navItem{home, acme, logs, manage, about, public} } func render(w http.ResponseWriter, r *http.Request, view string, data map[string]interface{}) { - viewSlice := strings.Split(view, ":") - menu := viewSlice[0] - if len(viewSlice) > 1 { - menu = viewSlice[1] - } - data["Menu"] = activeNav(menu, r.RequestURI, r.Header.Get("X-Request-Base")) + viewSlice := strings.Split(view, ":") + menu := viewSlice[0] + if len(viewSlice) > 1 { + menu = viewSlice[1] + } + data["Menu"] = activeNav(menu, r.RequestURI, r.Header.Get("X-Request-Base")) - if version != "" { - data["Version"] = version - } + if version != "" { + data["Version"] = version + } - b, err := tmpls.Render("base.tmpl", "views/"+viewSlice[0]+".tmpl", data) - if err != nil { - errorHandler(w, r, err, http.StatusInternalServerError) - return - } + b, err := tmpls.Render("base.tmpl", "views/"+viewSlice[0]+".tmpl", data) + if err != nil { + errorHandler(w, r, err, http.StatusInternalServerError) + return + } - w.Write(b) + w.Write(b) } func notFoundHandler(w http.ResponseWriter, r *http.Request) { - errorHandler(w, r, fmt.Errorf("NotFoundHandler for: %s %s", r.Method, r.URL), http.StatusNotFound) + errorHandler(w, r, fmt.Errorf("NotFoundHandler for: %s %s", r.Method, r.URL), http.StatusNotFound) } func authorized(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println(r.Method + " " + r.RequestURI) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method + " " + r.RequestURI) - if r.RequestURI == "/login" || strings.Contains(r.RequestURI, "/static/") { - next.ServeHTTP(w, r) - } else { - session := getSession(w, r) - if session.Values["user"] != nil || (r.RequestURI == "/setup" && viper.Get("user.password") == nil) { - next.ServeHTTP(w, r) - } else { - session.Values["bounce"] = r.RequestURI - session.Save(r, w) - http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/login", http.StatusFound) - } - } - }) + if r.RequestURI == "/login" || strings.Contains(r.RequestURI, "/static/") { + next.ServeHTTP(w, r) + } else { + session := getSession(w, r) + if session.Values["user"] != nil || (r.RequestURI == "/setup" && viper.Get("user.password") == nil) { + next.ServeHTTP(w, r) + } else { + session.Values["bounce"] = r.RequestURI + session.Save(r, w) + http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/login", http.StatusFound) + } + } + }) } func init() { - if os.Getenv("DEVELOPMENT") != "" { - isDev = true - } + if os.Getenv("DEVELOPMENT") != "" { + isDev = true + } - var err error - tmpls, err = templates.New().ParseDir("./templates", "templates/") - if err != nil { - panic(fmt.Errorf("Fatal error templates: %s \n", err)) - } - tmpls.AddFunc("rangeStruct", RangeStructer) + var err error + tmpls, err = templates.New().ParseDir("./templates", "templates/") + if err != nil { + panic(fmt.Errorf("Fatal error templates: %s \n", err)) + } + tmpls.AddFunc("rangeStruct", RangeStructer) - viper.SetConfigName("config") - viper.AddConfigPath("data") - viper.SetDefault("config.complete", false) - if err := viper.ReadInConfig(); err != nil { - panic(fmt.Errorf("Fatal error config file: %s \n", err)) - } + viper.SetConfigName("config") + viper.AddConfigPath("data") + viper.SetDefault("config.complete", false) + if err := viper.ReadInConfig(); err != nil { + panic(fmt.Errorf("Fatal error config file: %s \n", err)) + } - if viper.Get("keys.auth") == nil { - key := securecookie.GenerateRandomKey(32) - if key == nil { - panic(fmt.Errorf("Fatal error random key\n")) - } - viper.Set("keys.auth", key) - viper.WriteConfig() - } - if viper.Get("keys.enc") == nil { - key := securecookie.GenerateRandomKey(32) - if key == nil { - panic(fmt.Errorf("Fatal error random key\n")) - } - viper.Set("keys.enc", key) - viper.WriteConfig() - } + if viper.Get("keys.auth") == nil { + key := securecookie.GenerateRandomKey(32) + if key == nil { + panic(fmt.Errorf("Fatal error random key\n")) + } + viper.Set("keys.auth", key) + viper.WriteConfig() + } + if viper.Get("keys.enc") == nil { + key := securecookie.GenerateRandomKey(32) + if key == nil { + panic(fmt.Errorf("Fatal error random key\n")) + } + viper.Set("keys.enc", key) + viper.WriteConfig() + } - if viper.Get("server.addr") == nil { - viper.Set("server.addr", "0.0.0.0") - viper.WriteConfig() - } + if viper.Get("server.addr") == nil { + viper.Set("server.addr", "0.0.0.0") + viper.WriteConfig() + } - if viper.Get("server.port") == nil { - viper.Set("server.port", 3000) - viper.WriteConfig() - } + if viper.Get("server.port") == nil { + viper.Set("server.port", 3000) + viper.WriteConfig() + } - if viper.Get("server.session.maxage") == nil { - viper.Set("server.session.maxage", 3600) // 1 hour - viper.WriteConfig() - } + if viper.Get("server.session.maxage") == nil { + viper.Set("server.session.maxage", 3600) // 1 hour + viper.WriteConfig() + } - if viper.Get("db.conn") == nil { - viper.Set("db.type", "mysql") - viper.Set("db.conn", "root@tcp(boulder-mysql:3306)/boulder_sa_integration") - viper.WriteConfig() - } - dbConn = viper.GetString("db.conn") - dbType = viper.GetString("db.type") + if viper.Get("db.conn") == nil { + viper.Set("db.type", "mysql") + viper.Set("db.conn", "root@tcp(boulder-mysql:3306)/boulder_sa_integration") + viper.WriteConfig() + } + dbConn = viper.GetString("db.conn") + dbType = viper.GetString("db.type") - version = viper.GetString("version") + version = viper.GetString("version") } func main() { - tmpls.Parse() + tmpls.Parse() - sessionStore = sessions.NewCookieStore([]byte(viper.GetString("keys.auth")), []byte(viper.GetString("keys.enc"))) - sessionStore.Options = &sessions.Options{ - Path: "/", - MaxAge: viper.GetInt("server.session.maxage") * 1, - HttpOnly: true, - } + sessionStore = sessions.NewCookieStore([]byte(viper.GetString("keys.auth")), []byte(viper.GetString("keys.enc"))) + sessionStore.Options = &sessions.Options{ + Path: "/", + MaxAge: viper.GetInt("server.session.maxage") * 1, + HttpOnly: true, + } - r := mux.NewRouter() - r.HandleFunc("/", rootHandler).Methods("GET") - r.HandleFunc("/about", aboutHandler).Methods("GET") - r.HandleFunc("/manage", manageHandler).Methods("GET", "POST") - r.HandleFunc("/final", finalHandler).Methods("GET") - r.HandleFunc("/login", loginHandler).Methods("GET", "POST") - r.HandleFunc("/logout", logoutHandler).Methods("GET") - r.HandleFunc("/logs/{type}", logsHandler).Methods("GET") - r.HandleFunc("/restart", restartHandler).Methods("GET") - r.HandleFunc("/setup", setupHandler).Methods("GET", "POST") - r.HandleFunc("/wait", waitHandler).Methods("GET") - r.HandleFunc("/ws", wsHandler).Methods("GET") + r := mux.NewRouter() + r.HandleFunc("/", rootHandler).Methods("GET") + r.HandleFunc("/about", aboutHandler).Methods("GET") + r.HandleFunc("/manage", manageHandler).Methods("GET", "POST") + r.HandleFunc("/final", finalHandler).Methods("GET") + r.HandleFunc("/login", loginHandler).Methods("GET", "POST") + r.HandleFunc("/logout", logoutHandler).Methods("GET") + r.HandleFunc("/logs/{type}", logsHandler).Methods("GET") + r.HandleFunc("/restart", restartHandler).Methods("GET") + r.HandleFunc("/setup", setupHandler).Methods("GET", "POST") + r.HandleFunc("/wait", waitHandler).Methods("GET") + r.HandleFunc("/ws", wsHandler).Methods("GET") - r.HandleFunc("/accounts", accountsHandler).Methods("GET") - r.HandleFunc("/accounts/{id}", accountHandler).Methods("GET") - r.HandleFunc("/orders", ordersHandler).Methods("GET") - r.HandleFunc("/orders/{id}", orderHandler).Methods("GET") - r.HandleFunc("/authz", authzHandler).Methods("GET") - r.HandleFunc("/authz/{id}", authHandler).Methods("GET") - r.HandleFunc("/challenges", challengesHandler).Methods("GET") - r.HandleFunc("/challenges/{id}", challengeHandler).Methods("GET") - r.HandleFunc("/certificates", certificatesHandler).Methods("GET") - r.HandleFunc("/certificates/{id}", certificateHandler).Methods("GET") - r.HandleFunc("/certificates/{id}", certRevokeHandler).Methods("POST") + r.HandleFunc("/accounts", accountsHandler).Methods("GET") + r.HandleFunc("/accounts/{id}", accountHandler).Methods("GET") + r.HandleFunc("/orders", ordersHandler).Methods("GET") + r.HandleFunc("/orders/{id}", orderHandler).Methods("GET") + r.HandleFunc("/authz", authzHandler).Methods("GET") + r.HandleFunc("/authz/{id}", authHandler).Methods("GET") + r.HandleFunc("/challenges", challengesHandler).Methods("GET") + r.HandleFunc("/challenges/{id}", challengeHandler).Methods("GET") + r.HandleFunc("/certificates", certificatesHandler).Methods("GET") + r.HandleFunc("/certificates/{id}", certificateHandler).Methods("GET") + r.HandleFunc("/certificates/{id}", certRevokeHandler).Methods("POST") - r.NotFoundHandler = http.HandlerFunc(notFoundHandler) - if isDev { - r.PathPrefix("/accounts/static/").Handler(http.StripPrefix("/accounts/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/authz/static/").Handler(http.StripPrefix("/authz/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/challenges/static/").Handler(http.StripPrefix("/challenges/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/certificates/static/").Handler(http.StripPrefix("/certificates/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/orders/static/").Handler(http.StripPrefix("/orders/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/logs/static/").Handler(http.StripPrefix("/logs/static/", http.FileServer(http.Dir("../www")))) - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("../www")))) - } - r.Use(authorized) + r.NotFoundHandler = http.HandlerFunc(notFoundHandler) + if isDev { + r.PathPrefix("/accounts/static/").Handler(http.StripPrefix("/accounts/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/authz/static/").Handler(http.StripPrefix("/authz/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/challenges/static/").Handler(http.StripPrefix("/challenges/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/certificates/static/").Handler(http.StripPrefix("/certificates/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/orders/static/").Handler(http.StripPrefix("/orders/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/logs/static/").Handler(http.StripPrefix("/logs/static/", http.FileServer(http.Dir("../www")))) + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("../www")))) + } + r.Use(authorized) - log.Printf("Listening on %s:%d...\n", viper.GetString("server.addr"), viper.GetInt("server.port")) - srv := &http.Server{ - Handler: r, - Addr: viper.GetString("server.addr") + ":" + viper.GetString("server.port"), - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - } - log.Fatal(srv.ListenAndServe()) + log.Printf("Listening on %s:%d...\n", viper.GetString("server.addr"), viper.GetInt("server.port")) + srv := &http.Server{ + Handler: r, + Addr: viper.GetString("server.addr") + ":" + viper.GetString("server.port"), + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + log.Fatal(srv.ListenAndServe()) }