Merge lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations into lp:ubuntu-system-settings
- wifi-802-1x-configurations
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations |
Merge into: | lp:ubuntu-system-settings |
Diff against target: |
1255 lines (+927/-48) 9 files modified
plugins/wifi/CMakeLists.txt (+4/-0) plugins/wifi/CertDialog.qml (+63/-0) plugins/wifi/CertPicker.qml (+75/-0) plugins/wifi/OtherNetwork.qml (+456/-42) plugins/wifi/certhandler.cpp (+144/-0) plugins/wifi/certhandler.h (+45/-0) plugins/wifi/plugin.cpp (+3/-0) plugins/wifi/wifidbushelper.cpp (+135/-5) plugins/wifi/wifidbushelper.h (+2/-1) |
To merge this branch: | bzr merge lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Matthew Paul Thomas | design | Pending | |
Jonas G. Drange | Pending | ||
Review via email: mp+258318@code.launchpad.net |
This proposal supersedes a proposal from 2015-04-27.
This proposal has been superseded by a proposal from 2015-06-03.
Commit message
With 1392, I have added basic file picker functionality for choosing cert files.
It arises a general question: Where to store the cert files?
Network Manager (NM) allows to use to different schemes: blob and path [1].
If one uses blob NM parses the content and creates a file uuid-certtype.pem in
/userdata/
At least a unique place to store them with the connection.
For path, a file:///... will be handed over and set in the network configuration.
In my first approach I have decided to use blob as the path scheme did not work for me on desktop environment. Haven't worked on that further.
Thus, at the moment there are three different ways to handle the cert data in the ui.
1. Copy cert content from clipboard
2. absolute path to cert file
3. Use ContentHub to choose file. The file will be stored in .local/
All end up with parsing the content to NetworkManager as described above.
In general, if there is a general place to store the certs, a Menu should be implemented as propagated in [2]. This Menu than should point to all "installed" certs on the device (system or user).
---
[1] https:/
[2] https:/
Description of the change
Added support for 802-1x wireless network configurations.
now back on dialog.
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
JkB (joergberroth) wrote : Posted in a previous version of this proposal | # |
> This is really great. Thanks for proposing this.
>
> I've added some comments, but they're mostly about your decision to make the
> Dialog an ItemPage. If this is not crucial to the implementation of support
> for 802-1x, we need to revert it.
>
> Also, if cert picking is not implemented, please remove all components that
> are unused. Please leave the UI bits in, but hide it with "visible:
> showAllUI". This way we can get strings translated.
>
> Thanks again.
Hey, thanks a lot for for reviewing.
First I had the concerns about pushing it to an ItemPage, too. Then, after dealing with the variety of different configurations, I found there would be an advantage if one changes to ItemPage. There is no need for the ItemPage from implementation point of view but there are configurations for which the user has to be asked up to two different certificates and an additional private key (TLS) and there can be different types of path2 authentication types for the different WPA Enterprise configurations.
So if we want the user to be able two choose all the different types of configurations, it seems to me that a dialog would get quite overloaded with ui inputs. And correct me if I'm wrong but scrolling, which certainly would be needed, seems not to be provided for the dialogs.
At the moment there are some pages in the cellular settings (e.g. APN) where one switched to ItemPages, too. So from design point of view it would keep consistent.
Maybe, based on these points, we can quickly discuss this again before I revert the change.
All other comments are clear. I will consider for the next commit.
I think the file picker would make selecting certificates even more comfortable but I will remove it as proposed, so one can work on that later.
Thanks again.
Joerg
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal | # |
Thanks so much for working on this, Joerg!
Jonas is right, though, that the authentication UI does need to remain a dialog. The reason is that System Settings is just one of three -- and will eventually be just one of six -- different places that might launch the UI for entering Wi-Fi details. The first-run setup "Connect to Wi-Fi" screen, and the network indicator menu, should let you connect to all the same Wi-Fi networks that System Settings does, by putting up the same dialog. <https:/
When dialog contents are bigger than the available screen space, the body is supposed to scroll automatically, and apparently this has been implemented already (bug 1376763). If it's not working, please report a bug.
JkB (joergberroth) wrote : Posted in a previous version of this proposal | # |
Thanks for the review and the hints.
It was not clear from documentation for me. But the bug post made it.
I just reverted the page back to dialog.
Am 2015-04-27 um 13:04 schrieb Matthew Paul Thomas:
> Review: Needs Fixing design
>
> Thanks so much for working on this, Joerg!
>
> Jonas is right, though, that the authentication UI does need to remain a dialog. The reason is that System Settings is just one of three -- and will eventually be just one of six -- different places that might launch the UI for entering Wi-Fi details. The first-run setup "Connect to Wi-Fi" screen, and the network indicator menu, should let you connect to all the same Wi-Fi networks that System Settings does, by putting up the same dialog. <https:/
>
> When dialog contents are bigger than the available screen space, the body is supposed to scroll automatically, and apparently this has been implemented already (bug 1376763). If it's not working, please report a bug.
>
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal | # |
Thank you.
Marcus Tomlinson (marcustomlinson) wrote : Posted in a previous version of this proposal | # |
Your code isn't compiling. There are some weird "!==" occurrences in 2 of your .cpp files. Rather hard to test your changes work when the project doesn't compile no? :P
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
Getting [1] when trying to build. Could you fix those? Thanks.
Matthew Paul Thomas (mpt) wrote : | # |
Yesterday, before I saw this new merge proposal, I was tackling the same question: "Where to store the cert files?" Also private key files and PAC files. On Ubuntu for PC, the current answer is in their own app, "Passwords and Keys". But on phones/tablets the overall system UI real estate is much smaller, so as with software updates and system version, this task fits best in System Settings.
This means the same conclusion (3) that you came to: storing the files in System Settings. "For this reason, System Settings should be set up as the default handler for certificates, private key files, and PAC files that you download or open, showing a confirmation dialog with info about the certificate/file and “Cancel” and “Save” buttons, and then lowering itself behind the previous app." <https:/
A later task will be to design+implement a way to remove previously-saved certificates/files inside System Settings.
- 1393. By JkB
-
Added CertificateHandling to list installed and add new certificates from OtherNetwork
Now uses ItemSelectors and dataModels. Certs can be added by calling ContentHub.ToDos:
*improve list update for ItemSelectors
*Add handling for private keys and pac files.
*add password-flags
*add pac-Provisioning
*change? from blob to path scheme for nm configurations no that certs can be stored in a central place.--- in wifi settings:
*Page (from PageComponents) to manage all installed certs and keys. - 1394. By JkB
-
Improved certificate and key handling. List installed and add new certificates from OtherNetwork Dialog.
Uses ItemSelectors and dataModels to select certs and keys. Certs and keys can be added by calling ContentHub.ToDos:
*improve list update for ItemSelectors
*Improve handling pac files.
*change? from blob to path scheme for nm configurations no that certs can be stored in a central place.--- in wifi settings:
*Page (from PageComponents) to manage all "installed" certs and keys. - 1395. By JkB
-
Merge with trunk
- 1396. By JkB
-
merge with trunk.
Fixed bugs. - 1397. By JkB
-
removed some bugs,
finally tested on my BQ Aquaris. At least for WPA and a WPA Enterprise TTLS/MCHAP2 connection.
Had no other networks around.final changes:
*changed to path scheme for cert handling with networkmanager
*removed some further small bugs that made it finally work.----
ToDos:
*Improve handling of pac Files.
*As suggested, cert and key managment for "installed" ones will be needed.
*Improve CertDialog not to show raw content of cert.
*Implement network encryption detection to use dialog for visible networks as well. - 1398. By JkB
-
merge with trunk
----
*added checks against bad cert/key content
*improved data update. - 1399. By JkB
-
OtherNetwork extensions mature now.
---
*improved Pac fIle handling. - 1400. By JkB
-
*
- 1401. By JkB
-
formatting
- 1402. By JkB
-
* ItemSelectors: select back to "None" as standard for cases when filePicker is canceled.
* formatting
----
ToDo (later on):
- change selectedIndex to Item that has been added via ContentHub. - 1403. By JkB
-
merge with trunk
- 1404. By JkB
-
* improve config handling
* fixed bug: added missing nul termination to successfully store certs with path scheme. - 1405. By JkB
-
* added QStandardPaths for cert handling
* improved getting secrets in Previous network to get wpa-eap passwords as well.
* restored .bzrignore - 1406. By JkB
-
merge with trunk
- 1407. By JkB
-
merged with jgdx merge proposal. Thanks a lot Jonas for the extensive format fixes!
+Also, considered some quickly managable FIXMEs from Jonas. Some stay. - 1408. By JkB
-
* fixed wpa-eap/peap configurations.
* added "certificates recommended" security hint. - 1409. By JkB
-
*merged with trunk
- 1410. By JkB
-
merge jonas branch
- 1411. By JkB
-
merge with trunk
- 1412. By JkB
-
* set feedback back to original implementation
- 1413. By JkB
-
merge Jonas fixmes
- 1414. By JkB
-
clear spaces
- 1415. By JkB
-
merge with trunk
- 1416. By JkB
-
* multiple %1 args in i18n.tr all fall back to the first arg() provided.
Is this an individuell problem of my build?
If not we should consider this last commit. - 1417. By JkB
-
* only show "using certificate.." hint if selected one == "None"
Unmerged revisions
Preview Diff
1 | === modified file 'plugins/wifi/CMakeLists.txt' |
2 | --- plugins/wifi/CMakeLists.txt 2014-09-15 15:39:50 +0000 |
3 | +++ plugins/wifi/CMakeLists.txt 2015-05-12 23:13:53 +0000 |
4 | @@ -1,6 +1,8 @@ |
5 | set(QML_SOURCES |
6 | AccessPoint.qml |
7 | BaseMenuItem.qml |
8 | +CertPicker.qml |
9 | +CertDialog.qml |
10 | Common.qml |
11 | DivMenuItem.qml |
12 | FramedMenuItem.qml |
13 | @@ -23,10 +25,12 @@ |
14 | plugin.cpp |
15 | unitymenumodelstack.cpp |
16 | previousnetworkmodel.cpp |
17 | + certhandler.cpp |
18 | wifidbushelper.h |
19 | plugin.h |
20 | unitymenumodelstack.h |
21 | previousnetworkmodel.h |
22 | + certhandler.cpp |
23 | nm_manager_proxy.h |
24 | nm_settings_proxy.h |
25 | nm_settings_connection_proxy.h |
26 | |
27 | === added file 'plugins/wifi/CertDialog.qml' |
28 | --- plugins/wifi/CertDialog.qml 1970-01-01 00:00:00 +0000 |
29 | +++ plugins/wifi/CertDialog.qml 2015-05-12 23:13:53 +0000 |
30 | @@ -0,0 +1,63 @@ |
31 | +import QtQuick 2.0 |
32 | +import QtQuick.Layouts 1.1 |
33 | +import Ubuntu.Components.Popups 0.1 |
34 | +import Ubuntu.Components 0.1 |
35 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
36 | +import Ubuntu.SystemSettings.Wifi 1.0 |
37 | + |
38 | +Component { |
39 | + |
40 | + Dialog { |
41 | + id: certDialog |
42 | + |
43 | + property var certFileName; |
44 | + |
45 | + anchors.fill: parent |
46 | + |
47 | + title: i18n.tr("Add Certificate?") |
48 | + |
49 | + CertificateHandler { |
50 | + id: certificateHandler |
51 | + } |
52 | + |
53 | + TextArea { |
54 | + id : certContent |
55 | + objectName: "certContent" |
56 | + readOnly: true |
57 | + width: parent.width |
58 | + autoSize: true |
59 | + maximumLineCount: 7 |
60 | + placeholderText: i18n.tr("No data available.") |
61 | + text: {certificateHandler.getCertContent(certDialog.certFileName).toString()} |
62 | + } |
63 | + |
64 | + RowLayout { |
65 | + id: buttonRow |
66 | + anchors { |
67 | + left: parent.left |
68 | + right: parent.right |
69 | + } |
70 | + spacing: units.gu(2) |
71 | + height: cancelButton.height |
72 | + |
73 | + Button { |
74 | + id: cancelButton |
75 | + text: i18n.tr("Cancel") |
76 | + onClicked: { certificateHandler.removeFile(certDialog.certFileName); |
77 | + PopupUtils.close(certDialog); |
78 | + } |
79 | + } |
80 | + |
81 | + Button { |
82 | + id: saveButton |
83 | + text: i18n.tr("Add Certificate") |
84 | + enabled: (certDialog.certContent.text !== []) |
85 | + onClicked: { certificateHandler.moveCertFile(certDialog.certFileName); |
86 | + // just to be sure source file will be deleted if move was not successfull: |
87 | + certificateHandler.removeFile(certDialog.certFileName); |
88 | + PopupUtils.close(certDialog); |
89 | + } |
90 | + } |
91 | + } |
92 | + } |
93 | +} |
94 | |
95 | === added file 'plugins/wifi/CertPicker.qml' |
96 | --- plugins/wifi/CertPicker.qml 1970-01-01 00:00:00 +0000 |
97 | +++ plugins/wifi/CertPicker.qml 2015-05-12 23:13:53 +0000 |
98 | @@ -0,0 +1,75 @@ |
99 | +import QtQuick 2.0 |
100 | +import QtQuick.Layouts 1.1 |
101 | +import Ubuntu.Components 0.1 |
102 | +import Ubuntu.Components.Popups 0.1 |
103 | +import Ubuntu.Content 0.1 |
104 | + |
105 | +/* with a little help by looking into dekko mail client (lp:dekko) :*/ |
106 | +PopupBase { |
107 | + //visible: false |
108 | + id: picker |
109 | + |
110 | + /* Picked Ffles will be stored in |
111 | + ~/.local/share/ubuntu-system-settings/Documents/ |
112 | + |
113 | + At this state of implementation, this store will be used to parse the file to |
114 | + Networkmanager. |
115 | + As I haven't found that it is yet decided where to store cert files in general, all certs will be stored |
116 | + by parsing the cert content to NM. NM then creates a file (UUID-certType.pem) in /userdata/system-data/etc/NetworkManager/system-connections/ . |
117 | + At least a unique place. |
118 | + |
119 | + The files in ~/.local/share/ubuntu-system-settings/Documents/ |
120 | + will not be deleted. Could be implemented later on. |
121 | + */ |
122 | + |
123 | + |
124 | + signal fileImportSignal(var file) |
125 | + property var activeTransfer |
126 | + |
127 | + Rectangle { |
128 | + anchors.fill: parent |
129 | + |
130 | + ContentTransferHint { |
131 | + id: transferHint |
132 | + anchors.fill: parent |
133 | + activeTransfer: picker.activeTransfer |
134 | + } |
135 | + |
136 | + ContentStore { |
137 | + id: appStore |
138 | + scope: ContentScope.App |
139 | + } |
140 | + |
141 | + ContentPeerPicker { |
142 | + id: peerPicker |
143 | + anchors.fill: parent |
144 | + visible: true |
145 | + contentType: ContentType.Documents |
146 | + handler: ContentHandler.Source |
147 | + onPeerSelected: { |
148 | + peer.selectionType = ContentTransfer.Single; |
149 | + picker.activeTransfer = peer.request(appStore); |
150 | + } |
151 | + onCancelPressed: { |
152 | + PopupUtils.close(picker) |
153 | + } |
154 | + } |
155 | + } |
156 | + |
157 | + Connections { |
158 | + target: picker.activeTransfer ? picker.activeTransfer : null |
159 | + onStateChanged: { |
160 | + if (picker.activeTransfer.state === ContentTransfer.Charged) { |
161 | + if (picker.activeTransfer.items.length > 0) { |
162 | + var fileUrl = picker.activeTransfer.items[0].url; |
163 | + picker.fileImportSignal(fileUrl.toString().replace("file://", "")); |
164 | + PopupUtils.close(picker); |
165 | + } |
166 | + |
167 | + } else if (picker.activeTransfer.state === ContentTransfer.Aborted){ |
168 | + PopupUtils.close(picker); |
169 | + } |
170 | + } |
171 | + } |
172 | + |
173 | +} |
174 | |
175 | === modified file 'plugins/wifi/OtherNetwork.qml' |
176 | --- plugins/wifi/OtherNetwork.qml 2015-01-09 08:47:53 +0000 |
177 | +++ plugins/wifi/OtherNetwork.qml 2015-05-12 23:13:53 +0000 |
178 | @@ -38,14 +38,16 @@ |
179 | if(securityList.selectedIndex == 0) { |
180 | return true |
181 | } |
182 | - if(securityList.selectedIndex == 1) { |
183 | - return password.length >= 8 |
184 | + if(securityList.selectedIndex == 3) { |
185 | + |
186 | + // WEP |
187 | + return password.length === 5 || |
188 | + password.length === 10 || |
189 | + password.length === 13 || |
190 | + password.length === 26; |
191 | } |
192 | - // WEP |
193 | - return password.length === 5 || |
194 | - password.length === 10 || |
195 | - password.length === 13 || |
196 | - password.length === 26; |
197 | + //WPA |
198 | + return password.length >= 8 |
199 | } |
200 | |
201 | title: i18n.tr("Connect to Hidden Network") |
202 | @@ -66,6 +68,19 @@ |
203 | target: connectButtonIndicator |
204 | running: true |
205 | } |
206 | + |
207 | + PropertyChanges { |
208 | + target: p2authList |
209 | + enabled: false |
210 | + } |
211 | + PropertyChanges { |
212 | + target: p2authListLabel |
213 | + opacity: 0.5 |
214 | + } |
215 | + PropertyChanges { |
216 | + target: cacertLabel |
217 | + opacity: 0.5 |
218 | + } |
219 | PropertyChanges { |
220 | target: passwordVisibleSwitch |
221 | enabled: false |
222 | @@ -79,7 +94,36 @@ |
223 | enabled: false |
224 | } |
225 | PropertyChanges { |
226 | - target: passwordListLabel |
227 | + target: passwordLabel |
228 | + opacity: 0.5 |
229 | + } |
230 | + PropertyChanges { |
231 | + target: username |
232 | + enabled: false |
233 | + } |
234 | + PropertyChanges { |
235 | + target: usernameLabel |
236 | + opacity: 0.5 |
237 | + } |
238 | + PropertyChanges { |
239 | + target: anonymousIdentity |
240 | + enabled: false |
241 | + } |
242 | + PropertyChanges { |
243 | + target: anonymousIdentityLabel |
244 | + opacity: 0.5 |
245 | + } |
246 | + PropertyChanges { |
247 | + target: authList |
248 | + enabled: false |
249 | + opacity: 0.5 |
250 | + } |
251 | + PropertyChanges { |
252 | + target: authListLabel |
253 | + opacity: 0.5 |
254 | + } |
255 | + PropertyChanges { |
256 | + target: wepInsecureLabel |
257 | opacity: 0.5 |
258 | } |
259 | PropertyChanges { |
260 | @@ -102,6 +146,7 @@ |
261 | PropertyChanges { |
262 | target: feedback |
263 | enabled: true |
264 | + visible: true |
265 | } |
266 | }, |
267 | State { |
268 | @@ -109,6 +154,7 @@ |
269 | PropertyChanges { |
270 | target: feedback |
271 | enabled: true |
272 | + visible: true |
273 | } |
274 | }, |
275 | State { |
276 | @@ -117,10 +163,7 @@ |
277 | target: successIndicator |
278 | running: true |
279 | } |
280 | - PropertyChanges { |
281 | - target: cancelButton |
282 | - enabled: false |
283 | - } |
284 | + |
285 | PropertyChanges { |
286 | target: connectAction |
287 | enabled: false |
288 | @@ -142,7 +185,7 @@ |
289 | text : i18n.tr("Network name") |
290 | objectName: "networknameLabel" |
291 | fontSize: "medium" |
292 | - font.bold: true |
293 | + font.bold: false |
294 | color: Theme.palette.selected.backgroundText |
295 | elide: Text.ElideRight |
296 | } |
297 | @@ -150,6 +193,8 @@ |
298 | TextField { |
299 | id : networkname |
300 | objectName: "networkname" |
301 | + width: parent.width |
302 | + placeholderText: i18n.tr("SSID") |
303 | inputMethodHints: Qt.ImhNoPredictiveText |
304 | Component.onCompleted: forceActiveFocus() |
305 | } |
306 | @@ -159,7 +204,7 @@ |
307 | text : i18n.tr("Security") |
308 | objectName: "securityListLabel" |
309 | fontSize: "medium" |
310 | - font.bold: true |
311 | + font.bold: false |
312 | color: Theme.palette.selected.backgroundText |
313 | elide: Text.ElideRight |
314 | } |
315 | @@ -167,18 +212,348 @@ |
316 | ListItem.ItemSelector { |
317 | id: securityList |
318 | objectName: "securityList" |
319 | - model: [i18n.tr("None"), // index: 0 |
320 | - i18n.tr("WPA & WPA2 Personal"), // index: 1 |
321 | - i18n.tr("WEP"), // index: 2 |
322 | - ] |
323 | - } |
324 | - |
325 | - Label { |
326 | - id: passwordListLabel |
327 | - text : i18n.tr("Password") |
328 | + model: [i18n.tr("None"), // index: 0 |
329 | + i18n.tr("WPA & WPA2 Personal"), // index: 1 |
330 | + i18n.tr("WPA & WPA2 Enterprise"),// index: 2 |
331 | + i18n.tr("WEP"), // index: 3 |
332 | + i18n.tr("Dynamic WEP (802.1x)"), // index: 4 |
333 | + i18n.tr("LEAP"), // index: 5 |
334 | + ] |
335 | + selectedIndex: 1 |
336 | + } |
337 | + |
338 | + Label { |
339 | + id: wepInsecureLabel |
340 | + objectName: "wepInsecureLabel" |
341 | + color: "red" |
342 | + text: i18n.tr("This network is insecure.") |
343 | + visible: ( securityList.selectedIndex == 3) |
344 | + } |
345 | + |
346 | + Label { |
347 | + id: authListLabel |
348 | + text : i18n.tr("Authentication") |
349 | + objectName: "authListLabel" |
350 | + fontSize: "medium" |
351 | + font.bold: false |
352 | + color: Theme.palette.selected.backgroundText |
353 | + elide: Text.ElideRight |
354 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
355 | + } |
356 | + |
357 | + ListItem.ItemSelector { |
358 | + id: authList |
359 | + objectName: "authList" |
360 | + model: [i18n.tr("TLS"), // index: 0 |
361 | + i18n.tr("TTLS"), // index: 1 |
362 | + i18n.tr("LEAP"), // index: 2 |
363 | + i18n.tr("FAST"), // index: 3 |
364 | + i18n.tr("PEAP"), // index: 4 |
365 | + ] |
366 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
367 | + } |
368 | + |
369 | + Label { |
370 | + id: p2authListLabel |
371 | + text : i18n.tr("Inner authentication") |
372 | + objectName: "p2authLabel" |
373 | + fontSize: "medium" |
374 | + font.bold: false |
375 | + color: Theme.palette.selected.backgroundText |
376 | + elide: Text.ElideRight |
377 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) // WPA or D-WEP |
378 | + && ( authList.selectedIndex == 1 || |
379 | + authList.selectedIndex == 3 || |
380 | + authList.selectedIndex == 4 ) |
381 | + } |
382 | + |
383 | + ListItem.ItemSelector { |
384 | + id: p2authList |
385 | + objectName: "p2authList" |
386 | + width: parent.width |
387 | + model: [i18n.tr("PAP"), // index: 0 |
388 | + i18n.tr("MSCHAPv2"), // index: 1 |
389 | + i18n.tr("MSCHAP"), // index: 2 |
390 | + i18n.tr("CHAP"), // index: 3 |
391 | + i18n.tr("GTC"), // index: 4 |
392 | + i18n.tr("MD5") // index: 5 |
393 | + ] |
394 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) // WPA or D-WEP |
395 | + && ( authList.selectedIndex == 1 || |
396 | + authList.selectedIndex == 3 || |
397 | + authList.selectedIndex == 4 ) |
398 | + } |
399 | + |
400 | + Label { |
401 | + id: cacertLabel |
402 | + text : i18n.tr("CA Certificate") |
403 | + objectName: "cacertListLabel" |
404 | + fontSize: "medium" |
405 | + font.bold: false |
406 | + color: Theme.palette.selected.backgroundText |
407 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) // WPA or D-WEP |
408 | + && ( authList.selectedIndex == 0 || |
409 | + authList.selectedIndex == 1 || |
410 | + authList.selectedIndex == 3 ) |
411 | + } |
412 | + |
413 | + ListItem.ItemSelector { |
414 | + id: cacertSelector |
415 | + anchors { |
416 | + left: parent.left |
417 | + right: parent.right |
418 | + } |
419 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) // WPA or D-WEP |
420 | + && ( authList.selectedIndex == 0 || |
421 | + authList.selectedIndex == 1 || |
422 | + authList.selectedIndex == 3 ) |
423 | + model: cacertListModel |
424 | + expanded: false |
425 | + delegate: certSelectorDelegate |
426 | + selectedIndex: 0 |
427 | + property string cacertFileName : { if(cacertSelector.selectedIndex !== 0 && |
428 | + cacertSelector.selectedIndex !== (certListModel.rowCount()-1)){ |
429 | + certListModel.getfileName(cacertSelector.selectedIndex) |
430 | + } else {"";} |
431 | + } |
432 | + onSelectedIndexChanged: { |
433 | + cacertListModel.dataupdate(); |
434 | + if (cacertSelector.selectedIndex === cacertListModel.rowCount()-1){ |
435 | + var pickerDialog = PopupUtils.open(Qt.resolvedUrl("./CertPicker.qml")); |
436 | + pickerDialog.fileImportSignal.connect(function(file){ |
437 | + certDialogLoader.source = "./CertDialog.qml"; |
438 | + PopupUtils.open(certDialogLoader.item, cacertSelector, {certFileName: file}); |
439 | + }); |
440 | + } |
441 | + } |
442 | + |
443 | + |
444 | + } |
445 | + |
446 | + Component{ |
447 | + id: certSelectorDelegate |
448 | + OptionSelectorDelegate { text: CommonName; |
449 | + subText:(CommonName != "None" && CommonName != "Choose file…") ? |
450 | + (Organization +", Exp.date: " + expiryDate) : "" |
451 | + } |
452 | + } |
453 | + CertificateListModel { |
454 | + id: cacertListModel |
455 | + } |
456 | + |
457 | + Loader{ |
458 | + id: certDialogLoader |
459 | + asynchronous: false |
460 | + } |
461 | + |
462 | + Label { |
463 | + id: usercertLabel |
464 | + text : i18n.tr("Client Certificate") |
465 | + objectName: "usercertLabel" |
466 | + fontSize: "medium" |
467 | + font.bold: false |
468 | + color: Theme.palette.selected.backgroundText |
469 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
470 | + && ( authList.selectedIndex == 0 ) // only for TLS |
471 | + |
472 | + } |
473 | + |
474 | + ListItem.ItemSelector { |
475 | + id: usercertSelector |
476 | + anchors { |
477 | + left: parent.left |
478 | + right: parent.right |
479 | + } |
480 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
481 | + && ( authList.selectedIndex == 0 ) // only for TLS |
482 | + model: cacertListModel |
483 | + expanded: false |
484 | + delegate: certSelectorDelegate |
485 | + selectedIndex: 0 |
486 | + property string usercertFileName: { if(usercertFileName.selectedIndex !== 0 && |
487 | + usercertFileName.selectedIndex !== (certListModel.rowCount()-1)){ |
488 | + certListModel.getfileName(usercertFileName.selectedIndex) |
489 | + } else {"";} |
490 | + } |
491 | + onSelectedIndexChanged: { |
492 | + if (usercertSelector.selectedIndex === cacertListModel.rowCount()-1){ |
493 | + var pickerDialog = PopupUtils.open(Qt.resolvedUrl("./CertPicker.qml")); |
494 | + pickerDialog.fileImportSignal.connect(function(file){ |
495 | + }); |
496 | + } |
497 | + } |
498 | + } |
499 | + |
500 | + /*CertificateListModel { |
501 | + id: usercertListModel |
502 | + }*/ |
503 | + |
504 | + RowLayout{ |
505 | + spacing: units.gu(4) |
506 | + anchors { |
507 | + left: parent.left |
508 | + right: parent.right |
509 | + } |
510 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
511 | + && ( authList.selectedIndex == 0 ) // only for TLS |
512 | + |
513 | + Label { |
514 | + id: userprivatekeyLabel |
515 | + text : i18n.tr("User Private Key") |
516 | + objectName: "userprivatekeyLabel" |
517 | + fontSize: "medium" |
518 | + font.bold: false |
519 | + color: Theme.palette.selected.backgroundText |
520 | + anchors.bottom: adduserprivatekeyButton.bottom |
521 | + } |
522 | + |
523 | + Button { |
524 | + id: adduserprivatekeyButton |
525 | + visible: true |
526 | + objectName: "adduserprivatekeyButton" |
527 | + anchors.right: parent.right |
528 | + text: i18n.tr("Choose file…") |
529 | + onClicked: { |
530 | + var pickerDialog = PopupUtils.open(Qt.resolvedUrl("./CertPicker.qml")); |
531 | + pickerDialog.fileImportSignal.connect(function(file){ |
532 | + userprivatekey.text = file; |
533 | + }); |
534 | + } |
535 | + } |
536 | + } |
537 | + |
538 | + TextArea { |
539 | + id : userprivatekey |
540 | + objectName: "userprivatekey" |
541 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
542 | + && ( authList.selectedIndex == 0 ) |
543 | + width: parent.width |
544 | + autoSize: true |
545 | + maximumLineCount: 4 |
546 | + placeholderText: i18n.tr("Absolute path to key or clipboard content") |
547 | + } |
548 | + |
549 | + Column{ // pacFile |
550 | + id: pacFileColumn |
551 | + anchors { |
552 | + left: parent.left |
553 | + right: parent.right |
554 | + } |
555 | + spacing: parent.spacing |
556 | + |
557 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
558 | + && ( authList.selectedIndex == 3 ) |
559 | + |
560 | + RowLayout{ |
561 | + spacing: units.gu(4) |
562 | + anchors { |
563 | + left: parent.left |
564 | + right: parent.right |
565 | + } |
566 | + |
567 | + Label { |
568 | + id: pacFileLabel |
569 | + text : i18n.tr("Pac File") |
570 | + objectName: "pacFileLabel" |
571 | + fontSize: "medium" |
572 | + font.bold: false |
573 | + color: Theme.palette.selected.backgroundText |
574 | + anchors.bottom: adduserprivatekeyButton.bottom |
575 | + } |
576 | + |
577 | + Button { |
578 | + id: addpacFileButton |
579 | + visible: true |
580 | + objectName: "addpacFileButton" |
581 | + anchors.right: parent.right |
582 | + text: i18n.tr("Choose file…") |
583 | + onClicked: { |
584 | + var pickerDialog = PopupUtils.open(Qt.resolvedUrl("./CertPicker.qml")); |
585 | + pickerDialog.fileImportSignal.connect(function(file){ |
586 | + PopupUtils.open(Qt.resolvedUrl("./CertDialog.qml"), {certContentText: file}); // pacFile.text = file; |
587 | + }); |
588 | + } |
589 | + } |
590 | + } |
591 | + |
592 | + TextArea { |
593 | + id : pacFile |
594 | + objectName: "pacFile" |
595 | + width: parent.width |
596 | + autoSize: true |
597 | + maximumLineCount: 4 |
598 | + placeholderText: i18n.tr("Absolute path to Pac File or clipboard content") |
599 | + } |
600 | + |
601 | + } |
602 | + |
603 | + Label { |
604 | + id: anonymousIdentityLabel |
605 | + text : i18n.tr("Anonymous identity") |
606 | + objectName: "anonymousIdentityLabel" |
607 | + fontSize: "medium" |
608 | + font.bold: false |
609 | + color: Theme.palette.selected.backgroundText |
610 | + visible: ( securityList.selectedIndex == 2 && authList.selectedIndex != 2 ) |
611 | + } |
612 | + |
613 | + TextField { |
614 | + id : anonymousIdentity |
615 | + objectName: "anonymousIdentity" |
616 | + width: parent.width |
617 | + visible: ( securityList.selectedIndex == 2 && authList.selectedIndex != 2 ) |
618 | + inputMethodHints: Qt.ImhNoPredictiveText |
619 | + Component.onCompleted: forceActiveFocus() |
620 | + onAccepted: { |
621 | + connectAction.trigger() |
622 | + } |
623 | + } |
624 | + |
625 | + Label { |
626 | + id: usernameLabel |
627 | + text : { |
628 | + if ( ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
629 | + && ( authList.selectedIndex == 0 )) { |
630 | + i18n.tr("Identity") |
631 | + } |
632 | + else { |
633 | + i18n.tr("Username") |
634 | + } |
635 | + } |
636 | + objectName: "usernameLabel" |
637 | + fontSize: "medium" |
638 | + font.bold: false |
639 | + color: Theme.palette.selected.backgroundText |
640 | + elide: Text.ElideRight |
641 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4 || securityList.selectedIndex == 5) |
642 | + } |
643 | + |
644 | + TextField { |
645 | + id : username |
646 | + objectName: "username" |
647 | + width: parent.width |
648 | + visible: ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4 || securityList.selectedIndex == 5) |
649 | + inputMethodHints: Qt.ImhNoPredictiveText |
650 | + Component.onCompleted: forceActiveFocus() |
651 | + onAccepted: { |
652 | + connectAction.trigger() |
653 | + } |
654 | + } |
655 | + |
656 | + Label { |
657 | + id: passwordLabel |
658 | + text: { |
659 | + if ( ( securityList.selectedIndex == 2 || securityList.selectedIndex == 4) |
660 | + && ( authList.selectedIndex == 0 )) { |
661 | + i18n.tr("Private Key Password") |
662 | + } else { |
663 | + i18n.tr("Password") |
664 | + } |
665 | + } |
666 | + |
667 | objectName: "passwordListLabel" |
668 | fontSize: "medium" |
669 | - font.bold: true |
670 | + font.bold: false |
671 | color: Theme.palette.selected.backgroundText |
672 | elide: Text.ElideRight |
673 | visible: securityList.selectedIndex !== 0 |
674 | @@ -187,16 +562,17 @@ |
675 | TextField { |
676 | id : password |
677 | objectName: "password" |
678 | + width: parent.width |
679 | visible: securityList.selectedIndex !== 0 |
680 | echoMode: passwordVisibleSwitch.checked ? |
681 | - TextInput.Normal : TextInput.Password |
682 | + TextInput.Normal : TextInput.Password |
683 | inputMethodHints: Qt.ImhNoPredictiveText |
684 | onAccepted: { |
685 | connectAction.trigger(); |
686 | } |
687 | } |
688 | |
689 | - Row { |
690 | + Row { |
691 | id: passwordVisiblityRow |
692 | layoutDirection: Qt.LeftToRight |
693 | spacing: units.gu(2) |
694 | @@ -204,7 +580,7 @@ |
695 | |
696 | CheckBox { |
697 | id: passwordVisibleSwitch |
698 | - activeFocusOnPress: false |
699 | + //activeFocusOnPress: false |
700 | } |
701 | |
702 | Label { |
703 | @@ -222,10 +598,44 @@ |
704 | } |
705 | onClicked: { |
706 | passwordVisibleSwitch.checked = |
707 | - !passwordVisibleSwitch.checked |
708 | - } |
709 | - } |
710 | - } |
711 | + !passwordVisibleSwitch.checked |
712 | + } |
713 | + } |
714 | + } |
715 | + } |
716 | + |
717 | + Row { |
718 | + id: passwordRememberRow |
719 | + layoutDirection: Qt.LeftToRight |
720 | + spacing: units.gu(2) |
721 | + visible: false |
722 | + //( authList.selectedIndex == 1 || authList.selectedIndex == 3 || authList.selectedIndex == 4) |
723 | + //not implemented yet. |
724 | + CheckBox { |
725 | + id: passwordRememberSwitch |
726 | + //activeFocusOnPress: false |
727 | + } |
728 | + |
729 | + Label { |
730 | + id: passwordRememberLabel |
731 | + text : i18n.tr("Remember password") |
732 | + objectName: "passwordRememberLabel" |
733 | + fontSize: "medium" |
734 | + color: Theme.palette.selected.backgroundText |
735 | + elide: Text.ElideRight |
736 | + height: passwordRememberSwitch.height |
737 | + verticalAlignment: Text.AlignVCenter |
738 | + MouseArea { |
739 | + anchors { |
740 | + fill: parent |
741 | + } |
742 | + onClicked: { |
743 | + passwordRememberSwitch.checked = |
744 | + !passwordRememberSwitch.checked |
745 | + } |
746 | + } |
747 | + } |
748 | + |
749 | } |
750 | |
751 | RowLayout { |
752 | @@ -287,9 +697,13 @@ |
753 | enabled: settingsValid() |
754 | onTriggered: { |
755 | DbusHelper.connect( |
756 | - networkname.text, |
757 | - securityList.selectedIndex, |
758 | - password.text); |
759 | + networkname.text, |
760 | + securityList.selectedIndex, |
761 | + authList.selectedIndex, |
762 | + [username.text, anonymousIdentity.text], |
763 | + password.text, |
764 | + [cacertSelector.cacertFileName, usercertSelector.usercertFileName, userprivatekey.text, pacFile.text] , |
765 | + p2authList.selectedIndex); |
766 | otherNetworkDialog.state = "CONNECTING"; |
767 | } |
768 | } |
769 | @@ -321,15 +735,15 @@ |
770 | */ |
771 | if (otherNetworkDialog.state === "CONNECTING") { |
772 | switch (newState) { |
773 | - case 120: |
774 | - feedback.text = common.reasonToString(reason); |
775 | - otherNetworkDialog.state = "FAILED"; |
776 | - break; |
777 | - case 100: |
778 | - /* connection succeeded only if it was us that |
779 | + case 120: |
780 | + feedback.text = common.reasonToString(reason); |
781 | + otherNetworkDialog.state = "FAILED"; |
782 | + break; |
783 | + case 100: |
784 | + /* connection succeeded only if it was us that |
785 | created it */ |
786 | - otherNetworkDialog.state = "SUCCEEDED"; |
787 | - break; |
788 | + otherNetworkDialog.state = "SUCCEEDED"; |
789 | + break; |
790 | } |
791 | } |
792 | } |
793 | |
794 | === added file 'plugins/wifi/certhandler.cpp' |
795 | --- plugins/wifi/certhandler.cpp 1970-01-01 00:00:00 +0000 |
796 | +++ plugins/wifi/certhandler.cpp 2015-05-12 23:13:53 +0000 |
797 | @@ -0,0 +1,144 @@ |
798 | +#include "certhandler.h" |
799 | + |
800 | +#include <QtQml> |
801 | +#include <QtQml/QQmlContext> |
802 | +#include <QtDebug> |
803 | +#include <QObject> |
804 | +#include <QSslCertificate> |
805 | +#include <QAbstractListModel> |
806 | +#include <QDir> |
807 | + |
808 | +#define CERTS_PATH "/home/phablet/.local/share/ubuntu-system-settings/Documents/" //<----to be changed #jkb |
809 | +#define KEYS_PATH "/home/phablet/.local/share/ubuntu-system-settings/Documents/" |
810 | +/* |
811 | +CERTS_PATH points to the certificates directory. |
812 | +Later on should/could be .../ubuntu-system-settings/wifi/ssl/certs |
813 | +CA and client to be stored here. |
814 | +and KEYS_PATH to private keys |
815 | +Cold be .../ubuntu-system-settings/wifi/ssl/keys |
816 | + |
817 | +Same for pac files? |
818 | +*/ |
819 | + |
820 | +QByteArray CertificateHandler::getCertContent(QString filename){ |
821 | + QFile file(filename); |
822 | + if (!file.open(QIODevice::ReadOnly)) { |
823 | + qWarning() << "Could not resolve Cert-File (" << filename << "): File does not exist or is empty." ; |
824 | + return QByteArray(); |
825 | + } |
826 | + else { |
827 | + return file.readAll(); |
828 | + } |
829 | +} |
830 | + |
831 | +QString CertificateHandler::moveCertFile(QString filename){ |
832 | + QDir certPath(CERTS_PATH); |
833 | + if (!certPath.exists(CERTS_PATH)){ |
834 | + certPath.mkpath(CERTS_PATH); |
835 | + } |
836 | + QFile file(filename); |
837 | + QByteArray certificate = getCertContent(filename); |
838 | + QList<QSslCertificate> SslCertificate = QSslCertificate::fromData(certificate, QSsl::Pem); |
839 | + QStringList subject = SslCertificate[0].subjectInfo(QSslCertificate::CommonName); |
840 | + QString modFileName = CERTS_PATH+subject[0]+".pem"; |
841 | + if(file.rename(modFileName.replace(" ", "_"))){ |
842 | + return file.fileName(); |
843 | + } else { |
844 | + return "Error storing certificate." ; |
845 | + } |
846 | +} |
847 | + |
848 | +bool CertificateHandler::removeFile(QString filename){ |
849 | + QFile file(filename); |
850 | + return file.remove(); |
851 | +} |
852 | + |
853 | + |
854 | +struct CertificateListModel::Private { |
855 | + QStringList data; |
856 | +}; |
857 | + |
858 | +CertificateListModel::CertificateListModel(QObject *parent) : QAbstractListModel(parent) { |
859 | + p = new CertificateListModel::Private(); |
860 | + QStringList nameFilter("*.pem"); |
861 | + QDir directory(CERTS_PATH); |
862 | + QStringList files = directory.entryList(nameFilter); |
863 | + files.sort(Qt::CaseInsensitive); |
864 | + files.insert(0, "None"); |
865 | + files.append("Choose file…"); |
866 | + p->data = files; |
867 | +} |
868 | + |
869 | +CertificateListModel::~CertificateListModel() { |
870 | + delete p; |
871 | +} |
872 | + |
873 | +QHash<int, QByteArray> CertificateListModel::roleNames() const { |
874 | + QHash<int, QByteArray> roles; |
875 | + roles[CNRole] = "CommonName"; |
876 | + roles[ORole] = "Organization"; |
877 | + roles[expDateRole] = "expiryDate"; |
878 | + |
879 | + //roles[certFileNameRole] = "certFileName"; |
880 | + //...more if needed see QSslCertificate::SubjectInfo |
881 | + return roles; |
882 | +} |
883 | + |
884 | +int CertificateListModel::rowCount(const QModelIndex &/*parent*/) const { |
885 | + return p->data.size(); |
886 | +} |
887 | + |
888 | +QString CertificateListModel::getfileName(const int selectedIndex) const { |
889 | + return CERTS_PATH + p->data[selectedIndex]; |
890 | +} |
891 | + |
892 | +void CertificateListModel::dataupdate(){ |
893 | + beginResetModel(); |
894 | + p->data.clear(); |
895 | + QStringList nameFilter("*.pem"); |
896 | + QDir directory(CERTS_PATH); |
897 | + QStringList files = directory.entryList(nameFilter); |
898 | + files.sort(Qt::CaseInsensitive); |
899 | + files.insert(0, "None"); |
900 | + files.append("Choose file…"); |
901 | + p->data = files; |
902 | + endResetModel(); |
903 | +} |
904 | + |
905 | +QVariant CertificateListModel::data(const QModelIndex &index, int role) const { |
906 | + if(!index.isValid() || index.row() >= ( p->data.size()) ) { |
907 | + return QVariant(); |
908 | + } else if (index.row() == 0){ |
909 | + const QString &row0 = p->data[index.row()]; |
910 | + |
911 | + switch(role) { |
912 | + case CNRole : return row0; |
913 | + case ORole : return ""; |
914 | + case expDateRole : return ""; |
915 | + //case certFileNameRole : return ""; |
916 | + } |
917 | + } else if (index.row() == p->data.size()-1){ |
918 | + const QString &rowend = p->data[index.row()]; |
919 | + |
920 | + switch(role) { |
921 | + case CNRole : return rowend; |
922 | + case ORole : return ""; |
923 | + case expDateRole : return ""; |
924 | + //case certFileNameRole : return ""; |
925 | + } |
926 | + } |
927 | + |
928 | + const QString &row = CERTS_PATH+p->data[index.row()]; |
929 | + QList<QSslCertificate> certificate = QSslCertificate::fromPath(row, QSsl::Pem, QRegExp::Wildcard); |
930 | + |
931 | + switch(role) { |
932 | + |
933 | + case CNRole : return certificate[0].subjectInfo(QSslCertificate::CommonName)[0]; |
934 | + case ORole : return certificate[0].subjectInfo(QSslCertificate::Organization)[0]; |
935 | + case expDateRole : return certificate[0].expiryDate().toString("dd.MM.yyyy"); |
936 | + //case certFileNameRole : return row; |
937 | + |
938 | + default : return QVariant(); |
939 | + |
940 | + } |
941 | +} |
942 | |
943 | === added file 'plugins/wifi/certhandler.h' |
944 | --- plugins/wifi/certhandler.h 1970-01-01 00:00:00 +0000 |
945 | +++ plugins/wifi/certhandler.h 2015-05-12 23:13:53 +0000 |
946 | @@ -0,0 +1,45 @@ |
947 | +#ifndef CERTHANDLER_H |
948 | +#define CERTHANDLER_H |
949 | + |
950 | +#include <QtQml> |
951 | +#include <QtQml/QQmlContext> |
952 | +#include <QObject> |
953 | +#include <QAbstractListModel> |
954 | + |
955 | +class CertificateHandler : public QObject |
956 | +{ |
957 | + Q_OBJECT |
958 | +public: |
959 | + Q_INVOKABLE QByteArray getCertContent(QString filename); |
960 | + Q_INVOKABLE QString moveCertFile(QString filename); |
961 | + Q_INVOKABLE bool removeFile(QString filename); |
962 | +}; |
963 | + |
964 | + |
965 | + |
966 | +class CertificateListModel : public QAbstractListModel |
967 | +{ |
968 | + Q_OBJECT |
969 | + |
970 | +public: |
971 | + enum CertificateListRoles { |
972 | + CNRole = Qt::UserRole + 1, |
973 | + ORole, |
974 | + expDateRole, |
975 | + //certFileNameRole, |
976 | + }; |
977 | + |
978 | + explicit CertificateListModel(QObject *parent = 0); |
979 | + ~CertificateListModel(); |
980 | + QHash<int, QByteArray> roleNames() const; |
981 | + Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const; |
982 | + Q_INVOKABLE QString getfileName(const int selectedIndex) const; |
983 | + Q_INVOKABLE void dataupdate(); |
984 | + QVariant data(const QModelIndex &index, int role) const; |
985 | +private: |
986 | + struct Private; |
987 | + Private *p; |
988 | + |
989 | +}; |
990 | +#endif // CERTHANDLER_H |
991 | + |
992 | |
993 | === modified file 'plugins/wifi/plugin.cpp' |
994 | --- plugins/wifi/plugin.cpp 2014-07-23 13:53:48 +0000 |
995 | +++ plugins/wifi/plugin.cpp 2015-05-12 23:13:53 +0000 |
996 | @@ -22,6 +22,7 @@ |
997 | #include "unitymenumodelstack.h" |
998 | #include "wifidbushelper.h" |
999 | #include "previousnetworkmodel.h" |
1000 | +#include "certhandler.h" |
1001 | |
1002 | namespace { |
1003 | |
1004 | @@ -45,6 +46,8 @@ |
1005 | qmlRegisterType<UnityMenuModelStack>(uri, 1, 0, "UnityMenuModelStack"); |
1006 | qmlRegisterSingletonType<WifiDbusHelper>(uri, 1, 0, "DbusHelper", dbusProvider); |
1007 | qmlRegisterType<PreviousNetworkModel>(uri, 1, 0, "PreviousNetworkModel"); |
1008 | + qmlRegisterType<CertificateListModel>(uri, 1, 0, "CertificateListModel"); |
1009 | + qmlRegisterType<CertificateHandler>(uri, 1, 0, "CertificateHandler"); |
1010 | } |
1011 | |
1012 | void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
1013 | |
1014 | === modified file 'plugins/wifi/wifidbushelper.cpp' |
1015 | --- plugins/wifi/wifidbushelper.cpp 2014-10-10 14:10:52 +0000 |
1016 | +++ plugins/wifi/wifidbushelper.cpp 2015-05-12 23:13:53 +0000 |
1017 | @@ -37,15 +37,29 @@ |
1018 | typedef QMap<QString,QVariantMap> ConfigurationData; |
1019 | Q_DECLARE_METATYPE(ConfigurationData) |
1020 | |
1021 | + |
1022 | WifiDbusHelper::WifiDbusHelper(QObject *parent) : QObject(parent), |
1023 | m_systemBusConnection(QDBusConnection::systemBus()) |
1024 | { |
1025 | qDBusRegisterMetaType<ConfigurationData>(); |
1026 | } |
1027 | |
1028 | -void WifiDbusHelper::connect(QString ssid, int security, QString password) |
1029 | + |
1030 | +QByteArray WifiDbusHelper::getCertContent(QString filename){ |
1031 | + QFile file(filename); |
1032 | + if (!file.open(QIODevice::ReadOnly)) { |
1033 | + qWarning() << "Could not resolve Cert-File (" << filename << "): File does not exist or is empty." ; |
1034 | + return QByteArray(); |
1035 | + } |
1036 | + else { |
1037 | + return file.readAll(); |
1038 | + } |
1039 | +} |
1040 | + |
1041 | + |
1042 | +void WifiDbusHelper::connect(QString ssid, int security, int auth, QStringList usernames, QString password, QStringList certs, int p2auth) |
1043 | { |
1044 | - if(security<0 || security>2) { |
1045 | + if((security<0 || security>5) || (auth<0 || auth>4) || (p2auth<0 || p2auth>5)) { |
1046 | qWarning() << "Qml and C++ have gotten out of sync. Can't connect.\n"; |
1047 | return; |
1048 | } |
1049 | @@ -66,8 +80,11 @@ |
1050 | // security: |
1051 | // 0: None |
1052 | // 1: WPA & WPA2 Personal |
1053 | - // 2: WEP |
1054 | - if (security != 0) { |
1055 | + // 2: WPA Enterprise |
1056 | + // 3: WEP |
1057 | + // 4: Dynamic WEP |
1058 | + // 5: LEAP |
1059 | + if (security != 0) { // WPA Enterprise or Dynamic WEP |
1060 | wireless["security"] = QStringLiteral("802-11-wireless-security"); |
1061 | |
1062 | QVariantMap wireless_security; |
1063 | @@ -75,17 +92,124 @@ |
1064 | if (security == 1) { |
1065 | wireless_security["key-mgmt"] = QStringLiteral("wpa-psk"); |
1066 | wireless_security["psk"] = password; |
1067 | - } else if (security == 2) { |
1068 | + } else if (security == 3) { |
1069 | wireless_security["key-mgmt"] = QStringLiteral("none"); |
1070 | wireless_security["auth-alg"] = QStringLiteral("open"); |
1071 | wireless_security["wep-key0"] = password; |
1072 | wireless_security["wep-key-type"] = QVariant(uint(1)); |
1073 | + } else if (security == 2) { |
1074 | + wireless_security["key-mgmt"] = QStringLiteral("wpa-eap"); |
1075 | + } else if (security == 4) { |
1076 | + wireless_security["key-mgmt"] = QStringLiteral("ieee8021x"); |
1077 | + /* leave disabled as hopefully not needed: |
1078 | + QStringList wep_pairwise, wep_group; |
1079 | + wep_pairwise[0] ="wep40"; wep_pairwise[1] ="wep104"; |
1080 | + wep_group[0] ="wep40"; wep_group[1] ="wep104"; |
1081 | + wireless_security["pairwise"] = wep_pairwise; |
1082 | + wireless_security["group"] = wep_group; */ |
1083 | + } else if (security == 5) { |
1084 | + wireless_security["key-mgmt"] = QStringLiteral("ieee8021x"); |
1085 | + wireless_security["auth-alg"] = QStringLiteral("leap"); |
1086 | + wireless_security["leap-username"] = usernames[0]; |
1087 | + wireless_security["leap-password"] = password; |
1088 | } |
1089 | configuration["802-11-wireless-security"] = wireless_security; |
1090 | } |
1091 | |
1092 | configuration["802-11-wireless"] = wireless; |
1093 | |
1094 | + if (security == 2 || security == 4){ |
1095 | + |
1096 | + QVariantMap wireless_802_1x; |
1097 | + // [802-1x] |
1098 | + /*TLS // index: 0 |
1099 | + TTLS // index: 1 |
1100 | + LEAP // index: 2 |
1101 | + FAST // index: 3 |
1102 | + PEAP // index: 4 */ |
1103 | + |
1104 | + wireless_802_1x["identity"] = usernames[0]; |
1105 | + if (auth != 0) { |
1106 | + wireless_802_1x["password"] = password; |
1107 | + } |
1108 | + |
1109 | + QByteArray cacert_a, clientcert, privatekey, pacFile; |
1110 | + |
1111 | + if (certs[0].left(1) == "/"){ |
1112 | + cacert_a = getCertContent(certs[0]); |
1113 | + } |
1114 | + else { |
1115 | + cacert_a.append(certs[0]); |
1116 | + } |
1117 | + |
1118 | + if (auth == 0) { // TLS |
1119 | + wireless_802_1x["eap"] = QStringList("tls"); |
1120 | + wireless_802_1x["ca-cert"] = cacert_a; |
1121 | + |
1122 | + if (certs[1].left(1) == "/"){ |
1123 | + clientcert = getCertContent(certs[1]); |
1124 | + } |
1125 | + else { |
1126 | + clientcert.append(certs[1]); |
1127 | + } |
1128 | + wireless_802_1x["client-cert"] = clientcert; |
1129 | + if (certs[2].left(1) == "/"){ |
1130 | + privatekey = getCertContent(certs[2]); |
1131 | + } |
1132 | + else { |
1133 | + privatekey.append(certs[2]); |
1134 | + } |
1135 | + wireless_802_1x["private-key"] = privatekey; |
1136 | + wireless_802_1x["private-key-password"] = password; |
1137 | + } else if (auth == 1) { // TTLS |
1138 | + wireless_802_1x["eap"] = QStringList("ttls"); |
1139 | + wireless_802_1x["ca-cert"] = cacert_a; |
1140 | + wireless_802_1x["anonymous-identity"] = usernames[1]; |
1141 | + } else if (auth == 2) { // LEAP |
1142 | + wireless_802_1x["eap"] = QStringList("leap"); |
1143 | + } else if (auth == 3) { // FAST |
1144 | + wireless_802_1x["eap"] = QStringList("fast"); |
1145 | + wireless_802_1x["ca-cert"] = cacert_a; |
1146 | + wireless_802_1x["anonymous-identity"] = usernames[1]; |
1147 | + |
1148 | + if (certs[3].left(1) == "/"){ |
1149 | + pacFile = getCertContent(certs[3]); |
1150 | + } |
1151 | + else { |
1152 | + pacFile.append(certs[3]); |
1153 | + } |
1154 | + wireless_802_1x["pac-file"] = pacFile; |
1155 | + // wireless_802_1x["phase1-fast-provisioning"] = QString("0"); |
1156 | + } else if (auth == 4) { // PEAP |
1157 | + wireless_802_1x["eap"] = QStringList("peap"); |
1158 | + wireless_802_1x["phase1-peaplabel"] = QString("1"); |
1159 | + wireless_802_1x["anonymous-identity"] = usernames[1]; |
1160 | + //wireless_802_1x["phase1-peapver"] = QString("0"); #jkb:let us unset this until problems are reported. |
1161 | + } |
1162 | + |
1163 | + if (auth == 1 || auth == 3 || auth == 4 ){ // only for TTLS, FAST and PEAP |
1164 | + /* PAP // index: 0 |
1165 | + MSCHAPv2 // index: 1 |
1166 | + MSCHAP // index: 2 |
1167 | + CHAP // index: 3 |
1168 | + GTC // index: 4 |
1169 | + MD5 // index: 5 */ |
1170 | + if (p2auth == 0) { |
1171 | + wireless_802_1x["phase2-auth"] = QStringLiteral("pap"); |
1172 | + } else if (p2auth == 1) { |
1173 | + wireless_802_1x["phase2-auth"] = QStringLiteral("mschapv2"); |
1174 | + } else if (p2auth == 2) { |
1175 | + wireless_802_1x["phase2-auth"] = QStringLiteral("mschap"); |
1176 | + } else if (p2auth == 3) { |
1177 | + wireless_802_1x["phase2-auth"] = QStringLiteral("chap"); |
1178 | + } else if (p2auth == 4) { |
1179 | + wireless_802_1x["phase2-auth"] = QStringLiteral("gtc"); |
1180 | + } else if (p2auth == 5) { |
1181 | + wireless_802_1x["phase2-auth"] = QStringLiteral("md5"); |
1182 | + } |
1183 | + } |
1184 | + configuration["802-1x"] = wireless_802_1x; |
1185 | + } |
1186 | |
1187 | // find the first wlan adapter for now |
1188 | auto reply1 = mgr.GetDevices(); |
1189 | @@ -142,6 +266,7 @@ |
1190 | } |
1191 | } |
1192 | |
1193 | + |
1194 | void WifiDbusHelper::nmDeviceStateChanged(uint newState, |
1195 | uint oldState, |
1196 | uint reason) |
1197 | @@ -150,6 +275,7 @@ |
1198 | Q_EMIT (deviceStateChanged(newState, reason)); |
1199 | } |
1200 | |
1201 | + |
1202 | QString WifiDbusHelper::getWifiIpAddress() |
1203 | { |
1204 | OrgFreedesktopNetworkManagerInterface mgr(NM_SERVICE, |
1205 | @@ -193,6 +319,7 @@ |
1206 | return QString(inet_ntoa(ip_addr)); |
1207 | } |
1208 | |
1209 | + |
1210 | struct Network : public QObject |
1211 | { |
1212 | struct DontCare : public std::exception {}; |
1213 | @@ -345,6 +472,7 @@ |
1214 | QMap<QString, QVariantMap> settings; |
1215 | }; |
1216 | |
1217 | + |
1218 | QList<QStringList> WifiDbusHelper::getPreviouslyConnectedWifiNetworks() { |
1219 | QList<QStringList> networks; |
1220 | |
1221 | @@ -383,6 +511,7 @@ |
1222 | return networks; |
1223 | } |
1224 | |
1225 | + |
1226 | void WifiDbusHelper::forgetConnection(const QString dbus_path) { |
1227 | OrgFreedesktopNetworkManagerSettingsConnectionInterface bar |
1228 | (NM_SERVICE, |
1229 | @@ -395,6 +524,7 @@ |
1230 | } |
1231 | } |
1232 | |
1233 | + |
1234 | bool WifiDbusHelper::forgetActiveDevice() { |
1235 | OrgFreedesktopNetworkManagerInterface mgr(NM_SERVICE, |
1236 | NM_PATH, |
1237 | |
1238 | === modified file 'plugins/wifi/wifidbushelper.h' |
1239 | --- plugins/wifi/wifidbushelper.h 2014-10-10 14:10:52 +0000 |
1240 | +++ plugins/wifi/wifidbushelper.h 2015-05-12 23:13:53 +0000 |
1241 | @@ -37,7 +37,7 @@ |
1242 | explicit WifiDbusHelper(QObject *parent = nullptr); |
1243 | ~WifiDbusHelper() {}; |
1244 | |
1245 | - Q_INVOKABLE void connect(QString ssid, int security, QString password); |
1246 | + Q_INVOKABLE void connect(QString ssid, int security, int auth, QStringList usernames, QString password, QStringList certs, int p2auth); |
1247 | Q_INVOKABLE QList<QStringList> getPreviouslyConnectedWifiNetworks(); |
1248 | Q_INVOKABLE void forgetConnection(const QString dbus_path); |
1249 | Q_INVOKABLE bool forgetActiveDevice(); |
1250 | @@ -52,6 +52,7 @@ |
1251 | private: |
1252 | QDBusConnection m_systemBusConnection; |
1253 | QString getWifiIpAddress(); |
1254 | + QByteArray getCertContent(QString filename); |
1255 | }; |
1256 | |
1257 |
This is really great. Thanks for proposing this.
I've added some comments, but they're mostly about your decision to make the Dialog an ItemPage. If this is not crucial to the implementation of support for 802-1x, we need to revert it.
Also, if cert picking is not implemented, please remove all components that are unused. Please leave the UI bits in, but hide it with "visible: showAllUI". This way we can get strings translated.
Thanks again.