// Joining an 802.1X network -- eduroam and every corporate SSID -- inline, // under the row you clicked. // // This is the single road that used to end at GNOME's Wi-Fi panel. A PSK field // cannot join these networks: they want an authentication method, an identity, // a password, and sometimes a certificate to check the network against. // // The password never becomes a command-line argument. It is handed to // panama-network over stdin, because argv is world-readable through /proc for // as long as the process lives -- see the pin in network-tools-contract. It is // also dropped from this form the moment the form closes. // // No file dialog for the certificate this phase: a path typed in is worse than // a picker and much better than a road back to GNOME. import QtQuick Column { id: root property string ssid: "" property bool busy: false // Live form state. There is no reset(): WifiPanel loads this form and // destroys it when the row closes, so the typed password goes with it // rather than sitting in a hidden object waiting to be reopened. property string eap: "peap-mschapv2" property string identity: "" property string password: "" property string caPath: "" readonly property bool ready: root.identity.trim() !== "" && root.password !== "" signal submitted(eap: string, identity: string, password: string, caPath: string) width: parent ? parent.width : 620 spacing: 0 OptionPickerRow { width: parent.width label: "Authentication" detail: "What the network expects. Whoever runs it publishes this." options: [ { value: "peap-mschapv2", label: "PEAP · MSCHAPv2", detail: "The usual choice for university and workplace networks" }, { value: "ttls-pap", label: "TTLS · PAP", detail: "For networks built around a plain-text inner method" } ] current: root.eap onPicked: value => root.eap = String(value) } TextFieldRow { width: parent.width label: "Identity" detail: "The username the network knows you by, often an email address" placeholder: "you@example.edu" text: root.identity enabled: !root.busy onAccepted: value => root.identity = value } PasswordRow { width: parent.width label: "Password" detail: "Handed to NetworkManager directly. It is never written to a command line." placeholder: "Password for " + (root.ssid !== "" ? root.ssid : "this network") onChanged: value => root.password = value } TextFieldRow { width: parent.width label: "CA certificate" detail: "Optional. A path to the certificate that proves the network is the one it claims to be." placeholder: "/etc/ssl/certs/example.pem" text: root.caPath enabled: !root.busy onAccepted: value => root.caPath = value } ActionRow { width: parent.width label: "Connect to " + (root.ssid !== "" ? root.ssid : "this network") detail: root.ready ? "NetworkManager saves this network, so it comes back on its own next time" : "An identity and a password are needed before this network will answer" action: root.busy ? "Connecting…" : "Connect" enabled: root.ready && !root.busy divider: false onTriggered: root.submitted(root.eap, root.identity.trim(), root.password, root.caPath.trim()) } }