Add PEAP, TTLS and server domain checks for enterprise wifi

This commit is contained in:
SirBlob committed 2026-09-24 11:45:01 -04:00
1 parent 4ad1a384cc
commit ce2fb8c8b6
2 files changed
+99 -14

No files matched your search

+23 -3
View File
@@ -317,14 +317,31 @@ function canForgetNetwork(network) {
// must never be an argument (printf is a bash builtin, so no process spawns
// with it either).
var enterpriseConnectScript =
"u=$(uuidgen); IFS= read -r pw;" +
"u=$(uuidgen); IFS= read -r pw; server_check=();" +
" [ -n \"$5\" ] && server_check=(802-1x.system-ca-certs yes 802-1x.domain-suffix-match \"$5\");" +
" nmcli connection add type wifi con-name \"$1\" ssid \"$1\" connection.uuid \"$u\"" +
" wifi-sec.key-mgmt wpa-eap 802-1x.eap peap 802-1x.phase2-auth mschapv2" +
" 802-1x.identity \"$2\" 802-1x.auth-timeout 8 >/dev/null" +
" wifi-sec.key-mgmt wpa-eap 802-1x.eap \"$3\" 802-1x.phase2-auth \"$4\"" +
" 802-1x.identity \"$2\" 802-1x.auth-timeout 8 \"${server_check[@]}\" >/dev/null" +
" && printf 'set 802-1x.password %s\\nsave\\nquit\\n' \"$pw\" | nmcli connection edit uuid \"$u\" >/dev/null" +
" && nmcli connection up uuid \"$u\"" +
" || { nmcli connection delete uuid \"$u\" >/dev/null 2>&1; false; }"
var eapMethods = [
{ value: "peap", label: "PEAP", tooltip: "PEAP with MSCHAPv2", eap: "peap", phase2: "mschapv2" },
{ value: "ttls", label: "TTLS", tooltip: "TTLS with PAP", eap: "ttls", phase2: "pap" }
]
function eapMethodFor(value) {
for (var i = 0; i < eapMethods.length; i++) {
if (eapMethods[i].value === value) return eapMethods[i]
}
return eapMethods[0]
}
function isEnterpriseSecurity(security, enterpriseSecurityTypes) {
return (enterpriseSecurityTypes || []).indexOf(security) !== -1
}
function networkFailureReason(reason, needsCredentials, reasons) {
var r = reasons || {}
if (needsCredentials && reason === r.NoSecrets) return "Passphrase required"
@@ -374,6 +391,9 @@ if (typeof module !== "undefined") {
requiresCredentials: requiresCredentials,
canForgetNetwork: canForgetNetwork,
enterpriseConnectScript: enterpriseConnectScript,
eapMethods: eapMethods,
eapMethodFor: eapMethodFor,
isEnterpriseSecurity: isEnterpriseSecurity,
networkFailureReason: networkFailureReason,
shouldRepromptPassphrase: shouldRepromptPassphrase
}
+76 -11
View File
@@ -26,6 +26,8 @@ Panel {
passwordSsid = ""
passwordText = ""
identityText = ""
serverDomainText = ""
eapMethod = "peap"
}
// Live connection details from `ip` / /sys / iw.
@@ -97,6 +99,14 @@ Panel {
property string passwordSsid: ""
property string passwordText: ""
property string identityText: ""
property string serverDomainText: ""
property string eapMethod: "peap"
readonly property var enterpriseSecurityTypes: [
WifiSecurityType.WpaEap,
WifiSecurityType.Wpa2Eap,
WifiSecurityType.Wpa3SuiteB192
]
// ConnectionFailReason values as a plain object, so Model.js helpers stay
// pure JS and Node-testable.
@@ -403,7 +413,11 @@ Panel {
function canShareNetwork(net) {
if (!net || !net.connected) return false
return net.security !== WifiSecurityType.Wpa2Eap && net.security !== WifiSecurityType.WpaEap
return !isEnterpriseSecurity(net.security)
}
function isEnterpriseSecurity(security) {
return Model.isEnterpriseSecurity(security, enterpriseSecurityTypes)
}
function selectWifiActionByDelta(delta) {
@@ -685,9 +699,17 @@ Panel {
}
function openPasswordPrompt(ssid) {
var network = networkForSsid(ssid)
if (network && network.security === WifiSecurityType.Wpa3SuiteB192) {
failureSsid = ssid
failureReason = "Needs a certificate, use nm-connection-editor"
return
}
if (passwordSsid !== ssid) {
passwordText = ""
identityText = ""
serverDomainText = ""
eapMethod = "peap"
}
passwordSsid = ssid
}
@@ -766,8 +788,10 @@ Panel {
function connectEnterprise(ssid, identity, passphrase) {
runNetworkAction("connect", networkForSsid(ssid), function(network) {
var method = Model.eapMethodFor(root.eapMethod)
enterpriseConnect.secret = passphrase
enterpriseConnect.command = ["bash", "-c", Model.enterpriseConnectScript, "nmcli-eap", ssid, identity]
enterpriseConnect.command = ["bash", "-c", Model.enterpriseConnectScript, "nmcli-eap",
ssid, identity, method.eap, method.phase2, root.serverDomainText.trim()]
enterpriseConnect.running = true
})
}
@@ -782,6 +806,9 @@ Panel {
write(secret + "\n")
secret = ""
}
onExited: function(exitCode) {
if (exitCode !== 0 && root.actionKind === "connect") root.failNetworkAction(root.networkForSsid(root.actionSsid), -1)
}
}
function disconnect(network) {
@@ -1601,9 +1628,7 @@ Panel {
readonly property bool isConnected: net && net.connected
readonly property bool isKnown: !!(net && net.known)
readonly property bool requiresCredentials: net ? root.requiresCredentials(net.security) : false
readonly property bool isEnterprise: net
? (net.security === WifiSecurityType.Wpa2Eap || net.security === WifiSecurityType.WpaEap)
: false
readonly property bool isEnterprise: net ? root.isEnterpriseSecurity(net.security) : false
readonly property bool canForget: root.canForgetNetwork(net)
readonly property bool isSelected: root.focusSection === "wifi" && root.selectedIndex === index
readonly property bool forgetFocused: isSelected && root.wifiActionFocused && canForget
@@ -1835,15 +1860,33 @@ Panel {
anchors.leftMargin: Style.space(10)
anchors.rightMargin: Style.space(10)
anchors.topMargin: Style.space(4)
implicitHeight: (idField.visible ? idField.implicitHeight + Style.space(4) : 0) + pwField.implicitHeight + Style.spacing.rowGap
readonly property bool enterpriseFieldsVisible: row.isEnterprise && !row.isBusy && !row.isFailed
readonly property real enterpriseFieldsHeight: methodGroup.implicitHeight + idField.implicitHeight
+ domainField.implicitHeight + Style.space(4) * 3
implicitHeight: (enterpriseFieldsVisible ? enterpriseFieldsHeight : 0) + pwField.implicitHeight + Style.spacing.rowGap
height: implicitHeight
ButtonGroup {
id: methodGroup
visible: passwordPanel.enterpriseFieldsVisible
anchors.left: parent.left
anchors.top: parent.top
options: Model.eapMethods
value: root.eapMethod
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
fontSize: Style.font.bodySmall
focusable: false
onChanged: function(selectedMethod) { root.eapMethod = selectedMethod }
}
TextField {
id: idField
visible: row.isEnterprise && !row.isBusy && !row.isFailed
visible: passwordPanel.enterpriseFieldsVisible
anchors.left: parent.left
anchors.right: connectPwBtn.left
anchors.top: parent.top
anchors.top: methodGroup.bottom
anchors.topMargin: Style.space(4)
anchors.rightMargin: Style.space(6)
placeholderText: "Identity (user@domain)"
font.family: Style.font.family
@@ -1854,7 +1897,7 @@ Panel {
enabled: !row.isBusy
text: row.isPasswordOpen ? root.identityText : ""
onAccepted: pwField.forceActiveFocus()
onAccepted: domainField.forceActiveFocus()
onTextChanged: if (row.isPasswordOpen && text !== root.identityText) root.identityText = text
Keys.onEscapePressed: root.cancelPasswordPrompt()
@@ -1862,6 +1905,28 @@ Panel {
Component.onCompleted: if (visible) Qt.callLater(forceActiveFocus)
}
TextField {
id: domainField
visible: passwordPanel.enterpriseFieldsVisible
anchors.left: parent.left
anchors.right: connectPwBtn.left
anchors.top: idField.bottom
anchors.topMargin: Style.space(4)
anchors.rightMargin: Style.space(6)
placeholderText: "Server domain (optional, verifies the network)"
font.family: Style.font.family
font.pixelSize: Style.font.body
foreground: root.bar.foreground
horizontalPadding: Style.spacing.controlGap
verticalPadding: Style.spacing.controlPaddingY
enabled: !row.isBusy
text: row.isPasswordOpen ? root.serverDomainText : ""
onAccepted: pwField.forceActiveFocus()
onTextChanged: if (row.isPasswordOpen && text !== root.serverDomainText) root.serverDomainText = text
Keys.onEscapePressed: root.cancelPasswordPrompt()
}
TextField {
id: pwField
visible: !row.isBusy && !row.isFailed
@@ -1904,7 +1969,7 @@ Panel {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: row.isFailed ? "Wrong password" : "Connecting..."
text: row.isFailed ? (root.failureReason || "Failed to connect") : "Connecting..."
color: row.isFailed ? root.bar.urgent : root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -1918,7 +1983,7 @@ Panel {
id: connectPwBtn
visible: !row.isBusy && !row.isFailed
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: pwField.verticalCenter
enabled: row.net && pwField.text.length > 0 && (!row.isEnterprise || idField.text.length > 0)
iconText: "󰄬"
tooltipText: "Connect"