Merge ubiquity:focal_ecryption_recovery_key into ubiquity:focal
- Git
- lp:ubiquity
- focal_ecryption_recovery_key
- Merge into focal
Proposed by
Jean-Baptiste Lallement
Status: | Merged |
---|---|
Merged at revision: | 42c32fe6ad6e98d3c07ecbe815f28c03ecea9500 |
Proposed branch: | ubiquity:focal_ecryption_recovery_key |
Merge into: | ubiquity:focal |
Diff against target: |
1289 lines (+772/-83) 8 files modified
debian/ubiquity.templates (+90/-1) gui/gtk/stepPartCrypto.ui (+427/-77) scripts/plugininstall.py (+51/-0) tests/test_gtkui.py (+3/-1) ubiquity/components/plugininstall.py (+2/-0) ubiquity/misc.py (+37/-0) ubiquity/plugins/ubi-partman.py (+156/-4) ubiquity/validation.py (+6/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Didier Roche-Tolomelli (community) | Approve | ||
Review via email: mp+405767@code.launchpad.net |
Commit message
This is a backport of the recovery key feature introduced in 21.04 and improved for 21.10
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/debian/ubiquity.templates b/debian/ubiquity.templates |
2 | index 5528e77..d3b8268 100644 |
3 | --- a/debian/ubiquity.templates |
4 | +++ b/debian/ubiquity.templates |
5 | @@ -782,6 +782,15 @@ _Description: Error configuring connection to Active Directory |
6 | <a href="https://discourse.ubuntu.com/t/service-sssd/11579">ubuntu.com/activedirectory</a> |
7 | for help. |
8 | |
9 | +Template: ubiquity/install/broken_luks_add_key |
10 | +Type: error |
11 | +_Description: Error setting LUKS recovery key |
12 | + An error occurred while setting the recovery key. The |
13 | + installation will continue, but you may have to manually add the recovery |
14 | + key in the installed system with the command: |
15 | + . |
16 | + cryptsetup luksAddKey <device> |
17 | + |
18 | Template: ubiquity/install/md5_check |
19 | Type: boolean |
20 | Default: true |
21 | @@ -1716,4 +1725,84 @@ _Description: That name already exists on the network. |
22 | |
23 | Template: ubiquity/text/domain_connection_error |
24 | Type: text |
25 | -_Description: Failed to connect to domain. |
26 | \ No newline at end of file |
27 | +_Description: Failed to connect to domain. |
28 | + |
29 | +Template: ubiquity/text/recovery_key_enable |
30 | +Type: text |
31 | +_Description: |
32 | + Enable recovery key: |
33 | + |
34 | +Template: ubiquity/text/recovery_key_label |
35 | +Type: text |
36 | +_Description: |
37 | + Recovery key: |
38 | + |
39 | +Template: ubiquity/text/verified_recovery_key_label |
40 | +Type: text |
41 | +_Description: |
42 | + Confirm recovery key: |
43 | + |
44 | +Template: ubiquity/text/show_recovery_key |
45 | +Type: text |
46 | +_Description: |
47 | + Display recovery key: |
48 | + |
49 | +Template: ubiquity/text/recovery_key_warning |
50 | +Type: text |
51 | +_Description: |
52 | + A recovery key is generated and will be temporarily saved on the live system. |
53 | + You can select an alternate location. Save this file and keep it in a safe |
54 | + place elsewhere before rebooting. |
55 | + |
56 | +Template: ubiquity/text/recovery_key_location_label |
57 | +Type: text |
58 | +_Description: Location: |
59 | + |
60 | +Template: ubiquity/text/recovery_key_location_warning |
61 | +Type: text |
62 | +_Description: |
63 | + It is not recommended to store the key on a non removable device. |
64 | + |
65 | +Template: ubiquity/crypto_key |
66 | +Type: password |
67 | +_Description: Crypto key for LUKS + LVM |
68 | + |
69 | +Template: ubiquity/recovery_key |
70 | +Type: password |
71 | +_Description: Recovery key for LUKS + LVM |
72 | + |
73 | +Template: ubiquity/text/save_recovery_key_info |
74 | +Type: text |
75 | +_Description: |
76 | + Count not save recovery key: |
77 | + . |
78 | + ${ERRORMSG} |
79 | + |
80 | +Template: ubiquity/text/recovery_key_filename |
81 | +Type: text |
82 | +_Description: |
83 | + Enter recovery key filename |
84 | + |
85 | +Template: ubiquity/text/recovery_mismatch |
86 | +Type: text |
87 | +_Description: Passwords do not match |
88 | + |
89 | +Template: ubiquity/text/recovery_too_short |
90 | +Type: text |
91 | +_Description: Short password |
92 | + |
93 | +Template: ubiquity/text/recovery_weak |
94 | +Type: text |
95 | +_Description: Weak password |
96 | + |
97 | +Template: ubiquity/text/recovery_fair |
98 | +Type: text |
99 | +_Description: Fair password |
100 | + |
101 | +Template: ubiquity/text/recovery_good |
102 | +Type: text |
103 | +_Description: Good password |
104 | + |
105 | +Template: ubiquity/text/recovery_strong |
106 | +Type: text |
107 | +_Description: Strong password |
108 | diff --git a/gui/gtk/stepPartCrypto.ui b/gui/gtk/stepPartCrypto.ui |
109 | index 62b3556..89616b0 100644 |
110 | --- a/gui/gtk/stepPartCrypto.ui |
111 | +++ b/gui/gtk/stepPartCrypto.ui |
112 | @@ -1,6 +1,17 @@ |
113 | <?xml version="1.0" encoding="UTF-8"?> |
114 | +<!-- Generated with glade 3.22.2 --> |
115 | <interface> |
116 | - <!-- interface-requires gtk+ 3.0 --> |
117 | + <requires lib="gtk+" version="3.24"/> |
118 | + <object class="GtkImage" id="image_file"> |
119 | + <property name="visible">True</property> |
120 | + <property name="can_focus">False</property> |
121 | + <property name="stock">gtk-save-as</property> |
122 | + </object> |
123 | + <object class="GtkImage" id="image_generate_key"> |
124 | + <property name="visible">True</property> |
125 | + <property name="can_focus">False</property> |
126 | + <property name="stock">gtk-refresh</property> |
127 | + </object> |
128 | <object class="GtkAlignment" id="stepPartCrypto"> |
129 | <property name="visible">True</property> |
130 | <property name="can_focus">False</property> |
131 | @@ -9,6 +20,7 @@ |
132 | <property name="left_padding">24</property> |
133 | <property name="right_padding">24</property> |
134 | <child> |
135 | + <!-- n-columns=2 n-rows=11 --> |
136 | <object class="GtkGrid" id="crypto_grid"> |
137 | <property name="visible">True</property> |
138 | <property name="can_focus">False</property> |
139 | @@ -18,32 +30,28 @@ |
140 | <object class="GtkLabel" id="verified_crypto_label"> |
141 | <property name="visible">True</property> |
142 | <property name="can_focus">False</property> |
143 | - <property name="xalign">1</property> |
144 | <property name="label" translatable="yes">Confirm the security key:</property> |
145 | <property name="justify">right</property> |
146 | <property name="single_line_mode">True</property> |
147 | + <property name="xalign">1</property> |
148 | </object> |
149 | <packing> |
150 | <property name="left_attach">0</property> |
151 | <property name="top_attach">3</property> |
152 | - <property name="width">1</property> |
153 | - <property name="height">1</property> |
154 | </packing> |
155 | </child> |
156 | <child> |
157 | <object class="GtkLabel" id="crypto_label"> |
158 | <property name="visible">True</property> |
159 | <property name="can_focus">False</property> |
160 | - <property name="xalign">1</property> |
161 | <property name="label" translatable="yes">Choose a security key:</property> |
162 | <property name="justify">right</property> |
163 | <property name="single_line_mode">True</property> |
164 | + <property name="xalign">1</property> |
165 | </object> |
166 | <packing> |
167 | <property name="left_attach">0</property> |
168 | <property name="top_attach">2</property> |
169 | - <property name="width">1</property> |
170 | - <property name="height">1</property> |
171 | </packing> |
172 | </child> |
173 | <child> |
174 | @@ -51,15 +59,16 @@ |
175 | <property name="visible">True</property> |
176 | <property name="can_focus">False</property> |
177 | <property name="halign">start</property> |
178 | - <property name="xalign">0</property> |
179 | <property name="label" translatable="yes">Disk encryption protects your files in case you lose your computer. It requires you to enter a security key each time the computer starts up.</property> |
180 | <property name="wrap">True</property> |
181 | + <property name="width_chars">92</property> |
182 | + <property name="max_width_chars">92</property> |
183 | + <property name="xalign">0</property> |
184 | </object> |
185 | <packing> |
186 | <property name="left_attach">0</property> |
187 | <property name="top_attach">0</property> |
188 | <property name="width">2</property> |
189 | - <property name="height">1</property> |
190 | </packing> |
191 | </child> |
192 | <child> |
193 | @@ -67,16 +76,245 @@ |
194 | <property name="visible">True</property> |
195 | <property name="can_focus">False</property> |
196 | <property name="halign">start</property> |
197 | - <property name="xalign">0</property> |
198 | - <property name="label" translatable="yes"><span foreground="darkred">Warning:</span> If you lose this security key, all data will be lost. If you need to, write down your key and keep it in a safe place elsewhere.</property> |
199 | + <property name="margin_top">6</property> |
200 | + <property name="label" translatable="yes"><span foreground="darkred">Warning:</span> If you lose your personal security key and recovery key, all data will be lost.</property> |
201 | <property name="use_markup">True</property> |
202 | <property name="wrap">True</property> |
203 | + <property name="width_chars">92</property> |
204 | + <property name="max_width_chars">92</property> |
205 | + <property name="xalign">0</property> |
206 | </object> |
207 | <packing> |
208 | <property name="left_attach">0</property> |
209 | - <property name="top_attach">4</property> |
210 | + <property name="top_attach">8</property> |
211 | <property name="width">2</property> |
212 | - <property name="height">1</property> |
213 | + </packing> |
214 | + </child> |
215 | + <child> |
216 | + <object class="GtkLabel" id="crypto_description_2"> |
217 | + <property name="visible">True</property> |
218 | + <property name="can_focus">False</property> |
219 | + <property name="halign">start</property> |
220 | + <property name="label" translatable="yes">Any files outside of Ubuntu will not be encrypted.</property> |
221 | + <property name="wrap">True</property> |
222 | + <property name="xalign">0</property> |
223 | + </object> |
224 | + <packing> |
225 | + <property name="left_attach">0</property> |
226 | + <property name="top_attach">1</property> |
227 | + <property name="width">2</property> |
228 | + </packing> |
229 | + </child> |
230 | + <child> |
231 | + <!-- n-columns=3 n-rows=2 --> |
232 | + <object class="GtkGrid" id="password_grid"> |
233 | + <property name="visible">True</property> |
234 | + <property name="can_focus">False</property> |
235 | + <property name="row_spacing">6</property> |
236 | + <property name="column_spacing">6</property> |
237 | + <child> |
238 | + <object class="GtkEntry" id="password"> |
239 | + <property name="visible">True</property> |
240 | + <property name="can_focus">True</property> |
241 | + <property name="visibility">False</property> |
242 | + <property name="invisible_char">●</property> |
243 | + <property name="activates_default">True</property> |
244 | + <property name="width_chars">36</property> |
245 | + <signal name="changed" handler="info_loop" swapped="no"/> |
246 | + </object> |
247 | + <packing> |
248 | + <property name="left_attach">0</property> |
249 | + <property name="top_attach">0</property> |
250 | + </packing> |
251 | + </child> |
252 | + <child> |
253 | + <object class="GtkEntry" id="verified_password"> |
254 | + <property name="visible">True</property> |
255 | + <property name="can_focus">True</property> |
256 | + <property name="visibility">False</property> |
257 | + <property name="invisible_char">●</property> |
258 | + <property name="activates_default">True</property> |
259 | + <property name="width_chars">36</property> |
260 | + <signal name="changed" handler="info_loop" swapped="no"/> |
261 | + </object> |
262 | + <packing> |
263 | + <property name="left_attach">0</property> |
264 | + <property name="top_attach">1</property> |
265 | + </packing> |
266 | + </child> |
267 | + <child> |
268 | + <object class="GtkNotebook" id="password_strength"> |
269 | + <property name="visible">True</property> |
270 | + <property name="can_focus">False</property> |
271 | + <property name="show_tabs">False</property> |
272 | + <property name="show_border">False</property> |
273 | + <child> |
274 | + <object class="GtkFixed" id="password/empty"> |
275 | + <property name="visible">True</property> |
276 | + <property name="can_focus">False</property> |
277 | + </object> |
278 | + </child> |
279 | + <child type="tab"> |
280 | + <placeholder/> |
281 | + </child> |
282 | + <child> |
283 | + <object class="GtkLabel" id="password/too_short"> |
284 | + <property name="visible">True</property> |
285 | + <property name="can_focus">False</property> |
286 | + <property name="label" translatable="yes">Short password</property> |
287 | + <property name="xalign">0</property> |
288 | + <attributes> |
289 | + <attribute name="scale" value="0.83333333333329995"/> |
290 | + <attribute name="foreground" value="#8b8b00000000"/> |
291 | + </attributes> |
292 | + </object> |
293 | + <packing> |
294 | + <property name="position">1</property> |
295 | + </packing> |
296 | + </child> |
297 | + <child type="tab"> |
298 | + <placeholder/> |
299 | + </child> |
300 | + <child> |
301 | + <object class="GtkLabel" id="password/weak"> |
302 | + <property name="visible">True</property> |
303 | + <property name="can_focus">False</property> |
304 | + <property name="label" translatable="yes">Weak password</property> |
305 | + <property name="xalign">0</property> |
306 | + <attributes> |
307 | + <attribute name="scale" value="0.83333333333329995"/> |
308 | + <attribute name="foreground" value="#8b8b00000000"/> |
309 | + </attributes> |
310 | + </object> |
311 | + <packing> |
312 | + <property name="position">2</property> |
313 | + </packing> |
314 | + </child> |
315 | + <child type="tab"> |
316 | + <placeholder/> |
317 | + </child> |
318 | + <child> |
319 | + <object class="GtkLabel" id="password/fair"> |
320 | + <property name="visible">True</property> |
321 | + <property name="can_focus">False</property> |
322 | + <property name="label" translatable="yes">Fair password</property> |
323 | + <property name="xalign">0</property> |
324 | + <attributes> |
325 | + <attribute name="scale" value="0.83333333333329995"/> |
326 | + <attribute name="foreground" value="#ffff8c8c0000"/> |
327 | + </attributes> |
328 | + </object> |
329 | + <packing> |
330 | + <property name="position">3</property> |
331 | + </packing> |
332 | + </child> |
333 | + <child type="tab"> |
334 | + <placeholder/> |
335 | + </child> |
336 | + <child> |
337 | + <object class="GtkLabel" id="password/good"> |
338 | + <property name="visible">True</property> |
339 | + <property name="can_focus">False</property> |
340 | + <property name="label" translatable="yes">Good password</property> |
341 | + <property name="xalign">0</property> |
342 | + <attributes> |
343 | + <attribute name="scale" value="0.83333333333329995"/> |
344 | + <attribute name="foreground" value="#000064640000"/> |
345 | + </attributes> |
346 | + </object> |
347 | + <packing> |
348 | + <property name="position">4</property> |
349 | + </packing> |
350 | + </child> |
351 | + <child type="tab"> |
352 | + <placeholder/> |
353 | + </child> |
354 | + <child> |
355 | + <object class="GtkLabel" id="password/strong"> |
356 | + <property name="visible">True</property> |
357 | + <property name="can_focus">False</property> |
358 | + <property name="label" translatable="yes">Strong password</property> |
359 | + <property name="xalign">0</property> |
360 | + <attributes> |
361 | + <attribute name="scale" value="0.83333333333329995"/> |
362 | + <attribute name="foreground" value="#000064640000"/> |
363 | + </attributes> |
364 | + </object> |
365 | + <packing> |
366 | + <property name="position">5</property> |
367 | + </packing> |
368 | + </child> |
369 | + <child type="tab"> |
370 | + <placeholder/> |
371 | + </child> |
372 | + </object> |
373 | + <packing> |
374 | + <property name="left_attach">1</property> |
375 | + <property name="top_attach">0</property> |
376 | + </packing> |
377 | + </child> |
378 | + <child> |
379 | + <object class="GtkNotebook" id="password_match"> |
380 | + <property name="visible">True</property> |
381 | + <property name="can_focus">False</property> |
382 | + <property name="show_tabs">False</property> |
383 | + <property name="show_border">False</property> |
384 | + <child> |
385 | + <object class="GtkFixed" id="empty2"> |
386 | + <property name="visible">True</property> |
387 | + <property name="can_focus">False</property> |
388 | + </object> |
389 | + </child> |
390 | + <child type="tab"> |
391 | + <placeholder/> |
392 | + </child> |
393 | + <child> |
394 | + <object class="GtkLabel" id="password_mismatch"> |
395 | + <property name="visible">True</property> |
396 | + <property name="can_focus">False</property> |
397 | + <property name="label" translatable="yes">Mismatch</property> |
398 | + <property name="wrap">True</property> |
399 | + <property name="xalign">0</property> |
400 | + <attributes> |
401 | + <attribute name="scale" value="0.83333333333329995"/> |
402 | + <attribute name="foreground" value="#8b8b00000000"/> |
403 | + </attributes> |
404 | + </object> |
405 | + <packing> |
406 | + <property name="position">1</property> |
407 | + </packing> |
408 | + </child> |
409 | + <child> |
410 | + <object class="GtkImage" id="password_ok"> |
411 | + <property name="visible">True</property> |
412 | + <property name="can_focus">False</property> |
413 | + <property name="xalign">0</property> |
414 | + <property name="stock">gtk-apply</property> |
415 | + </object> |
416 | + <packing> |
417 | + <property name="position">2</property> |
418 | + </packing> |
419 | + </child> |
420 | + <child type="tab"> |
421 | + <placeholder/> |
422 | + </child> |
423 | + </object> |
424 | + <packing> |
425 | + <property name="left_attach">1</property> |
426 | + <property name="top_attach">1</property> |
427 | + </packing> |
428 | + </child> |
429 | + <child> |
430 | + <placeholder/> |
431 | + </child> |
432 | + <child> |
433 | + <placeholder/> |
434 | + </child> |
435 | + </object> |
436 | + <packing> |
437 | + <property name="left_attach">1</property> |
438 | + <property name="top_attach">2</property> |
439 | + <property name="height">2</property> |
440 | </packing> |
441 | </child> |
442 | <child> |
443 | @@ -84,120 +322,172 @@ |
444 | <property name="visible">True</property> |
445 | <property name="can_focus">False</property> |
446 | <property name="halign">end</property> |
447 | - <property name="xalign">0</property> |
448 | <property name="label" translatable="yes">For more security:</property> |
449 | <property name="justify">right</property> |
450 | + <property name="xalign">0</property> |
451 | </object> |
452 | <packing> |
453 | <property name="left_attach">0</property> |
454 | - <property name="top_attach">5</property> |
455 | - <property name="width">1</property> |
456 | - <property name="height">1</property> |
457 | + <property name="top_attach">9</property> |
458 | </packing> |
459 | </child> |
460 | <child> |
461 | <object class="GtkCheckButton" id="crypto_overwrite_space"> |
462 | - <property name="label" translatable="yes">Overwrite the available space first</property> |
463 | + <property name="label" translatable="yes">Overwrite the available space first.</property> |
464 | <property name="use_action_appearance">False</property> |
465 | <property name="visible">True</property> |
466 | <property name="can_focus">True</property> |
467 | <property name="receives_default">False</property> |
468 | - <property name="use_action_appearance">False</property> |
469 | <property name="xalign">0</property> |
470 | <property name="draw_indicator">True</property> |
471 | </object> |
472 | <packing> |
473 | <property name="left_attach">1</property> |
474 | - <property name="top_attach">5</property> |
475 | - <property name="width">1</property> |
476 | - <property name="height">1</property> |
477 | + <property name="top_attach">9</property> |
478 | </packing> |
479 | </child> |
480 | <child> |
481 | - <object class="GtkLabel" id="crypto_extra_time"> |
482 | + <object class="GtkLabel" id="recovery_key_warning"> |
483 | <property name="visible">True</property> |
484 | <property name="can_focus">False</property> |
485 | - <property name="margin_left">24</property> |
486 | + <property name="halign">start</property> |
487 | + <property name="margin_top">6</property> |
488 | + <property name="label" translatable="yes">A recovery key is generated and will be temporarily saved on the live system. You can enter your own and can select an alternate location. Save this file and keep it in a safe place elsewhere before rebooting. </property> |
489 | + <property name="wrap">True</property> |
490 | + <property name="width_chars">72</property> |
491 | + <property name="max_width_chars">72</property> |
492 | <property name="xalign">0</property> |
493 | - <property name="label" translatable="yes"><span weight="light" size="small">The installation may take much longer.</span></property> |
494 | - <property name="use_markup">True</property> |
495 | - <property name="single_line_mode">True</property> |
496 | </object> |
497 | <packing> |
498 | <property name="left_attach">1</property> |
499 | - <property name="top_attach">6</property> |
500 | - <property name="width">1</property> |
501 | - <property name="height">1</property> |
502 | + <property name="top_attach">4</property> |
503 | </packing> |
504 | </child> |
505 | <child> |
506 | - <object class="GtkLabel" id="crypto_description_2"> |
507 | + <object class="GtkLabel" id="recovery_key_location_label"> |
508 | <property name="visible">True</property> |
509 | <property name="can_focus">False</property> |
510 | - <property name="halign">start</property> |
511 | - <property name="xalign">0</property> |
512 | - <property name="label" translatable="yes">Any files outside of Ubuntu will not be encrypted.</property> |
513 | - <property name="wrap">True</property> |
514 | + <property name="label" translatable="yes">Location:</property> |
515 | + <property name="justify">right</property> |
516 | + <property name="single_line_mode">True</property> |
517 | + <property name="xalign">1</property> |
518 | </object> |
519 | <packing> |
520 | <property name="left_attach">0</property> |
521 | - <property name="top_attach">1</property> |
522 | - <property name="width">2</property> |
523 | - <property name="height">1</property> |
524 | + <property name="top_attach">7</property> |
525 | </packing> |
526 | </child> |
527 | <child> |
528 | - <object class="GtkGrid" id="password_grid"> |
529 | + <object class="GtkLabel" id="recovery_key_label"> |
530 | + <property name="visible">True</property> |
531 | + <property name="can_focus">False</property> |
532 | + <property name="label" translatable="yes">Recovery key:</property> |
533 | + <property name="justify">right</property> |
534 | + <property name="single_line_mode">True</property> |
535 | + <property name="xalign">1</property> |
536 | + </object> |
537 | + <packing> |
538 | + <property name="left_attach">0</property> |
539 | + <property name="top_attach">5</property> |
540 | + </packing> |
541 | + </child> |
542 | + <child> |
543 | + <object class="GtkLabel" id="verified_recovery_key_label"> |
544 | + <property name="visible">True</property> |
545 | + <property name="can_focus">False</property> |
546 | + <property name="label" translatable="yes">Confirm the recovery key:</property> |
547 | + <property name="justify">right</property> |
548 | + <property name="single_line_mode">True</property> |
549 | + <property name="xalign">1</property> |
550 | + </object> |
551 | + <packing> |
552 | + <property name="left_attach">0</property> |
553 | + <property name="top_attach">6</property> |
554 | + </packing> |
555 | + </child> |
556 | + <child> |
557 | + <object class="GtkCheckButton" id="recovery_key_enable"> |
558 | + <property name="label" translatable="yes">Enable recovery key</property> |
559 | + <property name="visible">True</property> |
560 | + <property name="can_focus">True</property> |
561 | + <property name="receives_default">False</property> |
562 | + <property name="valign">start</property> |
563 | + <property name="margin_top">6</property> |
564 | + <property name="draw_indicator">True</property> |
565 | + <signal name="toggled" handler="on_recovery_key_enable_toggled" swapped="no"/> |
566 | + </object> |
567 | + <packing> |
568 | + <property name="left_attach">0</property> |
569 | + <property name="top_attach">4</property> |
570 | + </packing> |
571 | + </child> |
572 | + <child> |
573 | + <!-- n-columns=3 n-rows=3 --> |
574 | + <object class="GtkGrid" id="recovery_grid"> |
575 | <property name="visible">True</property> |
576 | <property name="can_focus">False</property> |
577 | <property name="row_spacing">6</property> |
578 | <property name="column_spacing">6</property> |
579 | <child> |
580 | - <object class="GtkEntry" id="password"> |
581 | + <object class="GtkEntry" id="recovery_key"> |
582 | <property name="visible">True</property> |
583 | <property name="can_focus">True</property> |
584 | - <property name="hexpand">True</property> |
585 | <property name="visibility">False</property> |
586 | <property name="invisible_char">●</property> |
587 | <property name="activates_default">True</property> |
588 | - <property name="width_chars">20</property> |
589 | - <property name="invisible_char_set">True</property> |
590 | + <property name="width_chars">36</property> |
591 | + <property name="secondary_icon_name">view-reveal-symbolic</property> |
592 | + <property name="primary_icon_activatable">False</property> |
593 | + <property name="primary_icon_sensitive">False</property> |
594 | + <property name="secondary_icon_tooltip_text" translatable="yes"> </property> |
595 | + <property name="secondary_icon_tooltip_markup" translatable="yes"> </property> |
596 | <signal name="changed" handler="info_loop" swapped="no"/> |
597 | + <signal name="icon_press" handler="on_recovery_key_toggle_visibility" swapped="no"/> |
598 | </object> |
599 | <packing> |
600 | <property name="left_attach">0</property> |
601 | <property name="top_attach">0</property> |
602 | - <property name="width">1</property> |
603 | - <property name="height">1</property> |
604 | </packing> |
605 | </child> |
606 | <child> |
607 | - <object class="GtkEntry" id="verified_password"> |
608 | + <object class="GtkButton" id="recovery_key_generate_button"> |
609 | + <property name="visible">True</property> |
610 | + <property name="can_focus">True</property> |
611 | + <property name="receives_default">True</property> |
612 | + <property name="image">image_generate_key</property> |
613 | + <signal name="clicked" handler="on_recovery_key_generate_button" swapped="no"/> |
614 | + </object> |
615 | + <packing> |
616 | + <property name="left_attach">1</property> |
617 | + <property name="top_attach">0</property> |
618 | + </packing> |
619 | + </child> |
620 | + <child> |
621 | + <object class="GtkEntry" id="verified_recovery_key"> |
622 | <property name="visible">True</property> |
623 | <property name="can_focus">True</property> |
624 | - <property name="hexpand">True</property> |
625 | <property name="visibility">False</property> |
626 | <property name="invisible_char">●</property> |
627 | <property name="activates_default">True</property> |
628 | - <property name="width_chars">20</property> |
629 | - <property name="invisible_char_set">True</property> |
630 | + <property name="width_chars">36</property> |
631 | + <property name="primary_icon_activatable">False</property> |
632 | + <property name="primary_icon_sensitive">False</property> |
633 | <signal name="changed" handler="info_loop" swapped="no"/> |
634 | </object> |
635 | <packing> |
636 | <property name="left_attach">0</property> |
637 | <property name="top_attach">1</property> |
638 | - <property name="width">1</property> |
639 | - <property name="height">1</property> |
640 | </packing> |
641 | </child> |
642 | <child> |
643 | - <object class="GtkNotebook" id="password_strength"> |
644 | + <object class="GtkNotebook" id="recovery_strength"> |
645 | <property name="visible">True</property> |
646 | <property name="can_focus">False</property> |
647 | + <property name="hexpand">True</property> |
648 | <property name="show_tabs">False</property> |
649 | <property name="show_border">False</property> |
650 | <child> |
651 | - <object class="GtkFixed" id="empty"> |
652 | + <object class="GtkFixed" id="recovery/empty"> |
653 | <property name="visible">True</property> |
654 | <property name="can_focus">False</property> |
655 | </object> |
656 | @@ -206,11 +496,11 @@ |
657 | <placeholder/> |
658 | </child> |
659 | <child> |
660 | - <object class="GtkLabel" id="password/too_short"> |
661 | + <object class="GtkLabel" id="recovery_too_short"> |
662 | <property name="visible">True</property> |
663 | <property name="can_focus">False</property> |
664 | - <property name="xalign">0</property> |
665 | <property name="label" translatable="yes">Short password</property> |
666 | + <property name="xalign">0</property> |
667 | <attributes> |
668 | <attribute name="scale" value="0.83333333333329995"/> |
669 | <attribute name="foreground" value="#8b8b00000000"/> |
670 | @@ -224,11 +514,11 @@ |
671 | <placeholder/> |
672 | </child> |
673 | <child> |
674 | - <object class="GtkLabel" id="password/weak"> |
675 | + <object class="GtkLabel" id="recovery_weak"> |
676 | <property name="visible">True</property> |
677 | <property name="can_focus">False</property> |
678 | - <property name="xalign">0</property> |
679 | <property name="label" translatable="yes">Weak password</property> |
680 | + <property name="xalign">0</property> |
681 | <attributes> |
682 | <attribute name="scale" value="0.83333333333329995"/> |
683 | <attribute name="foreground" value="#8b8b00000000"/> |
684 | @@ -242,11 +532,11 @@ |
685 | <placeholder/> |
686 | </child> |
687 | <child> |
688 | - <object class="GtkLabel" id="password/fair"> |
689 | + <object class="GtkLabel" id="recovery_fair"> |
690 | <property name="visible">True</property> |
691 | <property name="can_focus">False</property> |
692 | - <property name="xalign">0</property> |
693 | <property name="label" translatable="yes">Fair password</property> |
694 | + <property name="xalign">0</property> |
695 | <attributes> |
696 | <attribute name="scale" value="0.83333333333329995"/> |
697 | <attribute name="foreground" value="#ffff8c8c0000"/> |
698 | @@ -260,11 +550,11 @@ |
699 | <placeholder/> |
700 | </child> |
701 | <child> |
702 | - <object class="GtkLabel" id="password/good"> |
703 | + <object class="GtkLabel" id="recovery_good"> |
704 | <property name="visible">True</property> |
705 | <property name="can_focus">False</property> |
706 | - <property name="xalign">0</property> |
707 | <property name="label" translatable="yes">Good password</property> |
708 | + <property name="xalign">0</property> |
709 | <attributes> |
710 | <attribute name="scale" value="0.83333333333329995"/> |
711 | <attribute name="foreground" value="#000064640000"/> |
712 | @@ -278,11 +568,11 @@ |
713 | <placeholder/> |
714 | </child> |
715 | <child> |
716 | - <object class="GtkLabel" id="password/strong"> |
717 | + <object class="GtkLabel" id="recovery_strong"> |
718 | <property name="visible">True</property> |
719 | <property name="can_focus">False</property> |
720 | - <property name="xalign">0</property> |
721 | <property name="label" translatable="yes">Strong password</property> |
722 | + <property name="xalign">0</property> |
723 | <attributes> |
724 | <attribute name="scale" value="0.83333333333329995"/> |
725 | <attribute name="foreground" value="#000064640000"/> |
726 | @@ -297,20 +587,19 @@ |
727 | </child> |
728 | </object> |
729 | <packing> |
730 | - <property name="left_attach">1</property> |
731 | + <property name="left_attach">2</property> |
732 | <property name="top_attach">0</property> |
733 | - <property name="width">1</property> |
734 | - <property name="height">1</property> |
735 | </packing> |
736 | </child> |
737 | <child> |
738 | - <object class="GtkNotebook" id="password_match"> |
739 | + <object class="GtkNotebook" id="recovery_match"> |
740 | <property name="visible">True</property> |
741 | <property name="can_focus">False</property> |
742 | + <property name="hexpand">True</property> |
743 | <property name="show_tabs">False</property> |
744 | <property name="show_border">False</property> |
745 | <child> |
746 | - <object class="GtkFixed" id="empty2"> |
747 | + <object class="GtkFixed" id="recovery_empty2"> |
748 | <property name="visible">True</property> |
749 | <property name="can_focus">False</property> |
750 | </object> |
751 | @@ -319,11 +608,12 @@ |
752 | <placeholder/> |
753 | </child> |
754 | <child> |
755 | - <object class="GtkLabel" id="password_mismatch"> |
756 | + <object class="GtkLabel" id="recovery_mismatch"> |
757 | <property name="visible">True</property> |
758 | <property name="can_focus">False</property> |
759 | - <property name="xalign">0</property> |
760 | <property name="label" translatable="yes">Mismatch</property> |
761 | + <property name="wrap">True</property> |
762 | + <property name="xalign">0</property> |
763 | <attributes> |
764 | <attribute name="scale" value="0.83333333333329995"/> |
765 | <attribute name="foreground" value="#8b8b00000000"/> |
766 | @@ -334,7 +624,7 @@ |
767 | </packing> |
768 | </child> |
769 | <child> |
770 | - <object class="GtkImage" id="password_ok"> |
771 | + <object class="GtkImage" id="recovery_ok"> |
772 | <property name="visible">True</property> |
773 | <property name="can_focus">False</property> |
774 | <property name="xalign">0</property> |
775 | @@ -349,18 +639,78 @@ |
776 | </child> |
777 | </object> |
778 | <packing> |
779 | - <property name="left_attach">1</property> |
780 | + <property name="left_attach">2</property> |
781 | <property name="top_attach">1</property> |
782 | - <property name="width">1</property> |
783 | - <property name="height">1</property> |
784 | </packing> |
785 | </child> |
786 | + <child> |
787 | + <object class="GtkLabel" id="recovery_key_location"> |
788 | + <property name="visible">True</property> |
789 | + <property name="can_focus">False</property> |
790 | + <property name="label">/home/ubuntu/recovery.key</property> |
791 | + <property name="ellipsize">end</property> |
792 | + <property name="width_chars">38</property> |
793 | + <property name="single_line_mode">True</property> |
794 | + <property name="max_width_chars">38</property> |
795 | + <property name="track_visited_links">False</property> |
796 | + <property name="xalign">0.05000000074505806</property> |
797 | + </object> |
798 | + <packing> |
799 | + <property name="left_attach">0</property> |
800 | + <property name="top_attach">2</property> |
801 | + </packing> |
802 | + </child> |
803 | + <child> |
804 | + <object class="GtkButton" id="recovery_key_button"> |
805 | + <property name="visible">True</property> |
806 | + <property name="can_focus">True</property> |
807 | + <property name="receives_default">True</property> |
808 | + <property name="image">image_file</property> |
809 | + <property name="always_show_image">True</property> |
810 | + <signal name="clicked" handler="on_recovery_key_button_clicked" swapped="no"/> |
811 | + </object> |
812 | + <packing> |
813 | + <property name="left_attach">1</property> |
814 | + <property name="top_attach">2</property> |
815 | + </packing> |
816 | + </child> |
817 | + <child> |
818 | + <object class="GtkLabel" id="recovery_key_location_warning"> |
819 | + <property name="visible">False</property> |
820 | + <property name="can_focus">False</property> |
821 | + <property name="wrap">True</property> |
822 | + <property name="width_chars">32</property> |
823 | + <property name="max_width_chars">32</property> |
824 | + <property name="track_visited_links">False</property> |
825 | + </object> |
826 | + <packing> |
827 | + <property name="left_attach">2</property> |
828 | + <property name="top_attach">2</property> |
829 | + </packing> |
830 | + </child> |
831 | + <child> |
832 | + <placeholder/> |
833 | + </child> |
834 | </object> |
835 | <packing> |
836 | <property name="left_attach">1</property> |
837 | - <property name="top_attach">2</property> |
838 | - <property name="width">1</property> |
839 | - <property name="height">2</property> |
840 | + <property name="top_attach">5</property> |
841 | + <property name="height">3</property> |
842 | + </packing> |
843 | + </child> |
844 | + <child> |
845 | + <object class="GtkLabel" id="crypto_extra_time"> |
846 | + <property name="visible">True</property> |
847 | + <property name="can_focus">False</property> |
848 | + <property name="margin_left">24</property> |
849 | + <property name="label" translatable="yes"><span weight="light" size="small">The installation may take much longer.</span></property> |
850 | + <property name="use_markup">True</property> |
851 | + <property name="single_line_mode">True</property> |
852 | + <property name="xalign">0</property> |
853 | + </object> |
854 | + <packing> |
855 | + <property name="left_attach">1</property> |
856 | + <property name="top_attach">10</property> |
857 | </packing> |
858 | </child> |
859 | <child> |
860 | diff --git a/scripts/plugininstall.py b/scripts/plugininstall.py |
861 | index f7d5a7f..cd46373 100755 |
862 | --- a/scripts/plugininstall.py |
863 | +++ b/scripts/plugininstall.py |
864 | @@ -234,6 +234,7 @@ class Install(install_misc.InstallBase): |
865 | self.next_region() |
866 | self.db.progress('INFO', 'ubiquity/install/bootloader') |
867 | self.copy_mok() |
868 | + self.configure_recovery_key() |
869 | self.configure_bootloader() |
870 | |
871 | self.next_region(size=4) |
872 | @@ -899,6 +900,56 @@ class Install(install_misc.InstallBase): |
873 | continue |
874 | os.symlink(linksrc, linkdst) |
875 | |
876 | + def configure_recovery_key(self): |
877 | + crypto_key = self.db.get('ubiquity/crypto_key') |
878 | + recovery_key = self.db.get('ubiquity/recovery_key') |
879 | + if not crypto_key or not recovery_key: |
880 | + self.clean_crypto_keys() |
881 | + return |
882 | + |
883 | + debconf_disk = self.db.get('partman-auto/select_disk') |
884 | + disk = debconf_disk.split('/')[-1].replace('=', '/') |
885 | + |
886 | + args = ['lsblk', '-lp', '-oNAME,FSTYPE', disk] |
887 | + lsblk_out = subprocess.check_output(args).decode(sys.stdout.encoding) |
888 | + for line in lsblk_out.splitlines(): |
889 | + if 'crypto_LUKS' not in line: |
890 | + continue |
891 | + dev = line.split()[0] |
892 | + |
893 | + if not dev: |
894 | + syslog.syslog(syslog.LOG_ERR, ' '.join(args)) |
895 | + syslog.syslog(syslog.LOG_ERR, 'determining crypto device failed. Output: %s' % lsblk_out) |
896 | + self.clean_crypto_keys() |
897 | + self.db.input('critical', 'ubiquity/install/broken_luks_add_key') |
898 | + self.db.go() |
899 | + return |
900 | + syslog.syslog(' '.join(args)) |
901 | + |
902 | + key_args = "%s\n%s" % (crypto_key, recovery_key) |
903 | + try: |
904 | + log_args = ['log-output', '-t', 'ubiquity'] |
905 | + log_args.extend(['cryptsetup', 'luksAddKey', dev]) |
906 | + p = subprocess.run(log_args, input=key_args, encoding="utf-8") |
907 | + except subprocess.CalledProcessError as e: |
908 | + syslog.syslog(syslog.LOG_ERR, ' '.join(log_args)) |
909 | + syslog.syslog(syslog.LOG_ERR, "cryptsetup failed(%s): %s" % (e.returncode, e.output)) |
910 | + return |
911 | + finally: |
912 | + self.clean_crypto_keys() |
913 | + |
914 | + if p.returncode != 0: |
915 | + syslog.syslog(syslog.LOG_ERR, ' '.join(log_args)) |
916 | + self.db.input('critical', 'ubiquity/install/broken_luks_add_key') |
917 | + self.db.go() |
918 | + return |
919 | + |
920 | + syslog.syslog(' '.join(log_args)) |
921 | + |
922 | + def clean_crypto_keys(self): |
923 | + self.db.set('ubiquity/crypto_key', '') |
924 | + self.db.set('ubiquity/recovery_key', '') |
925 | + |
926 | def configure_bootloader(self): |
927 | """Configure and install the boot loader.""" |
928 | if 'UBIQUITY_OEM_USER_CONFIG' in os.environ: |
929 | diff --git a/tests/test_gtkui.py b/tests/test_gtkui.py |
930 | index 60cbfd3..a68395e 100644 |
931 | --- a/tests/test_gtkui.py |
932 | +++ b/tests/test_gtkui.py |
933 | @@ -73,7 +73,7 @@ class TestFrontend(unittest.TestCase): |
934 | # Anything smaller will need to use Alt+Ctrl+Pgd/Right |
935 | # Scrollbars anyone? |
936 | # self.assertLessEqual(alloc.width, 640, page.module.NAME) # fixme |
937 | - self.assertLessEqual(alloc.height, 556, page.module.NAME) |
938 | + self.assertLessEqual(alloc.height, 744, page.module.NAME) # 768 - 24px (top panel) |
939 | if page.module.NAME == 'partman': |
940 | ui.allow_change_step(False) |
941 | |
942 | @@ -123,6 +123,7 @@ class TestFrontend(unittest.TestCase): |
943 | # setup page. |
944 | 'password_strength', 'hostname_error_label', |
945 | 'password_error_label', 'username_error_label', |
946 | + 'recovery_strength', |
947 | # Pulled straight from debconf into the UI on progress. |
948 | 'install_progress_text', |
949 | # Contains just the traceback. |
950 | @@ -132,6 +133,7 @@ class TestFrontend(unittest.TestCase): |
951 | 'page_title', |
952 | # To be calculated and set |
953 | 'partition_lvm_status', |
954 | + 'recovery_key_location', |
955 | # These are "placeholders" for debconfs impromptu notices |
956 | 'ubi_question_dialog', 'question_label', |
957 | # Calculated error string |
958 | diff --git a/ubiquity/components/plugininstall.py b/ubiquity/components/plugininstall.py |
959 | index dcb04d6..6aa1a90 100644 |
960 | --- a/ubiquity/components/plugininstall.py |
961 | +++ b/ubiquity/components/plugininstall.py |
962 | @@ -67,6 +67,8 @@ class Install(FilteredCommand): |
963 | fatal = False |
964 | elif question == 'ubiquity/install/broken_active_directory': |
965 | fatal = False |
966 | + elif question == 'ubiquity/install/broken_luks_add_key': |
967 | + fatal = False |
968 | else: |
969 | fatal = True |
970 | self.frontend.error_dialog(self.description(question), |
971 | diff --git a/ubiquity/misc.py b/ubiquity/misc.py |
972 | index e9c2a2b..5fcaf19 100644 |
973 | --- a/ubiquity/misc.py |
974 | +++ b/ubiquity/misc.py |
975 | @@ -9,6 +9,7 @@ import re |
976 | import shutil |
977 | import subprocess |
978 | import syslog |
979 | +import json |
980 | |
981 | from ubiquity import osextras |
982 | from gi.repository import Gio, GLib, GObject |
983 | @@ -150,6 +151,14 @@ def raise_privileges(func): |
984 | return helper |
985 | |
986 | |
987 | +def get_live_user_home(): |
988 | + """Returns live user home directory, even if executed under SUDO or PKEXEC""" |
989 | + uid = os.environ.get('PKEXEC_UID', os.environ.get('SUDO_UID')) |
990 | + if uid is not None: |
991 | + return pwd.getpwuid(int(uid)).pw_dir |
992 | + return os.getenv('HOME', '') |
993 | + |
994 | + |
995 | @raise_privileges |
996 | def grub_options(): |
997 | """ Generates a list of suitable targets for grub-installer |
998 | @@ -957,6 +966,34 @@ def launch_uri(uri): |
999 | preexec_fn=drop_all_privileges) |
1000 | |
1001 | |
1002 | +def is_removable_device(path): |
1003 | + """Returns True if path is on a removable device""" |
1004 | + lsblk_output = "" |
1005 | + cmd = "lsblk -J -o MOUNTPOINT,PATH,RM" |
1006 | + |
1007 | + # Find mount point of path |
1008 | + mp = path |
1009 | + while not os.path.ismount(mp): |
1010 | + mp = os.path.dirname(mp) |
1011 | + |
1012 | + # In ubiquity environment / is the installation media |
1013 | + if mp == "/": |
1014 | + return True |
1015 | + |
1016 | + # Then search if the corresponding device is removable |
1017 | + try: |
1018 | + lsblk_output = subprocess.check_output(cmd.split()) |
1019 | + except subprocess.CalledProcessError: |
1020 | + syslog.syslog(syslog.LOG_ERR, "Unable to determine if %s is on a removable device" % path) |
1021 | + return False |
1022 | + |
1023 | + devices = json.loads(lsblk_output) |
1024 | + for entry in devices["blockdevices"]: |
1025 | + if entry["mountpoint"] == mp and entry["rm"]: |
1026 | + return True |
1027 | + return False |
1028 | + |
1029 | + |
1030 | class SystemdUnitWatcher: |
1031 | def __init__(self, unit, cb): |
1032 | # try connecting to the bus |
1033 | diff --git a/ubiquity/plugins/ubi-partman.py b/ubiquity/plugins/ubi-partman.py |
1034 | index 68a1140..83cab1b 100644 |
1035 | --- a/ubiquity/plugins/ubi-partman.py |
1036 | +++ b/ubiquity/plugins/ubi-partman.py |
1037 | @@ -110,6 +110,9 @@ class PageBase(plugin.PluginUI): |
1038 | def get_crypto_keys(self): |
1039 | pass |
1040 | |
1041 | + def get_recovery_keys(self): |
1042 | + pass |
1043 | + |
1044 | |
1045 | class PageGtk(PageBase): |
1046 | plugin_title = 'ubiquity/text/part_auto_heading_label' |
1047 | @@ -145,7 +148,7 @@ class PageGtk(PageBase): |
1048 | for wdg in all_widgets: |
1049 | setattr(self, wdg, builder.get_object(wdg)) |
1050 | |
1051 | - # Crypto page |
1052 | + # Crypto page, used for both primary and recovery keys |
1053 | self.password_strength_pages = { |
1054 | 'empty': 0, |
1055 | 'too_short': 1, |
1056 | @@ -210,6 +213,14 @@ class PageGtk(PageBase): |
1057 | # Define a list to save grub imformation |
1058 | self.grub_options = [] |
1059 | |
1060 | + default_recovery_key_location = os.path.join(misc.get_live_user_home(), 'recovery.key') |
1061 | + self.recovery_key_location.set_text(default_recovery_key_location) |
1062 | + self.recovery_key.set_visibility(False) |
1063 | + self.recovery_key.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'view-reveal-symbolic') |
1064 | + self.verified_recovery_key.set_visibility(False) |
1065 | + self.recovery_key_location_warning.set_visible(False) |
1066 | + self.enable_recovery_key(False) |
1067 | + |
1068 | def on_link_clicked(self, widget, uri): |
1069 | misc.launch_uri(uri) |
1070 | |
1071 | @@ -275,7 +286,13 @@ class PageGtk(PageBase): |
1072 | return |
1073 | crypto_widgets += [ |
1074 | ('verified_crypto_label', 'crypto_label', 'bottom', 1, 1), |
1075 | - ('crypto_warning', 'verified_crypto_label', 'bottom', 2, 1), |
1076 | + ('recovery_key_enable', 'verified_crypto_label', 'bottom', 1, 1), |
1077 | + ('recovery_key_warning', 'recovery_key_enable', 'right', 1, 1), |
1078 | + ('recovery_grid', 'recovery_key_warning', 'bottom', 1, 3), |
1079 | + ('recovery_key_label', 'recovery_grid', 'left', 1, 1), |
1080 | + ('verified_recovery_key_label', 'recovery_key_label', 'bottom', 1, 1), |
1081 | + ('recovery_key_location_label', 'verified_recovery_key_label', 'bottom', 1, 1), |
1082 | + ('crypto_warning', 'recovery_key_location_label', 'bottom', 2, 1), |
1083 | ('crypto_extra_label', 'crypto_warning', 'bottom', 1, 1), |
1084 | ('crypto_overwrite_space', 'crypto_extra_label', 'right', 1, 1), |
1085 | ('crypto_extra_time', 'crypto_overwrite_space', 'bottom', 1, 1)] |
1086 | @@ -291,6 +308,14 @@ class PageGtk(PageBase): |
1087 | width, height) |
1088 | widget.show() |
1089 | |
1090 | + def generate_recovery_key(self): |
1091 | + if not self.recovery_key_enable.get_active(): |
1092 | + return |
1093 | + from secrets import randbelow |
1094 | + key = str(randbelow(10**48)).zfill(48) |
1095 | + self.recovery_key.set_text(key) |
1096 | + self.verified_recovery_key.set_text(key) |
1097 | + |
1098 | def on_advanced_features_clicked(self, widget): |
1099 | from gi.repository import Gtk |
1100 | |
1101 | @@ -329,6 +354,77 @@ class PageGtk(PageBase): |
1102 | selected.set_active(True) |
1103 | self.use_crypto.set_active(crypto_selected) |
1104 | |
1105 | + def on_recovery_key_button_clicked(self, widget): |
1106 | + from gi.repository import Gtk |
1107 | + label = self.controller.get_string('recovery_key_filename') |
1108 | + |
1109 | + # Set HOME to the live session user's home directory so the |
1110 | + # filechooser dialog opens at the right location. |
1111 | + orig_home = os.getenv('HOME') |
1112 | + live_user_home = misc.get_live_user_home() |
1113 | + if live_user_home: |
1114 | + os.environ['HOME'] = live_user_home |
1115 | + save_recovery_dialog = Gtk.FileChooserDialog(label, widget.get_toplevel(), |
1116 | + Gtk.FileChooserAction.SAVE, |
1117 | + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, |
1118 | + Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT)) |
1119 | + save_recovery_dialog.set_do_overwrite_confirmation(True) |
1120 | + save_recovery_dialog.set_modal(True) |
1121 | + save_recovery_dialog.set_current_name(os.path.basename(self.recovery_key_location.get_text())) |
1122 | + save_recovery_dialog.set_filename(self.recovery_key_location.get_text()) |
1123 | + save_recovery_dialog.connect("response", self.on_save_recovery_selected) |
1124 | + save_recovery_dialog.remove_shortcut_folder('/root') |
1125 | + save_recovery_dialog.show() |
1126 | + if orig_home is not None: |
1127 | + os.environ['HOME'] = orig_home |
1128 | + else: |
1129 | + del os.environ['HOME'] |
1130 | + |
1131 | + def on_save_recovery_selected(self, dialog, response_id): |
1132 | + from gi.repository import Gtk |
1133 | + if response_id == Gtk.ResponseType.ACCEPT: |
1134 | + self.recovery_key_location.set_text(dialog.get_filename()) |
1135 | + dialog.destroy() |
1136 | + |
1137 | + is_removable = misc.is_removable_device(self.recovery_key_location.get_text()) |
1138 | + self.recovery_key_location_warning.set_visible(not is_removable) |
1139 | + |
1140 | + def on_recovery_key_generate_button(self, widget): |
1141 | + self.generate_recovery_key() |
1142 | + |
1143 | + def on_recovery_key_toggle_visibility(self, widget, icon_pos, event): |
1144 | + from gi.repository import Gtk |
1145 | + visibility = self.recovery_key.get_visibility() |
1146 | + self.recovery_key.set_visibility(not visibility) |
1147 | + self.verified_recovery_key.set_visibility(not visibility) |
1148 | + self.recovery_key.set_icon_from_icon_name( |
1149 | + Gtk.EntryIconPosition.SECONDARY, ('view-conceal-symbolic', 'view-reveal-symbolic')[visibility]) |
1150 | + |
1151 | + def on_recovery_key_enable_toggled(self, widget): |
1152 | + self.enable_recovery_key(widget.get_active()) |
1153 | + |
1154 | + def enable_recovery_key(self, enable=False): |
1155 | + self.recovery_key_warning.set_sensitive(enable) |
1156 | + self.recovery_key_label.set_sensitive(enable) |
1157 | + self.recovery_key.set_sensitive(enable) |
1158 | + self.recovery_key_generate_button.set_sensitive(enable) |
1159 | + self.verified_recovery_key_label.set_sensitive(enable) |
1160 | + self.verified_recovery_key.set_sensitive(enable) |
1161 | + self.recovery_key_location_label.set_sensitive(enable) |
1162 | + self.recovery_key_location_warning.set_sensitive(enable) |
1163 | + self.recovery_key_location.set_sensitive(enable) |
1164 | + self.recovery_key_button.set_sensitive(enable) |
1165 | + |
1166 | + if enable: |
1167 | + self.generate_recovery_key() |
1168 | + else: |
1169 | + self.recovery_key.set_text("") |
1170 | + self.verified_recovery_key.set_text("") |
1171 | + self.recovery_strength.set_current_page( |
1172 | + self.password_strength_pages['empty']) |
1173 | + self.recovery_match.set_current_page( |
1174 | + self.password_match_pages['empty']) |
1175 | + |
1176 | def should_show_bitlocker_page(self): |
1177 | return ('bitlocker' in self.extra_options or |
1178 | os.environ.get('SHOW_BITLOCKER_UI', '0') == '1') |
1179 | @@ -436,6 +532,24 @@ class PageGtk(PageBase): |
1180 | self.plugin_is_install = True |
1181 | return True |
1182 | |
1183 | + recovery_key_location_path = self.recovery_key_location.get_text() |
1184 | + if recovery_key_location_path: |
1185 | + try: |
1186 | + with open(recovery_key_location_path, "w") as f: |
1187 | + f.write(self.recovery_key.get_text()) |
1188 | + except Exception as exc: |
1189 | + save_recovery_key_info = 'ubiquity/text/save_recovery_key_info' |
1190 | + msg = self.controller.get_string(save_recovery_key_info).replace('${ERRORMSG}', str(exc)) |
1191 | + |
1192 | + from gi.repository import Gtk |
1193 | + dialog = Gtk.MessageDialog( |
1194 | + self.current_page.get_toplevel(), Gtk.DialogFlags.MODAL, |
1195 | + Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, None) |
1196 | + dialog.set_markup(msg) |
1197 | + dialog.run() |
1198 | + dialog.destroy() |
1199 | + return True |
1200 | + |
1201 | # Return control to partman, which will call |
1202 | # get_autopartition_choice and start partitioninging the device. |
1203 | self.controller.switch_to_install_interface() |
1204 | @@ -1014,9 +1128,17 @@ class PageGtk(PageBase): |
1205 | self.partition_dialog_okbutton.set_sensitive(True) |
1206 | |
1207 | for widget in ['password_grid', 'crypto_label', 'crypto_warning', |
1208 | - 'verified_crypto_label', 'crypto_extra_label', |
1209 | - 'crypto_overwrite_space', 'crypto_extra_time']: |
1210 | + 'verified_crypto_label', |
1211 | + 'crypto_extra_label', |
1212 | + 'crypto_overwrite_space', 'crypto_extra_time', |
1213 | + 'recovery_key_enable', 'recovery_key_warning', |
1214 | + 'recovery_grid', |
1215 | + 'recovery_key_label', |
1216 | + 'verified_recovery_key_label', |
1217 | + 'recovery_key_location_label']: |
1218 | getattr(getattr(self, widget), action)() |
1219 | + is_removable = misc.is_removable_device(self.recovery_key_location.get_text()) |
1220 | + self.recovery_key_location_warning.set_visible(not is_removable) |
1221 | |
1222 | @plugin.only_this_page |
1223 | def partman_dialog(self, devpart, partition, create=True): |
1224 | @@ -1553,6 +1675,28 @@ class PageGtk(PageBase): |
1225 | self.password_strength.set_current_page( |
1226 | self.password_strength_pages['empty']) |
1227 | |
1228 | + # Recovery key |
1229 | + recovery = self.recovery_key.get_text() |
1230 | + vrecovery = self.verified_recovery_key.get_text() |
1231 | + |
1232 | + if recovery: |
1233 | + if recovery != vrecovery: |
1234 | + # It's okay to reuse complete since it'll stay False if it's |
1235 | + # already false from previous check and switch to False |
1236 | + # otherwise. |
1237 | + # In either case, we don't want to proceed if the password or |
1238 | + # the recovery are invalid. |
1239 | + complete = False |
1240 | + self.recovery_match.set_current_page( |
1241 | + self.password_match_pages['mismatch']) |
1242 | + else: |
1243 | + self.recovery_match.set_current_page( |
1244 | + self.password_match_pages['ok']) |
1245 | + |
1246 | + txt = validation.human_password_strength(recovery)[0] |
1247 | + self.recovery_strength.set_current_page( |
1248 | + self.password_strength_pages[txt]) |
1249 | + |
1250 | self.controller.allow_go_forward(complete) |
1251 | self.partition_dialog_okbutton.set_sensitive(complete) |
1252 | return complete |
1253 | @@ -1573,6 +1717,12 @@ class PageGtk(PageBase): |
1254 | else: |
1255 | return False |
1256 | |
1257 | + def get_recovery_keys(self): |
1258 | + if self.info_loop(None): |
1259 | + return self.recovery_key.get_text() |
1260 | + else: |
1261 | + return False |
1262 | + |
1263 | |
1264 | class PageKde(PageBase): |
1265 | plugin_breadcrumb = 'ubiquity/text/breadcrumb_partition' |
1266 | @@ -3234,6 +3384,8 @@ class Page(plugin.Plugin): |
1267 | |
1268 | if do_preseed: |
1269 | self.preseed(question, self.ui.get_crypto_keys()) |
1270 | + self.preseed('ubiquity/crypto_key', self.ui.get_crypto_keys()) |
1271 | + self.preseed('ubiquity/recovery_key', self.ui.get_recovery_keys()) |
1272 | return True |
1273 | |
1274 | elif question == 'partman-crypto/mainmenu': |
1275 | diff --git a/ubiquity/validation.py b/ubiquity/validation.py |
1276 | index 9a08b4e..a782acc 100644 |
1277 | --- a/ubiquity/validation.py |
1278 | +++ b/ubiquity/validation.py |
1279 | @@ -116,6 +116,12 @@ def password_strength(password): |
1280 | strength = 1 |
1281 | if strength < 0: |
1282 | strength = 0 |
1283 | + |
1284 | + # Recovery keys are 48 digits number and cannot be considered "fair" |
1285 | + # so set it a level higher |
1286 | + if len(password) >= 48 and strength < 0.75: |
1287 | + strength = 0.8 |
1288 | + |
1289 | return strength |
1290 | |
1291 |
LGTM with the additional set_visible(False).