Compare commits

...
Author SHA1 Message Date
k.renner 5718c9bae2 Merge pull request 'feat(radius): Apple Passpoint profile with a per-device app password' (#1568) from feat/wlan-setup-apple-passpoint into main
Reviewed-on: #1568
2026-11-05 13:03:12 +00:00
k.renner 2c79edabea Merge pull request 'docs(radius): Renner UniFi is WPA3 Enterprise with Passpoint' (#1567) from docs/dot1x-passpoint-renner-unifi into main
Reviewed-on: #1567
2026-11-05 13:02:23 +00:00
claude-botandClaude Opus 5.5 6e12a608b3 docs(radius): Passpoint setup for Android and Apple
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
Android and Apple get Passpoint profiles with their own app password from
wlan.renner.uno; the manual Android steps with the account password are
removed. Windows and Linux keep their setup files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:00:55 +01:00
claude-botandClaude Opus 5.5 5718492e2b feat(radius): Apple Passpoint profile with a per-device app password
wlan.renner.uno serves Apple devices the same way as Android: /apple/install
signs in through the wlan-setup OAuth application, /apple/callback creates
an app password (wlan-apple-...) with the user's own access token and returns
a .mobileconfig with Passpoint (IsHotspot, domain and NAI realm renner.uno),
EAP-TTLS/PAP, outer identity anonymous, trusted server name
radius.renner.uno, username and app password. The static profile without a
password is removed; its PayloadIdentifier/UUIDs are kept so the new profile
replaces it on install. The OAuth provider gets the redirect URI
https://wlan.renner.uno/apple/callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:00:16 +01:00
claude-botandClaude Opus 5.5 3bfb38ebd7 docs(radius): Renner UniFi is WPA3 Enterprise with Passpoint
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
"Renner UniFi" now runs WPA3 Enterprise without transition mode and
advertises Passpoint (realm and domain renner.uno, EAP-TTLS/PAP), so the
Android profiles from wlan.renner.uno join it directly. The table row for
the deleted "Renner Test" WLAN is replaced; the Windows manual setup uses
WPA3-Enterprise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 13:53:12 +01:00
k.renner 1de63af07b Merge pull request 'feat(radius): Android WLAN profile with a per-device app password' (#1566) from feat/dot1x-app-passwords into main
Reviewed-on: #1566
2026-11-05 12:19:11 +00:00
3 changed files with 127 additions and 123 deletions
+34 -30
View File
@@ -125,7 +125,15 @@ Created through the UniFi Network API (site `default`):
|---|---|---|
| Firewall policy "Allow APs RADIUS" | `62c21e63-8c15-4720-adf8-b2333c090e2f` | zone Isolated `10.2.10.0/24` → zone External `10.2.99.91`, UDP `1812-1813`, ALLOW, IPv4 |
| RADIUS profile "Cluster 802.1X" | `3e5fcfed-63dc-4e7d-ad51-17cbc074e4bb` | auth `10.2.99.91:1812`, acct `10.2.99.91:1813`, secret `DOT1X_NAS_SECRET`, VLAN assignment on (`vlan_wlan_mode: optional`) |
| WLAN "Renner Test" | `3eba27e7-ddc2-41fb-ad3f-82add317847a` | copy of "Renner UniFi" (WPA2/WPA3 Enterprise transition, fast roaming, BSS transition, same AP group and bands), network (90) Guest as fallback, RADIUS profile "Cluster 802.1X" |
| WLAN "Renner UniFi" | `ef4122f2-4a83-4dca-9ef3-468d29f39a6b` | WPA3 Enterprise (no transition), PMF required, fast roaming, BSS transition, client isolation off, RADIUS profile "Cluster 802.1X"; Application Hotspot, type Passpoint (set in the UniFi UI: the API format differs from the UI's) |
Passpoint on "Renner UniFi" (UniFi offers Passpoint only with WPA3 Enterprise):
venue "Renner", Residential / Private Residence, network type Private with
Guest Access, IPv4 single NATed private, IPv6 available, NAI realm
`renner.uno` with EAP-TTLS, sub-methods PAP and username/password, domain
`renner.uno`, operator friendly name "Renner", connection capability ICMP
allow. The AKMs on air are `FT/802.1X` and `802.1X/SHA-256`; plain `802.1X`
is not offered.
## Live login check
@@ -146,20 +154,22 @@ For IPv6 set `LIVE_SOURCE` to the workstation's `fd02:50::` address and use
## Client setup (SSID "Renner UniFi")
Setup page: `https://wlan.renner.uno` (behind the Authentik gate, any
authentik user; `kubernetes/apps/authentik/wlan-setup*.yaml`). It serves the
Apple profile (caller's username filled in), a Windows file that imports the
WLAN profile with `netsh`, and the Linux `nmcli` command. None of these carries a password.
authentik user; `kubernetes/apps/authentik/wlan-setup*.yaml`). Android and
Apple get Passpoint profiles with their own app password; Windows gets a file
that imports the WLAN profile with `netsh`, Linux an `nmcli` command
(NetworkManager has no Passpoint support). The Windows and Linux setups carry
no password.
Android gets a Passpoint profile (`application/x-wifi-config`) with its own
app password. "Auf Android installieren" (`/android/install`) signs the user in
through the authentik OAuth2 application `wlan-setup` (scope
`goauthentik.io/api`). On `/android/callback`, nginx (njs) exchanges the code,
creates an app password (`wlan-android-<user>-<timestamp>-<random>`) with the
user's own access token, and returns the profile in the response to that GET,
as the Android installer requires. The page stores nothing. Deleting the app
password in authentik removes that device from the WLAN. The profile matches
WLANs that advertise Hotspot 2.0 with domain and NAI realm `renner.uno`
(EAP-TTLS/PAP). Creating the app password needs no admin rights.
Passpoint (Android, Apple): `/<platform>/install` (`android` or `apple`) signs
the user in through the authentik OAuth2 application `wlan-setup` (scope
`goauthentik.io/api`). On `/<platform>/callback`, nginx (njs) exchanges the
code, creates an app password (`wlan-<platform>-<user>-<timestamp>-<random>`)
with the user's own access token, and returns the profile in the response to
that GET: Android `application/x-wifi-config` (as its installer requires),
Apple a `.mobileconfig`. The page stores nothing. Deleting the app password in
authentik removes that device from the WLAN. The profiles match WLANs that
advertise Hotspot 2.0 with domain and NAI realm `renner.uno` (EAP-TTLS/PAP),
i.e. "Renner UniFi". Creating the app password needs no admin rights.
App passwords expire when unused. The page creates them with 29 days (the API
caps new tokens at 30 days unless the group attribute
@@ -179,14 +189,7 @@ is never sent in clear over the air.
### Android
- EAP method: TTLS
- Phase 2 authentication: PAP
- CA certificate: Use system certificates
- Domain: `radius.renner.uno`
- Identity: authentik username
- Anonymous identity: `anonymous` (mandatory; empty sends the login to the
UDM, where it fails)
- Password: authentik password
Passpoint profile from the setup page ("Auf Android installieren").
### Linux (NetworkManager)
@@ -203,7 +206,7 @@ is never sent in clear over the air.
Settings > Network & Internet > Wi-Fi > Manage known networks > Add network:
- Network name: `Renner UniFi`
- Security type: WPA2-Enterprise AES
- Security type: WPA3-Enterprise AES
- EAP method: EAP-TTLS
- Authentication method: Unencrypted password (PAP)
- Server validation: where offered ("Verify server identity" / trusted
@@ -218,13 +221,14 @@ wireless network" instead.
### Apple (iOS, iPadOS, macOS)
Apple devices need a configuration profile; the setup page serves it with the
username filled in. Install it via Settings (Profile Downloaded). The device
asks for the password on the first join. The profile sets security type Any (WPA2/WPA3), outer identity
`anonymous` and trusted server name `radius.renner.uno`; it contains no
password and no certificate. Apple
devices may show a one-time "trust certificate" prompt for `radius.renner.uno`
on the first join.
Passpoint configuration profile from the setup page ("Profil laden"),
installed via Settings (Profile Downloaded) or, on a Mac, System Settings >
General > Device Management. It sets `IsHotspot` with domain and NAI realm
`renner.uno` (no SSID), security type Any, outer identity `anonymous`,
trusted server name `radius.renner.uno`, username and app password; it
contains no certificate. Its PayloadIdentifier is fixed, so installing it
replaces an earlier profile. Apple devices may show a one-time "trust
certificate" prompt for `radius.renner.uno` on the first join.
## Measurement: authentication latency per SSID
@@ -1698,6 +1698,8 @@ data:
redirect_uris:
- url: https://wlan.renner.uno/android/callback
matching_mode: strict
- url: https://wlan.renner.uno/apple/callback
matching_mode: strict
- model: authentik_core.application
identifiers:
@@ -1,9 +1,9 @@
# wlan.renner.uno: setup files for "Renner UniFi" (802.1X, EAP-TTLS/PAP
# against freeradius, outer identity anonymous, server name radius.renner.uno).
# Served by wlan-setup (wlan-setup.yaml) behind the Authentik gate; the
# username comes from X-authentik-username. Only the Android Passpoint profile
# carries a credential (the format requires it): a per-device authentik app
# password that the page creates with the user's own OAuth access token.
# username comes from X-authentik-username. The Android and Apple Passpoint
# profiles carry a credential: a per-device authentik app password that the
# page creates with the user's own OAuth access token.
apiVersion: v1
kind: ConfigMap
metadata:
@@ -77,75 +77,6 @@ data:
return 200 $wifi_user;
}
# Apple: com.apple.wifi.managed, TTLS (21) with inner PAP. Fixed
# PayloadIdentifier/UUIDs so a reinstall replaces the old profile.
location = /renner-unifi.mobileconfig {
default_type application/x-apple-aspen-config;
add_header Cache-Control "no-store" always;
add_header Content-Disposition 'attachment; filename="renner-unifi.mobileconfig"' always;
return 200 '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadType</key>
<string>com.apple.wifi.managed</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadIdentifier</key>
<string>uno.renner.wifi.renner-unifi.network</string>
<key>PayloadUUID</key>
<string>824959bf-c55d-4ed2-b569-c33f3759c2b6</string>
<key>PayloadDisplayName</key>
<string>Renner UniFi</string>
<key>PayloadOrganization</key>
<string>Renner</string>
<key>SSID_STR</key>
<string>Renner UniFi</string>
<key>HIDDEN_NETWORK</key>
<false/>
<key>AutoJoin</key>
<true/>
<key>EncryptionType</key>
<string>Any</string>
<key>EAPClientConfiguration</key>
<dict>
<key>UserName</key>
<string>$wifi_user</string>
<key>OuterIdentity</key>
<string>anonymous</string>
<key>AcceptEAPTypes</key>
<array>
<integer>21</integer>
</array>
<key>TTLSInnerAuthentication</key>
<string>PAP</string>
<key>TLSTrustedServerNames</key>
<array>
<string>radius.renner.uno</string>
</array>
</dict>
</dict>
</array>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadIdentifier</key>
<string>uno.renner.wifi.renner-unifi</string>
<key>PayloadUUID</key>
<string>7175a2a3-ddd3-42ea-b4ad-b7e5501892f3</string>
<key>PayloadDisplayName</key>
<string>WLAN Renner UniFi</string>
<key>PayloadOrganization</key>
<string>Renner</string>
</dict>
</plist>
';
}
location = /renner-unifi-wlan.cmd {
default_type application/octet-stream;
add_header Cache-Control "no-store" always;
@@ -153,16 +84,17 @@ data:
try_files /renner-unifi-wlan.cmd =404;
}
# Android: a tap on /android/install starts an authorization-code
# sign-in at authentik (the user is already signed in there); the
# callback creates the app password as the user and answers the same
# navigation with the Passpoint profile (application/x-wifi-config,
# base64, no Content-Disposition), as the Android installer requires.
location = /android/install {
# Android and Apple: a tap on /<platform>/install starts an
# authorization-code sign-in at authentik (the user is already signed
# in there); the callback creates the app password as the user and
# answers the same navigation with the Passpoint profile. Android:
# application/x-wifi-config, base64, no Content-Disposition, as its
# installer requires. Apple: a .mobileconfig download.
location ~ ^/(android|apple)/install$ {
js_content passpoint.install;
}
location = /android/callback {
location ~ ^/(android|apple)/callback$ {
# The query carries the one-time authorization code.
access_log off;
js_content passpoint.callback;
@@ -216,6 +148,11 @@ data:
# (authorization code, scope goauthentik.io/api). It starts with 29 days
# (below the 30-day token cap); each 802.1X login renews it to 60 days
# (policy dot1x-app-password-renew).
# Apple: com.apple.wifi.managed with IsHotspot, DomainName and NAIRealmNames
# renner.uno (no SSID: Passpoint matching), TTLS (21) with inner PAP, outer
# identity anonymous, trusted server name radius.renner.uno, username and
# app password. Fixed PayloadIdentifier/UUIDs so a reinstall replaces the
# previous profile.
passpoint.js: |
const ISRG_ROOT_X1 = "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZLubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=";
const USER = /^[A-Za-z0-9._@+-]{1,64}$/;
@@ -253,8 +190,60 @@ data:
return b64(mime);
}
function xml(s) {
return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function mobileconfig(user, password) {
return '<?xml version="1.0" encoding="UTF-8"?>\n' +
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n' +
'<plist version="1.0"><dict>' +
'<key>PayloadContent</key><array><dict>' +
'<key>PayloadType</key><string>com.apple.wifi.managed</string>' +
'<key>PayloadVersion</key><integer>1</integer>' +
'<key>PayloadIdentifier</key><string>uno.renner.wifi.renner-unifi.network</string>' +
'<key>PayloadUUID</key><string>824959bf-c55d-4ed2-b569-c33f3759c2b6</string>' +
'<key>PayloadDisplayName</key><string>Renner UniFi</string>' +
'<key>PayloadOrganization</key><string>Renner</string>' +
'<key>IsHotspot</key><true/>' +
'<key>DomainName</key><string>renner.uno</string>' +
'<key>NAIRealmNames</key><array><string>renner.uno</string></array>' +
'<key>DisplayedOperatorName</key><string>Renner</string>' +
'<key>ServiceProviderRoamingEnabled</key><false/>' +
'<key>AutoJoin</key><true/>' +
'<key>EncryptionType</key><string>Any</string>' +
'<key>EAPClientConfiguration</key><dict>' +
'<key>UserName</key><string>' + xml(user) + '</string>' +
'<key>UserPassword</key><string>' + xml(password) + '</string>' +
'<key>OuterIdentity</key><string>anonymous</string>' +
'<key>AcceptEAPTypes</key><array><integer>21</integer></array>' +
'<key>TTLSInnerAuthentication</key><string>PAP</string>' +
'<key>TLSTrustedServerNames</key><array><string>radius.renner.uno</string></array>' +
'</dict></dict></array>' +
'<key>PayloadType</key><string>Configuration</string>' +
'<key>PayloadVersion</key><integer>1</integer>' +
'<key>PayloadIdentifier</key><string>uno.renner.wifi.renner-unifi</string>' +
'<key>PayloadUUID</key><string>7175a2a3-ddd3-42ea-b4ad-b7e5501892f3</string>' +
'<key>PayloadDisplayName</key><string>WLAN Renner UniFi</string>' +
'<key>PayloadOrganization</key><string>Renner</string>' +
'</dict></plist>\n';
}
const PLATFORMS = {
android: { label: "Android" },
apple: { label: "Apple" },
};
// "android" or "apple" from /<platform>/install or /<platform>/callback.
function platform(r) {
return r.uri.split("/")[1];
}
function redirectUri(name) {
return "https://wlan.renner.uno/" + name + "/callback";
}
const CLIENT_ID = "wlan-setup";
const REDIRECT_URI = "https://wlan.renner.uno/android/callback";
const AUTHORIZE = "https://auth.renner.uno/application/o/authorize/";
const STATE_COOKIE = "wlan_oauth_state";
const LIFETIME_DAYS = 29;
@@ -300,19 +289,21 @@ data:
}
function install(r) {
const name = platform(r);
const state = random();
r.headersOut["Set-Cookie"] = STATE_COOKIE + "=" + state +
"; Path=/android/; Max-Age=300; HttpOnly; Secure; SameSite=Lax";
"; Path=/" + name + "/; Max-Age=300; HttpOnly; Secure; SameSite=Lax";
r.return(302, AUTHORIZE + "?" + form({
response_type: "code",
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
redirect_uri: redirectUri(name),
scope: "openid profile goauthentik.io/api",
state: state,
}));
}
async function callback(r) {
const name = platform(r);
try {
const state = cookie(r, STATE_COOKIE);
if (!state || r.args.state !== state || !r.args.code) { r.return(400, "Bitte die Einrichtung neu starten.\n"); return; }
@@ -320,7 +311,7 @@ data:
const grant = await ak(r, "POST", "/application/o/token/", "Basic", client, FORM, form({
grant_type: "authorization_code",
code: r.args.code,
redirect_uri: REDIRECT_URI,
redirect_uri: redirectUri(name),
}));
const access = grant.access_token;
const me = await ak(r, "GET", "/api/v3/core/users/me/", "Bearer", access, "");
@@ -329,23 +320,29 @@ data:
const now = new Date();
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\..*$/, "");
const identifier = "wlan-android-" + user.replace(/[^A-Za-z0-9-]/g, "-").toLowerCase() + "-" + stamp + "-" + random().substring(0, 6).replace(/[^A-Za-z0-9]/g, "x");
const identifier = "wlan-" + name + "-" + user.replace(/[^A-Za-z0-9-]/g, "-").toLowerCase() + "-" + stamp + "-" + random().substring(0, 6).replace(/[^A-Za-z0-9]/g, "x");
const expires = new Date(now.getTime() + LIFETIME_DAYS * 86400000).toISOString();
await ak(r, "POST", "/api/v3/core/tokens/", "Bearer", access, JSON_CT, JSON.stringify({
identifier: identifier,
intent: "app_password",
description: "WLAN Android, " + now.toISOString().substring(0, 10) + " (wlan.renner.uno)",
description: "WLAN " + PLATFORMS[name].label + ", " + now.toISOString().substring(0, 10) + " (wlan.renner.uno)",
expiring: true,
expires: expires,
}));
const key = (await ak(r, "GET", "/api/v3/core/tokens/" + identifier + "/view_key/", "Bearer", access, "")).key;
r.headersOut["Set-Cookie"] = STATE_COOKIE + "=; Path=/android/; Max-Age=0; HttpOnly; Secure; SameSite=Lax";
r.headersOut["Content-Type"] = "application/x-wifi-config";
r.headersOut["Content-Transfer-Encoding"] = "base64";
r.return(200, profile(user, key));
r.headersOut["Set-Cookie"] = STATE_COOKIE + "=; Path=/" + name + "/; Max-Age=0; HttpOnly; Secure; SameSite=Lax";
if (name === "apple") {
r.headersOut["Content-Type"] = "application/x-apple-aspen-config";
r.headersOut["Content-Disposition"] = 'attachment; filename="renner-unifi.mobileconfig"';
r.return(200, mobileconfig(user, key));
} else {
r.headersOut["Content-Type"] = "application/x-wifi-config";
r.headersOut["Content-Transfer-Encoding"] = "base64";
r.return(200, profile(user, key));
}
} catch (e) {
r.error("wlan-setup android: " + e.message);
r.error("wlan-setup " + name + ": " + e.message);
r.return(502, "Die Einrichtung ist fehlgeschlagen.\n");
}
}
@@ -383,7 +380,7 @@ data:
<body>
<main>
<h1>WLAN einrichten</h1>
<p>WLAN <strong>Renner UniFi</strong>. Anmeldung mit deinem Konto <strong id="user">…</strong> und deinem authentik-Passwort.</p>
<p>WLAN <strong>Renner UniFi</strong> für dein Konto <strong id="user">…</strong>. Android, iPhone, iPad und Mac bekommen ein eigenes WLAN-App-Passwort; Windows und Linux melden sich mit deinem authentik-Passwort an.</p>
<div id="detected"></div>
@@ -403,11 +400,12 @@ data:
<template id="t-apple">
<section data-os="apple">
<h2>iPhone, iPad, Mac</h2>
<p><a class="button" href="/renner-unifi.mobileconfig">Profil laden</a></p>
<p><a class="button" href="/apple/install">Profil laden</a></p>
<ol>
<li>iPhone/iPad: Einstellungen → „Profil geladen“ → Installieren. Mac: Systemeinstellungen → Allgemein → Geräteverwaltung → Profil doppelklicken.</li>
<li>Beim ersten Verbinden mit „Renner UniFi“ dein Passwort eingeben.</li>
<li>Das Gerät verbindet sich danach selbst mit „Renner UniFi“.</li>
</ol>
<p class="muted">Das Gerät bekommt ein eigenes WLAN-App-Passwort in deinem authentik-Konto; dort gelöscht, ist das Gerät aus dem WLAN.</p>
</section>
</template>