Merge pull request #6334 from KazeTachinuu/enterprise-8021x-wifi
Connect to enterprise (802.1X) Wi-Fi networks from the network panel
This commit is contained in:
@@ -232,6 +232,19 @@ function isProtected(security, openSecurity) {
|
|||||||
return security !== openSecurity
|
return security !== openSecurity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The password arrives on stdin and reaches nmcli through the scriptable
|
||||||
|
// `connection edit` editor -- argv is world-readable in /proc, so the secret
|
||||||
|
// 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;" +
|
||||||
|
" 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" +
|
||||||
|
" && 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; }"
|
||||||
|
|
||||||
function networkFailureReason(reason, reasons) {
|
function networkFailureReason(reason, reasons) {
|
||||||
var r = reasons || {}
|
var r = reasons || {}
|
||||||
if (reason === r.NoSecrets) return "Passphrase required"
|
if (reason === r.NoSecrets) return "Passphrase required"
|
||||||
@@ -263,6 +276,7 @@ if (typeof module !== "undefined") {
|
|||||||
sortWifiRows: sortWifiRows,
|
sortWifiRows: sortWifiRows,
|
||||||
wifiSectionTitle: wifiSectionTitle,
|
wifiSectionTitle: wifiSectionTitle,
|
||||||
isProtected: isProtected,
|
isProtected: isProtected,
|
||||||
|
enterpriseConnectScript: enterpriseConnectScript,
|
||||||
networkFailureReason: networkFailureReason
|
networkFailureReason: networkFailureReason
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ Panel {
|
|||||||
// Centralized close so callers can't forget to drop the passphrase prompt.
|
// Centralized close so callers can't forget to drop the passphrase prompt.
|
||||||
function close() {
|
function close() {
|
||||||
root.controller.hide()
|
root.controller.hide()
|
||||||
|
cancelPasswordPrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelPasswordPrompt() {
|
||||||
passwordSsid = ""
|
passwordSsid = ""
|
||||||
|
passwordText = ""
|
||||||
|
identityText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live connection details from `ip` / /sys / iw.
|
// Live connection details from `ip` / /sys / iw.
|
||||||
@@ -84,6 +90,7 @@ Panel {
|
|||||||
property string failureReason: ""
|
property string failureReason: ""
|
||||||
property string passwordSsid: ""
|
property string passwordSsid: ""
|
||||||
property string passwordText: ""
|
property string passwordText: ""
|
||||||
|
property string identityText: ""
|
||||||
|
|
||||||
// True while any wifi action is mid-flight. Rows
|
// True while any wifi action is mid-flight. Rows
|
||||||
// disable themselves on this so clicks on the other rows don't silently
|
// disable themselves on this so clicks on the other rows don't silently
|
||||||
@@ -489,7 +496,10 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openPasswordPrompt(ssid) {
|
function openPasswordPrompt(ssid) {
|
||||||
if (passwordSsid !== ssid) passwordText = ""
|
if (passwordSsid !== ssid) {
|
||||||
|
passwordText = ""
|
||||||
|
identityText = ""
|
||||||
|
}
|
||||||
passwordSsid = ssid
|
passwordSsid = ssid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,6 +577,26 @@ Panel {
|
|||||||
runNetworkAction("connect", networkForSsid(ssid), function(network) { network.connectWithPsk(passphrase) })
|
runNetworkAction("connect", networkForSsid(ssid), function(network) { network.connectWithPsk(passphrase) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function connectEnterprise(ssid, identity, passphrase) {
|
||||||
|
runNetworkAction("connect", networkForSsid(ssid), function(network) {
|
||||||
|
enterpriseConnect.secret = passphrase
|
||||||
|
enterpriseConnect.command = ["bash", "-c", Model.enterpriseConnectScript, "nmcli-eap", ssid, identity]
|
||||||
|
enterpriseConnect.running = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates and activates the 802.1X profile (see Model.enterpriseConnectScript).
|
||||||
|
// The password goes over stdin, never argv.
|
||||||
|
Process {
|
||||||
|
id: enterpriseConnect
|
||||||
|
property string secret: ""
|
||||||
|
stdinEnabled: true
|
||||||
|
onStarted: {
|
||||||
|
write(secret + "\n")
|
||||||
|
secret = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function disconnect(network) {
|
function disconnect(network) {
|
||||||
runNetworkAction("disconnect", network || connectedWifiNetwork, function(net) { net.disconnect() })
|
runNetworkAction("disconnect", network || connectedWifiNetwork, function(net) { net.disconnect() })
|
||||||
}
|
}
|
||||||
@@ -1235,6 +1265,9 @@ Panel {
|
|||||||
readonly property bool isConnected: net && net.connected
|
readonly property bool isConnected: net && net.connected
|
||||||
readonly property bool isKnown: !!(net && net.known)
|
readonly property bool isKnown: !!(net && net.known)
|
||||||
readonly property bool isProtected: net ? root.isProtected(net.security) : false
|
readonly property bool isProtected: net ? root.isProtected(net.security) : false
|
||||||
|
readonly property bool isEnterprise: net
|
||||||
|
? (net.security === WifiSecurityType.Wpa2Eap || net.security === WifiSecurityType.WpaEap)
|
||||||
|
: false
|
||||||
readonly property bool canForgetFromLock: isKnown && isProtected && !isConnected
|
readonly property bool canForgetFromLock: isKnown && isProtected && !isConnected
|
||||||
readonly property bool isSelected: root.focusSection === "wifi" && root.selectedIndex === index
|
readonly property bool isSelected: root.focusSection === "wifi" && root.selectedIndex === index
|
||||||
readonly property bool forgetFocused: isSelected && root.wifiActionFocused && canForgetFromLock
|
readonly property bool forgetFocused: isSelected && root.wifiActionFocused && canForgetFromLock
|
||||||
@@ -1251,6 +1284,12 @@ Panel {
|
|||||||
readonly property bool isFailed: root.failureReason !== "" && root.failureSsid === (net ? net.ssid : "")
|
readonly property bool isFailed: root.failureReason !== "" && root.failureSsid === (net ? net.ssid : "")
|
||||||
readonly property bool isPasswordOpen: root.passwordSsid !== "" && root.passwordSsid === (net ? net.ssid : "")
|
readonly property bool isPasswordOpen: root.passwordSsid !== "" && root.passwordSsid === (net ? net.ssid : "")
|
||||||
|
|
||||||
|
function submitCredentials() {
|
||||||
|
if (!net || root.busy || root.passwordText.length === 0) return
|
||||||
|
if (!isEnterprise) return root.connectWithPassphrase(net.ssid, root.passwordText)
|
||||||
|
if (root.identityText.length > 0) root.connectEnterprise(net.ssid, root.identityText, root.passwordText)
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: row.net ? row.net.network : null
|
target: row.net ? row.net.network : null
|
||||||
function onConnectionFailed(reason) {
|
function onConnectionFailed(reason) {
|
||||||
@@ -1450,15 +1489,40 @@ Panel {
|
|||||||
anchors.leftMargin: Style.space(10)
|
anchors.leftMargin: Style.space(10)
|
||||||
anchors.rightMargin: Style.space(10)
|
anchors.rightMargin: Style.space(10)
|
||||||
anchors.topMargin: Style.space(4)
|
anchors.topMargin: Style.space(4)
|
||||||
implicitHeight: pwField.implicitHeight + Style.spacing.rowGap
|
implicitHeight: (idField.visible ? idField.implicitHeight + Style.space(4) : 0) + pwField.implicitHeight + Style.spacing.rowGap
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: idField
|
||||||
|
visible: row.isEnterprise && !row.isBusy && !row.isFailed
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: connectPwBtn.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.rightMargin: Style.space(6)
|
||||||
|
placeholderText: "Identity (user@domain)"
|
||||||
|
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.identityText : ""
|
||||||
|
|
||||||
|
onAccepted: pwField.forceActiveFocus()
|
||||||
|
onTextChanged: if (row.isPasswordOpen && text !== root.identityText) root.identityText = text
|
||||||
|
Keys.onEscapePressed: root.cancelPasswordPrompt()
|
||||||
|
|
||||||
|
onVisibleChanged: if (visible) Qt.callLater(forceActiveFocus)
|
||||||
|
Component.onCompleted: if (visible) Qt.callLater(forceActiveFocus)
|
||||||
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: pwField
|
id: pwField
|
||||||
visible: !row.isBusy && !row.isFailed
|
visible: !row.isBusy && !row.isFailed
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: connectPwBtn.left
|
anchors.right: connectPwBtn.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Style.spacing.rowGap / 2
|
||||||
anchors.rightMargin: Style.space(6)
|
anchors.rightMargin: Style.space(6)
|
||||||
password: true
|
password: true
|
||||||
placeholderText: "Passphrase"
|
placeholderText: "Passphrase"
|
||||||
@@ -1470,14 +1534,12 @@ Panel {
|
|||||||
enabled: !row.isBusy
|
enabled: !row.isBusy
|
||||||
text: row.isPasswordOpen ? root.passwordText : ""
|
text: row.isPasswordOpen ? root.passwordText : ""
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: row.submitCredentials()
|
||||||
if (!root.busy && row.net && text.length > 0) root.connectWithPassphrase(row.net.ssid, text)
|
|
||||||
}
|
|
||||||
onTextChanged: if (row.isPasswordOpen && text !== root.passwordText) root.passwordText = text
|
onTextChanged: if (row.isPasswordOpen && text !== root.passwordText) root.passwordText = text
|
||||||
Keys.onEscapePressed: { root.passwordSsid = ""; root.passwordText = "" }
|
Keys.onEscapePressed: root.cancelPasswordPrompt()
|
||||||
|
|
||||||
onVisibleChanged: if (visible) Qt.callLater(forceActiveFocus)
|
onVisibleChanged: if (visible && !row.isEnterprise) Qt.callLater(forceActiveFocus)
|
||||||
Component.onCompleted: if (visible) Qt.callLater(forceActiveFocus)
|
Component.onCompleted: if (visible && !row.isEnterprise) Qt.callLater(forceActiveFocus)
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderSurface {
|
BorderSurface {
|
||||||
@@ -1510,12 +1572,12 @@ Panel {
|
|||||||
visible: !row.isBusy && !row.isFailed
|
visible: !row.isBusy && !row.isFailed
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: row.net && pwField.text.length > 0
|
enabled: row.net && pwField.text.length > 0 && (!row.isEnterprise || idField.text.length > 0)
|
||||||
iconText: ""
|
iconText: ""
|
||||||
tooltipText: "Connect"
|
tooltipText: "Connect"
|
||||||
foreground: root.bar.foreground
|
foreground: root.bar.foreground
|
||||||
fontFamily: root.bar.fontFamily
|
fontFamily: root.bar.fontFamily
|
||||||
onClicked: if (row.net) root.connectWithPassphrase(row.net.ssid, root.passwordText)
|
onClicked: row.submitCredentials()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user