wlan-setup/ is a Go service that will replace the nginx + njs backend of
wlan.renner.uno (switched over in a follow-up once the first image exists).
- Page, /whoami, /healthz; /{android,apple,windows}/install and /callback:
authentik OAuth code flow (client wlan-setup, client_secret_basic), user
check against X-authentik-username, per-device app password
wlan-<platform>-... (29 days), profile per platform: Android Passpoint
(application/x-wifi-config), Apple .mobileconfig with Passpoint, Windows
CarrierProvisioning with Passpoint.
- Windows: the profile is signed with XML-DSig in the form of Microsoft's
samples (enveloped, C14N 1.0, rsa-sha1, chain in KeyInfo) by the key in
/etc/wlan-signing, kept for 5 minutes under a single-use token, and the
browser is sent to ms-settings:wifi-provisioning?uri=.../windows/profile/<token>.
- Offline tests against a fake authentik; goxmldsig verifies the signature
in the tests only.
- CI: wlan-setup-test (gofmt, vet, test -race) on PRs; build-ci-images
builds gitea.renner.uno/gitea_admin/wlan-setup:YYYY-MM-DD-HHMM on main;
Flux image automation follows the newest tag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
1.6 KiB
Go
52 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// Config is the service configuration, read from the environment.
|
|
type Config struct {
|
|
ClientSecret string
|
|
// AuthentikURL is where the calls go; they carry Host auth.renner.uno.
|
|
AuthentikURL string
|
|
AuthorizeURL string
|
|
PublicURL string
|
|
SigningKey string
|
|
SigningCert string
|
|
Listen string
|
|
}
|
|
|
|
func loadConfig(getenv func(string) string) (Config, error) {
|
|
get := func(key, def string) string {
|
|
if v := strings.TrimSpace(getenv(key)); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
c := Config{
|
|
ClientSecret: strings.TrimSpace(getenv("WLAN_SETUP_CLIENT_SECRET")),
|
|
AuthentikURL: strings.TrimRight(get("AUTHENTIK_INTERNAL_URL", "http://authentik-server.authentik.svc.cluster.local"), "/"),
|
|
AuthorizeURL: get("AUTHENTIK_AUTHORIZE_URL", "https://auth.renner.uno/application/o/authorize/"),
|
|
PublicURL: strings.TrimRight(get("PUBLIC_URL", "https://wlan.renner.uno"), "/"),
|
|
SigningKey: get("SIGNING_KEY", "/etc/wlan-signing/tls.key"),
|
|
SigningCert: get("SIGNING_CERT", "/etc/wlan-signing/tls.crt"),
|
|
Listen: get("LISTEN", ":8080"),
|
|
}
|
|
var errs []error
|
|
if c.ClientSecret == "" {
|
|
errs = append(errs, errors.New("WLAN_SETUP_CLIENT_SECRET is not set"))
|
|
}
|
|
for key, v := range map[string]string{
|
|
"AUTHENTIK_INTERNAL_URL": c.AuthentikURL,
|
|
"AUTHENTIK_AUTHORIZE_URL": c.AuthorizeURL,
|
|
"PUBLIC_URL": c.PublicURL,
|
|
} {
|
|
if u, err := url.Parse(v); err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
|
|
errs = append(errs, errors.New(key+" must be an absolute http(s) URL"))
|
|
}
|
|
}
|
|
return c, errors.Join(errs...)
|
|
}
|