diff --git a/README.md b/README.md index 2a3b8a3..8b168b1 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ chldapasswd [flags] generate-lost-password-link | `-bind` | `127.0.0.1:8080` | Listen address | | `-baseurl` | `/` | URL prefix (for reverse-proxy subpath deployment) | | `-config` | _(none)_ | Path to a JSON config file for LDAP settings | -| `-public-url` | `https://ldap.nemunai.re` | Base URL used in password reset emails | +| `-public-url` | _(none)_ | Base URL used in password reset emails | | `-brand-name` | `chldapasswd` | Brand name shown in the UI | | `-brand-logo` | _(none)_ | URL of a logo image shown in the UI | | `-addy-api-secret` | _(none)_ | HMAC secret for the alias API | @@ -76,7 +76,7 @@ The `-config` flag accepts a JSON file whose fields map directly to the `LDAP` s ```json { - "Host": "ldap.example.com", + "Host": "auth.example.com", "Port": 636, "Ssl": true, "BaseDN": "dc=example,dc=com", @@ -109,13 +109,13 @@ The alias API is compatible with the addy.io API format. Tokens are HMAC-SHA224 ```sh # Create alias -curl -X POST https://ldap.example.com/api/v1/aliases \ +curl -X POST https://auth.example.com/api/v1/aliases \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"domain": "example.com"}' # Delete alias -curl -X DELETE https://ldap.example.com/api/v1/aliases/abc123%40example.com \ +curl -X DELETE https://auth.example.com/api/v1/aliases/abc123%40example.com \ -H "Authorization: Bearer " ``` @@ -133,7 +133,7 @@ The `dextpl/` directory contains a matching theme for [Dex](https://dexidp.io/) ```sh docker run -d \ - -e LDAP_HOST=ldap.example.com \ + -e LDAP_HOST=auth.example.com \ -e LDAP_PORT=636 \ -e LDAP_SSL=true \ -e LDAP_BASEDN=dc=example,dc=com \ @@ -142,7 +142,7 @@ docker run -d \ -e SMTP_HOST=smtp.example.com \ -e SMTP_PORT=587 \ -e SMTP_FROM=noreply@example.com \ - -e PUBLIC_URL=https://ldap.example.com \ + -e PUBLIC_URL=https://auth.example.com \ -p 8080:8080 \ nemunaire/chldapasswd ``` diff --git a/main.go b/main.go index 32a1124..5701f36 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,7 @@ import ( "syscall" ) -var myPublicURL = "https://ldap.nemunai.re" +var myPublicURL = "" var devMode bool var brandName = "chldapasswd" var brandLogo = "" @@ -35,7 +35,7 @@ var myLDAP = LDAP{ Port: 389, BaseDN: "dc=example,dc=com", MailPort: 587, - MailFrom: "noreply@nemunai.re", + MailFrom: "noreply@example.com", } type ResponseWriterPrefix struct { @@ -79,37 +79,34 @@ func StripPrefix(prefix string, h http.Handler) http.Handler { } func main() { - var bind = flag.String("bind", "127.0.0.1:8080", "Bind port/socket") - var baseURL = flag.String("baseurl", "/", "URL prepended to each URL") - var configfile = flag.String("config", "", "path to the configuration file") - var publicURL = flag.String("public-url", myPublicURL, "Public base URL used in password reset emails") - var dev = flag.Bool("dev", false, "Development mode: disables HSTS and cookie Secure flag for local HTTP testing") - var bname = flag.String("brand-name", "chldapasswd", "Brand name displayed in the UI") - var blogo = flag.String("brand-logo", "", "URL of brand logo displayed in the UI (added to CSP img-src)") - flag.Parse() + baseURL := "/" + bind := "127.0.0.1:8080" - myPublicURL = *publicURL - devMode = *dev - brandName = *bname - brandLogo = *blogo if val, ok := os.LookupEnv("BRAND_NAME"); ok { brandName = val } if val, ok := os.LookupEnv("BRAND_LOGO"); ok { brandLogo = val } + + var configfile = flag.String("config", "", "path to the configuration file") + flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL") + flag.StringVar(&bind, "bind", bind, "Bind port/socket") + flag.StringVar(&brandName, "brand-name", brandName, "Brand name displayed in the UI") + flag.StringVar(&brandLogo, "brand-logo", brandLogo, "URL of brand logo displayed in the UI (added to CSP img-src)") + flag.BoolVar(&devMode, "dev", devMode, "Development mode: disables HSTS and cookie Secure flag for local HTTP testing") + flag.StringVar(&myPublicURL, "public-url", myPublicURL, "Public base URL used in password reset emails") + flag.Parse() + if devMode { log.Println("WARNING: running in development mode — security features relaxed, do not use in production") } // Sanitize options - log.Println("Checking paths...") - if *baseURL != "/" { - tmp := path.Clean(*baseURL) - baseURL = &tmp + if baseURL != "/" { + baseURL = path.Clean(baseURL) } else { - tmp := "" - baseURL = &tmp + baseURL = "" } // Load config file @@ -231,20 +228,20 @@ func main() { signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) // Register handlers - http.HandleFunc(fmt.Sprintf("GET %s/altcha.min.js", *baseURL), serveAltchaJS) - http.HandleFunc(fmt.Sprintf("GET %s/style.css", *baseURL), serveStyleCSS) - http.HandleFunc(fmt.Sprintf("GET %s/altcha-challenge", *baseURL), serveAltchaChallenge) - http.HandleFunc(fmt.Sprintf("%s/{$}", *baseURL), changePassword) - http.HandleFunc(fmt.Sprintf("POST %s/api/v1/aliases", *baseURL), addyAliasAPI) - http.HandleFunc(fmt.Sprintf("DELETE %s/api/v1/aliases/{alias}", *baseURL), addyAliasAPIDelete) - http.HandleFunc(fmt.Sprintf("%s/auth", *baseURL), httpBasicAuth) - http.HandleFunc(fmt.Sprintf("%s/login", *baseURL), tryLogin) - http.HandleFunc(fmt.Sprintf("%s/change", *baseURL), changePassword) - http.HandleFunc(fmt.Sprintf("%s/reset", *baseURL), resetPassword) - http.HandleFunc(fmt.Sprintf("%s/lost", *baseURL), lostPassword) + http.HandleFunc(fmt.Sprintf("GET %s/altcha.min.js", baseURL), serveAltchaJS) + http.HandleFunc(fmt.Sprintf("GET %s/style.css", baseURL), serveStyleCSS) + http.HandleFunc(fmt.Sprintf("GET %s/altcha-challenge", baseURL), serveAltchaChallenge) + http.HandleFunc(fmt.Sprintf("%s/{$}", baseURL), changePassword) + http.HandleFunc(fmt.Sprintf("POST %s/api/v1/aliases", baseURL), addyAliasAPI) + http.HandleFunc(fmt.Sprintf("DELETE %s/api/v1/aliases/{alias}", baseURL), addyAliasAPIDelete) + http.HandleFunc(fmt.Sprintf("%s/auth", baseURL), httpBasicAuth) + http.HandleFunc(fmt.Sprintf("%s/login", baseURL), tryLogin) + http.HandleFunc(fmt.Sprintf("%s/change", baseURL), changePassword) + http.HandleFunc(fmt.Sprintf("%s/reset", baseURL), resetPassword) + http.HandleFunc(fmt.Sprintf("%s/lost", baseURL), lostPassword) srv := &http.Server{ - Addr: *bind, + Addr: bind, Handler: securityHeaders(http.DefaultServeMux), } @@ -253,7 +250,7 @@ func main() { log.Fatal(srv.ListenAndServe()) }() log.Printf("Using LDAP server at %s:%d (baseDN: %s)", myLDAP.Host, myLDAP.Port, myLDAP.BaseDN) - log.Printf("Ready, listening on %s", *bind) + log.Printf("Ready, listening on %s", bind) // Wait shutdown signal <-interrupt