Just look at all those + lines:
pyanaconda/storage/__init__.py | 24 +++- pyanaconda/storage/devicetree.py | 18 ++- pyanaconda/ui/gui/spokes/custom.glade | 130 ++++++++++++++- pyanaconda/ui/gui/spokes/custom.py | 230 +++++++++++++++++++++---- pyanaconda/ui/gui/spokes/lib/accordion.py | 4 + pyanaconda/ui/gui/spokes/lib/passphrase.glade | 230 +++++++++++++++++++++++++ pyanaconda/ui/gui/spokes/lib/passphrase.py | 177 +++++++++++++++++++ pyanaconda/ui/gui/spokes/storage.glade | 30 +++- pyanaconda/ui/gui/spokes/storage.py | 24 +++- 9 files changed, 818 insertions(+), 49 deletions(-)
--- pyanaconda/storage/__init__.py | 24 ++++++++++++++++++++++-- 1 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index 4cfbc80..0a7a8e5 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -1865,7 +1865,7 @@ class Storage(object): # set up new members as needed to accommodate the device new_members = [] for disk in add_disks: - if factory.encrypted: + if factory.encrypted and factory.encrypt_members: luks_format = factory.member_format member_format = "luks" else: @@ -1879,7 +1879,7 @@ class Storage(object): continue
self.createDevice(member) - if factory.encrypted: + if factory.encrypted and factory.encrypt_members: fmt = getFormat(luks_format) member = LUKSDevice("luks-%s" % member.name, parents=[member], format=fmt) @@ -2104,6 +2104,14 @@ class Storage(object): raise(e) elif factory.new_device_attr: log.debug("creating new device") + if factory.encrypted and factory.encrypt_leaves: + luks_fmt_type = fstype + luks_fmt_args = fmt_args + luks_mountpoint = mountpoint + fstype = "luks" + mountpoint = None + fmt_args = {} + try: device = factory.new_device(parents=parents, size=size, @@ -2154,6 +2162,14 @@ class Storage(object): self.__cleanUpMemberDevices(members) raise
+ if factory.encrypted and factory.encrypt_leaves: + fmt = getFormat(luks_fmt_type, + mountpoint=luks_mountpoint, + **luks_fmt_args) + luks_device = LUKSDevice("luks-" + device.name, + parents=[device], format=fmt) + self.createDevice(luks_device) + def copy(self): new = copy.deepcopy(self) # go through and re-get partedPartitions from the disks since they @@ -3126,6 +3142,8 @@ class DeviceFactory(object): new_container_attr = None # name of Storage method to create a container new_device_attr = None # name of Storage method to create a device container_list_attr = None # name of Storage attribute to list containers + encrypt_members = False + encrypt_leaves = True
def __init__(self, storage, size, disks, raid_level, encrypted): self.storage = storage # the Storage instance @@ -3219,6 +3237,8 @@ class BTRFSFactory(DeviceFactory): new_container_attr = "newBTRFS" new_device_attr = "newBTRFSSubVolume" container_list_attr = "btrfsVolumes" + encrypt_members = True + encrypt_leaves = False
def __init__(self, storage, size, disks, raid_level, encrypted): super(BTRFSFactory, self).__init__(storage, size, disks, raid_level,
This allows us to get/check/set passphrase and then call populate to continue populating the devicetree to pick up devices descended from the newly decrypted device. --- pyanaconda/storage/devicetree.py | 18 ++++++++++++------ 1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py index e6a3daa..f520c13 100644 --- a/pyanaconda/storage/devicetree.py +++ b/pyanaconda/storage/devicetree.py @@ -1150,7 +1150,9 @@ class DeviceTree(object): # look up or create the mapped device if not self.getDeviceByName(device.format.mapName): passphrase = self.__luksDevs.get(device.format.uuid) - if passphrase: + if device.format.configured: + pass + elif passphrase: device.format.passphrase = passphrase elif device.format.uuid in self.__luksDevs: log.info("skipping previously-skipped luks device %s" @@ -1162,11 +1164,15 @@ class DeviceTree(object): # this makes device.configured return True device.format.passphrase = 'yabbadabbadoo' else: - passphrase = getLUKSPassphrase(None, - device, - self.__passphrases) - if passphrase and passphrase not in self.__passphrases: - self.__passphrases.append(passphrase) + # Try each known passphrase. + for passphrase in self.__luksDevs.values(): + device.format.passphrase = passphrase + try: + device.format.setup() + except CryptoError: + device.format.passphrase = None + else: + break
luks_device = LUKSDevice(device.format.mapName, parents=[device],
--- pyanaconda/ui/gui/spokes/lib/accordion.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/lib/accordion.py b/pyanaconda/ui/gui/spokes/lib/accordion.py index ed4566c..a5812c2 100644 --- a/pyanaconda/ui/gui/spokes/lib/accordion.py +++ b/pyanaconda/ui/gui/spokes/lib/accordion.py @@ -69,6 +69,10 @@ class Accordion(Gtk.Box): def allPages(self): return [e.get_child() for e in self._expanders]
+ @property + def allSelectors(self): + return [s for p in self.allPages for s in getattr(p, "_members", [])] + def currentPage(self): for e in self._expanders: if e.get_expanded():
--- pyanaconda/ui/gui/spokes/lib/passphrase.glade | 230 +++++++++++++++++++++++++ pyanaconda/ui/gui/spokes/lib/passphrase.py | 177 +++++++++++++++++++ 2 files changed, 407 insertions(+), 0 deletions(-) create mode 100644 pyanaconda/ui/gui/spokes/lib/passphrase.glade create mode 100644 pyanaconda/ui/gui/spokes/lib/passphrase.py
diff --git a/pyanaconda/ui/gui/spokes/lib/passphrase.glade b/pyanaconda/ui/gui/spokes/lib/passphrase.glade new file mode 100644 index 0000000..8113374 --- /dev/null +++ b/pyanaconda/ui/gui/spokes/lib/passphrase.glade @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <object class="GtkDialog" id="passphrase_dialog"> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type_hint">dialog</property> + <property name="decorated">False</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox3"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="passphrase_dialog_title_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="ypad">1</property> + <property name="label" translatable="yes">DISK ENCRYPTION PASSPHRASE</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area3"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="passphrase_cancel_button"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="passphrase_save_button"> + <property name="label" translatable="yes">Save Passphrase</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_save_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="passphrase_description_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">You have chosen to encrypt some of your data. You will need to create a passphrase that you will use to access your data when you start your computer.</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="passphrase_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + <child> + <object class="GtkLabel" id="passphrase_entry_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Passphrase:</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="passphrase_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + <property name="width_chars">32</property> + <signal name="changed" handler="on_passphrase_changed" swapped="no"/> + <signal name="focus-out-event" handler="on_passphrase_editing_done" swapped="no"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="confirm_entry_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Confirm:</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="confirm_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + <property name="width_chars">32</property> + <signal name="changed" handler="on_confirm_changed" swapped="no"/> + <signal name="focus-out-event" handler="on_confirm_editing_done" swapped="no"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="strength_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkLabel" id="strength_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Weak</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox" id="warning_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-dialog-warning</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="passphrase_warning_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">keymap warning label</property> + <property name="use_markup">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">passphrase_cancel_button</action-widget> + <action-widget response="1">passphrase_save_button</action-widget> + </action-widgets> + </object> +</interface> diff --git a/pyanaconda/ui/gui/spokes/lib/passphrase.py b/pyanaconda/ui/gui/spokes/lib/passphrase.py new file mode 100644 index 0000000..453f13d --- /dev/null +++ b/pyanaconda/ui/gui/spokes/lib/passphrase.py @@ -0,0 +1,177 @@ +# Passphrase creation dialog +# +# Copyright (C) 2012 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +# Red Hat Author(s): David Lehman dlehman@redhat.com +# + +from gi.repository import Gtk +from gi.repository import Gdk + +import gettext +import pwquality + +from pyanaconda.ui.gui import GUIObject + +from pyanaconda import keyboard + +_ = lambda x: gettext.ldgettext("anaconda", x) +P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) + +__all__ = ["PassphraseDialog"] + +warning_label_template = _("Warning: You current keyboard layout is <b>%s</b>." + "If you change your keyboard layout, you may not be " + "able to decrypt your disks after install.") + +ERROR_WEAK = _("You have provided a weak passphrase: %s") +ERROR_NOT_MATCHING = _("Passphrases do not match.") + +class PassphraseDialog(GUIObject): + builderObjects = ["passphrase_dialog"] + mainWidgetName = "passphrase_dialog" + uiFile = "spokes/lib/passphrase.glade" + + def refresh(self): + super(GUIObject, self).refresh() + self._warning_label = self.builder.get_object("passphrase_warning_label") + + # disable input methods for the passphrase Entry widgets and make sure + # the focus change mask is enabled + self._passphrase_entry = self.builder.get_object("passphrase_entry") + self._passphrase_entry.set_property("im-module", "") + self._passphrase_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, "") + self._passphrase_entry.add_events(Gdk.EventMask.FOCUS_CHANGE_MASK) + self._confirm_entry = self.builder.get_object("confirm_entry") + self._confirm_entry.set_property("im-module", "") + self._confirm_entry.add_events(Gdk.EventMask.FOCUS_CHANGE_MASK) + + self._save_button = self.builder.get_object("passphrase_save_button") + + # add the passphrase strength meter + self._strength_bar = Gtk.LevelBar() + self._strength_bar.set_mode(Gtk.LevelBarMode.DISCRETE) + self._strength_bar.set_min_value(0) + self._strength_bar.set_max_value(4) + box = self.builder.get_object("strength_box") + box.pack_start(self._strength_bar, False, True, 0) + box.show_all() + self._strength_label = self.builder.get_object("strength_label") + + # set up passphrase quality checker + self._pwq = pwquality.PWQSettings() + self._pwq.read_config() + + # update the warning label with the currently selected keymap + xkl_wrapper = keyboard.XklWrapper.get_instance() + keymap = self.data.keyboard.keyboard + if not keymap and self.data.keyboard.layouts_list: + keymap = self.data.keyboard.layouts_list[0] + keymap_name = xkl_wrapper.name_to_show_str[keymap] + warning_label_text = warning_label_template % keymap_name + self._warning_label.set_markup(warning_label_text) + + # initialize with the previously set passphrase + self.passphrase = self.data.autopart.passphrase + + self._passphrase_entry.set_text(self.passphrase) + self._confirm_entry.set_text(self.passphrase) + + self._update_passphrase_strength() + + def run(self): + self.refresh() + rc = self.window.run() + self.window.destroy() + return rc + + def _update_passphrase_strength(self): + passphrase = self._passphrase_entry.get_text() + strength = 0 + self._pwq_error = "" + try: + strength = self._pwq.check(passphrase, None, None) + except pwquality.PWQError as (e, msg): + self._pwq_error = msg + + if strength < 50: + val = 1 + text = _("Weak") + elif strength < 75: + val = 2 + text = _("Fair") + elif strength < 90: + val = 3 + text = _("Good") + else: + val = 4 + text = _("Strong") + + self._strength_bar.set_value(val) + self._strength_label.set_text(text) + + def _set_entry_icon(self, entry, icon, msg): + entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, icon) + entry.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY, msg) + + def on_passphrase_changed(self, entry): + self._update_passphrase_strength() + if self._confirm_entry.get_text(): + self._confirm_entry.set_text("") + self._set_entry_icon(self._confirm_entry, "", "") + + if not self._pwq_error: + self._set_entry_icon(entry, "", "") + + self._save_button.set_sensitive(False) + self._confirm_entry.set_sensitive(False) + + def on_passphrase_editing_done(self, entry, *args): + sensitive = True + if self._pwq_error: + icon = "gtk-dialog-error" + msg = ERROR_WEAK % self._pwq_error + sensitive = False + self._set_entry_icon(entry, icon, msg) + + self._confirm_entry.set_sensitive(sensitive) + if sensitive: + self._confirm_entry.grab_focus() + + return True + + def on_confirm_changed(self, entry): + if not self._save_button.get_sensitive() and \ + entry.get_text() == self._passphrase_entry.get_text(): + self._save_button.set_sensitive(True) + self._set_entry_icon(entry, "", "") + + def on_confirm_editing_done(self, entry, *args): + passphrase = self._passphrase_entry.get_text() + confirm = self._confirm_entry.get_text() + if passphrase != confirm: + match = False + icon = "gtk-dialog-error" + msg = ERROR_NOT_MATCHING + self._set_entry_icon(entry, icon, msg) + self._save_button.set_sensitive(False) + else: + self._save_button.grab_focus() + + def on_save_clicked(self, button): + self.passphrase = self._passphrase_entry.get_text() +
On Thu, 2012-10-04 at 09:59 -0500, David Lehman wrote:
# update the warning label with the currently selected keymap
xkl_wrapper = keyboard.XklWrapper.get_instance()
keymap = self.data.keyboard.keyboard
if not keymap and self.data.keyboard.layouts_list:
keymap = self.data.keyboard.layouts_list[0]
keymap_name = xkl_wrapper.name_to_show_str[keymap]
warning_label_text = warning_label_template % keymap_name
self._warning_label.set_markup(warning_label_text)
As I've written in a reply to the question about my pykickstart changes, this won't work.
We need to tell user which layout he/she has currently selected in some dialogs.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- pyanaconda/keyboard.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py index fb3f7ef..6817a15 100755 --- a/pyanaconda/keyboard.py +++ b/pyanaconda/keyboard.py @@ -34,6 +34,8 @@ import os import re from pyanaconda import iutil
+from gi.repository import Xkl + import logging log = logging.getLogger("anaconda")
@@ -226,7 +228,7 @@ class XklWrapper(object): return XklWrapper._instance
def __init__(self): - from gi.repository import Xkl, GdkX11 + from gi.repository import GdkX11
#initialize Xkl-related stuff display = GdkX11.x11_get_default_xdisplay() @@ -311,6 +313,21 @@ class XklWrapper(object): #first layout (should exist for every language) return language_layouts[0].name
+ def get_current_layout_name(self): + """ + Get current activated X layout's name + + @return: current activated X layout's name (e.g. "Czech (qwerty)") + + """ + + self._engine.start_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE) + state = self._engine.get_current_state() + groups_names = self._engine.get_groups_names() + self._engine.stop_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE) + + return groups_names[state.group] + def add_layout(self, layout): """ Method that tries to add a given layout to the current X configuration.
On Fri, 2012-10-05 at 13:18 +0200, Vratislav Podzimek wrote:
We need to tell user which layout he/she has currently selected in some dialogs.
Looks good to me.
Thanks.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com
pyanaconda/keyboard.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py index fb3f7ef..6817a15 100755 --- a/pyanaconda/keyboard.py +++ b/pyanaconda/keyboard.py @@ -34,6 +34,8 @@ import os import re from pyanaconda import iutil
+from gi.repository import Xkl
import logging log = logging.getLogger("anaconda")
@@ -226,7 +228,7 @@ class XklWrapper(object): return XklWrapper._instance
def __init__(self):
from gi.repository import Xkl, GdkX11
from gi.repository import GdkX11 #initialize Xkl-related stuff display = GdkX11.x11_get_default_xdisplay()
@@ -311,6 +313,21 @@ class XklWrapper(object): #first layout (should exist for every language) return language_layouts[0].name
- def get_current_layout_name(self):
"""
Get current activated X layout's name
@return: current activated X layout's name (e.g. "Czech (qwerty)")
"""
self._engine.start_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE)
state = self._engine.get_current_state()
groups_names = self._engine.get_groups_names()
self._engine.stop_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE)
return groups_names[state.group]
- def add_layout(self, layout): """ Method that tries to add a given layout to the current X configuration.
pyanaconda/ui/gui/spokes/lib/passphrase.glade | 230 +++++++++++++++++++++++++ pyanaconda/ui/gui/spokes/lib/passphrase.py | 177 +++++++++++++++++++
Remember to add these files to po/POTFILES.in or their strings will never get translated.
For UI consistency, I recommend the following:
(1) passphrase_dialog_title_label be bold and have xalign = 0.0.
(2) passphrase_description_label have xalign = 0.0.
(3) passphrase_cancel_button have halign = end.
+warning_label_template = _("Warning: You current keyboard layout is <b>%s</b>."
^
Typo.
# disable input methods for the passphrase Entry widgets and make sure
# the focus change mask is enabled
self._passphrase_entry = self.builder.get_object("passphrase_entry")
self._passphrase_entry.set_property("im-module", "")
self._passphrase_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, "")
self._passphrase_entry.add_events(Gdk.EventMask.FOCUS_CHANGE_MASK)
self._confirm_entry = self.builder.get_object("confirm_entry")
self._confirm_entry.set_property("im-module", "")
self._confirm_entry.add_events(Gdk.EventMask.FOCUS_CHANGE_MASK)
self._save_button = self.builder.get_object("passphrase_save_button")
# add the passphrase strength meter
self._strength_bar = Gtk.LevelBar()
self._strength_bar.set_mode(Gtk.LevelBarMode.DISCRETE)
self._strength_bar.set_min_value(0)
self._strength_bar.set_max_value(4)
box = self.builder.get_object("strength_box")
box.pack_start(self._strength_bar, False, True, 0)
box.show_all()
self._strength_label = self.builder.get_object("strength_label")
It's distressing to see this much UI code that glade appears unable to handle.
- Chris
--- pyanaconda/ui/gui/spokes/custom.glade | 130 ++++++++++++++++++++++++++++++++- 1 files changed, 129 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.glade b/pyanaconda/ui/gui/spokes/custom.glade index 8ccae64..7ae922c 100644 --- a/pyanaconda/ui/gui/spokes/custom.glade +++ b/pyanaconda/ui/gui/spokes/custom.glade @@ -1248,7 +1248,135 @@ you'll be able to view their details here.</property> <placeholder/> </child> <child> - <placeholder/> + <object class="GtkBox" id="box5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkBox" id="box6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="encryptedDeviceLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Selected Device</property> + <attributes> + <attribute name="weight" value="bold"/> + <attribute name="scale" value="1.2"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="encryptedDeviceDescriptionLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Device description</property> + <attributes> + <attribute name="style" value="italic"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSeparator" id="separator2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="unlockLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">This device is encrypted and cannot be read without a valid passphrase. You may unlock it below.</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="passphraseLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Passphrase:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="passphraseEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="visibility">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="unlockButton"> + <property name="label" translatable="yes">_Unlock</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_unlock_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> </child> <child type="tab"> <placeholder/>
pyanaconda/ui/gui/spokes/custom.glade | 130 ++++++++++++++++++++++++++++++++- 1 files changed, 129 insertions(+), 1 deletions(-)
You should set encryptedDeviceDescriptionLabel's halign to end so it'll match up with selectedDeviceDescLabel.
You might also want to set line wrap on unlockLabel to Word mode. I'm not sure it'll ever come up, but that's kind of a long label (especially so in other languages) and it's possible it'll run off the screen.
- Chris
--- pyanaconda/ui/gui/spokes/custom.py | 225 +++++++++++++++++++++++++++++------ pyanaconda/ui/gui/spokes/storage.py | 7 +- 2 files changed, 193 insertions(+), 39 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 7bb6bf0..5af61c2 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -48,18 +48,22 @@ from pyanaconda.storage.formats import device_formats from pyanaconda.storage.formats import getFormat from pyanaconda.storage.size import Size from pyanaconda.storage import Root +from pyanaconda.storage import findExistingInstallations from pyanaconda.storage.partitioning import doPartitioning from pyanaconda.storage.partitioning import doAutoPartition from pyanaconda.storage.errors import StorageError from pyanaconda.storage.errors import NoDisksError from pyanaconda.storage.errors import NotEnoughFreeSpaceError from pyanaconda.storage.errors import ErrorRecoveryFailure +from pyanaconda.storage.errors import CryptoError from pyanaconda.storage.devicelibs import mdraid +from pyanaconda.storage.devices import LUKSDevice
from pyanaconda.ui.gui import GUIObject from pyanaconda.ui.gui.spokes import NormalSpoke from pyanaconda.ui.gui.spokes.storage import StorageChecker from pyanaconda.ui.gui.spokes.lib.cart import SelectedDisksDialog +from pyanaconda.ui.gui.spokes.lib.passphrase import PassphraseDialog from pyanaconda.ui.gui.spokes.lib.accordion import * from pyanaconda.ui.gui.utils import enlightbox, setViewportBackground from pyanaconda.ui.gui.categories.storage import StorageCategory @@ -73,6 +77,7 @@ __all__ = ["CustomPartitioningSpoke"]
NOTEBOOK_LABEL_PAGE = 0 NOTEBOOK_DETAILS_PAGE = 1 +NOTEBOOK_LUKS_PAGE = 2
new_install_name = _("New %s %s Installation") % (productName, productVersion) unrecoverable_error_msg = _("Storage configuration reset due to unrecoverable " @@ -273,7 +278,14 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): """ Register actions from the UI with the main Storage instance. """ for ui_action in actions: ui_device = ui_action.device - device = self.storage.devicetree.getDeviceByID(ui_device.id) + if isinstance(ui_device, LUKSDevice) and ui_device.exists: + # LUKS device that was unlocked during this spoke visit + # The ids won't match in this case because we instantiated the + # LUKSDevice both in the spoke's devicetree and in the main one. + device = self.storage.devicetree.getDeviceByName(ui_device.name) + else: + device = self.storage.devicetree.getDeviceByID(ui_device.id) + if device is None: # This device does not exist in the main devicetree. # @@ -325,6 +337,31 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): for action in ui_devicetree.findActions(): log.debug("%s" % action)
+ # Find any LUKS devices that have been unlocked in this visit to the + # custom spoke and find their descendant devices before we do anything + # else. + ui_luks_devices = [d for d in self._devices + if isinstance(d, LUKSDevice) and + d.exists and not + self.storage.devicetree.getDeviceByID(d.id)] + for ui_luks_device in ui_luks_devices: + if ui_luks_device not in self._devices: + # since removed + continue + + ui_slave = ui_luks_device.slave + slave = self.storage.devicetree.getDeviceByID(ui_slave.id) + slave.format.passphrase = ui_slave.format._LUKS__passphrase + luks_device = LUKSDevice(slave.format.mapName, + parents=[slave], + exists=True) + luks_device.setup() + self.storage.devicetree._addDevice(luks_device) + + # XXX What if the user has changed storage config in the shell? + if ui_luks_devices: + self.storage.devicetree.populate() + # schedule actions for device removals, resizes actions = ui_devicetree.findActions(type="destroy") partition_destroys = [a for a in actions @@ -396,6 +433,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): ui_device.size == ui_device.currentSize: self.storage.resetDevice(device)
+ # apply global passphrase to all new encrypted devices + self.data.autopart.passphrase = self.passphrase + for device in self.storage.devices: + if device.format.type == "luks" and not device.format.exists: + log.debug("using global passphrase for %s" % device.name) + device.format.passphrase = self.data.autopart.passphrase + # set up bootloader and check the configuration self.storage.setUpBootLoader() StorageChecker.run(self) @@ -561,6 +605,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): if t: t.join()
+ self.passphrase = self.data.autopart.passphrase self._reset_storage() self._do_refresh() # update our free space number based on Storage @@ -590,7 +635,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # Now it's time to populate the accordion.
# A device scheduled for formatting only belongs in the new root. - new_devices = [d for d in self._devices if not d.format.exists and + new_devices = [d for d in self._devices if d.isleaf and + not d.format.exists and not d.partitioned]
# If mountpoints have been assigned to any existing devices, go ahead @@ -800,7 +846,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
log.info("ui: saving changes to device %s" % device.name)
- # TODO: encryption, raid, member type + # TODO: member type, disk set
size = self.builder.get_object("sizeSpinner").get_value() log.debug("new size: %s" % size) @@ -819,10 +865,11 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): fs_type = fs_type_combo.get_model()[fs_type_index][0] log.debug("new fs type: %s" % fs_type)
+ prev_encrypted = device.encrypted + log.debug("old encryption setting: %s" % prev_encrypted) encrypted = self.builder.get_object("encryptCheckbox").get_active() log.debug("new encryption setting: %s" % encrypted)
- # TODO: get disks label = self.builder.get_object("labelEntry").get_text() old_label = getattr(device.format, "label", "") or ""
@@ -845,9 +892,9 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
with ui_storage_logger(): # create a new factory using the appropriate size and type - # XXX ignoring encryption for now factory = self.__storage.getDeviceFactory(device_type, size, disks=device.disks, + encrypted=encrypted, raid_level=raid_level)
# for raid settings, we'll need to adjust the member set and container, @@ -863,8 +910,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): "lvmlv": AUTOPART_TYPE_LVM, "btrfs subvolume": AUTOPART_TYPE_BTRFS, "mdarray": None} - current_device_type = device_types.get(device.type) + current_device_type = device.type + if current_device_type == "luks/dm-crypt": + current_device_type = device.slave.type + current_device_type = device_types.get(current_device_type) if current_device_type != device_type: + log.info("changing device type from %s to %s" % (current_device_type, + device_type)) # remove the current device self.clear_errors() root = self._current_selector._root @@ -874,7 +926,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): return
with ui_storage_logger(): - # XXX skipping encryption for now # Use any disks with space in addition to any disks used by # a defined container. disks = [d for d in self._clearpartDevices @@ -887,6 +938,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self._replace_device(device_type, size, fstype=fs_type, disks=disks, mountpoint=mountpoint, label=label, raid_level=raid_level, + encrypted=encrypted, selector=selector) except ErrorRecoveryFailure as e: self._error = e @@ -921,6 +973,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): mountpoint=old_mountpoint, label=old_label, raid_level=raid_level, + encrypted=encrypted, selector=selector) except StorageError as e: # failed to recover. @@ -998,9 +1051,40 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self._updateSpaceDisplay()
## + ## ENCRYPTION + ## + old_device = device + if prev_encrypted and not encrypted: + log.info("removing encryption from %s" % device.name) + with ui_storage_logger(): + self.__storage.destroyDevice(device) + self._devices.remove(device) + old_device = device + device = device.slave + selector._device = device + for s in self._accordion.allSelectors: + if s._device == old_device: + s._device = device + elif encrypted and not prev_encrypted: + log.info("applying encryption to %s" % device.name) + with ui_storage_logger(): + old_device = device + new_fmt = getFormat("luks", device=device.path) + self.__storage.formatDevice(device, new_fmt) + luks_dev = LUKSDevice("luks-" + device.name, + parents=[device]) + self.__storage.createDevice(luks_dev) + self._devices.append(luks_dev) + device = luks_dev + selector._device = device + for s in self._accordion.allSelectors: + if s._device == old_device: + s._device = device + + ## ## FORMATTING ## - if fs_type != device.format.name: + if fs_type != device.format.type: self.clear_errors() with ui_storage_logger(): old_format = device.format @@ -1027,7 +1111,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # it to the new page for page in self._accordion.allPages: for _selector in getattr(page, "_members", []): - if _selector._device == device: + if _selector._device in (device, old_device): page.removeSelector(_selector) if not page._members: log.debug("removing empty page %s" % page.pageTitle) @@ -1037,9 +1121,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
return
- # for encryption, I'm not sure if we'll want to modify the - # container/device or just create a new one - ## ## FORMATTING ATTRIBUTES ## @@ -1208,6 +1289,10 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): fsCombo = self.builder.get_object("fileSystemTypeCombo")
device = selector._device + if device.type == "luks/dm-crypt": + use_dev = device.slave + else: + use_dev = device
selectedDeviceLabel.set_text(selector.props.name) selectedDeviceDescLabel.set_text(self._description(selector.props.name)) @@ -1222,7 +1307,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): not device.format.exists) labelEntry.set_sensitive(can_label)
- if labelEntry.get_sensitive(): + if hasattr(device.format, "label"): labelEntry.props.has_tooltip = False else: labelEntry.set_tooltip_text(_("This file system does not support labels.")) @@ -1248,8 +1333,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): encryptCheckbox.set_active(device.encrypted)
# if the format is swap the device type can't be btrfs - include_btrfs = device.format.type not in ("swap", "prepboot", - "biosboot") + include_btrfs = use_dev.format.type not in ("swap", "prepboot", + "biosboot") # btrfs has to be the last type in the list btrfs_included = typeCombo.get_model()[-1][0] == "BTRFS" if include_btrfs and not btrfs_included: @@ -1269,20 +1354,20 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# FIXME: What do we do if we can't figure it out? raid_level = None - if device.type == "lvmlv": + if use_dev.type == "lvmlv": # TODO: striping/mirroring typeCombo.set_active(DEVICE_TYPE_LVM) - elif device.type == "mdarray": + elif use_dev.type == "mdarray": typeCombo.set_active(DEVICE_TYPE_MD) - raid_level = mdraid.raidLevelString(device.level) - elif device.type == "partition": + raid_level = mdraid.raidLevelString(use_dev.level) + elif use_dev.type == "partition": typeCombo.set_active(DEVICE_TYPE_PARTITION) - elif device.type.startswith("btrfs"): + elif use_dev.type.startswith("btrfs"): typeCombo.set_active(DEVICE_TYPE_BTRFS) - if hasattr(device, "volume"): - raid_level = device.volume.dataLevel or "single" + if hasattr(use_dev, "volume"): + raid_level = use_dev.volume.dataLevel or "single" else: - raid_level = device.dataLevel or "single" + raid_level = use_dev.dataLevel or "single"
# you can't change the type of an existing device typeCombo.set_sensitive(not device.exists) @@ -1309,6 +1394,21 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # to the install summary screen. def on_finish_clicked(self, button): self._save_right_side(self._current_selector) + + new_luks = any([d for d in self.__storage.devices + if d.format.type == "luks" and + not d.format.exists]) + if new_luks: + dialog = PassphraseDialog(self.data) + with enlightbox(self.window, dialog.window): + rc = dialog.run() + + if rc == 0: + # Cancel. Leave the old passphrase set if there was one. + return + + self.passphrase = dialog.passphrase + NormalSpoke.on_back_clicked(self, button)
def on_add_clicked(self, button): @@ -1428,16 +1528,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
log.debug("show first mountpoint: %s" % getattr(page, "pageTitle", None)) if getattr(page, "_members", []): - log.debug("page %s has %d members" % (page.pageTitle, len(page._members))) - # Make sure we're showing details instead of the "here's how you create - # a new OS" label. - if self._current_selector: - self._current_selector.set_chosen(False) - self._partitionsNotebook.set_current_page(NOTEBOOK_DETAILS_PAGE) - self._current_selector = page._members[0] - self._current_selector.set_chosen(True) - self._populate_right_side(page._members[0]) - page._members[0].grab_focus() + self.on_selector_clicked(page._members[0]) else: self._current_selector = None
@@ -1506,6 +1597,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # Now that devices have been removed from the installation root, # refreshing the display will have the effect of making them disappear. # It's like they never existed. + self._unused_devices = None # why do we cache this? self._do_refresh() self._updateSpaceDisplay() self._show_first_mountpoint() @@ -1525,17 +1617,34 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): if not self._initialized: return
- # Make sure we're showing details instead of the "here's how you create - # a new OS" label. - self._partitionsNotebook.set_current_page(NOTEBOOK_DETAILS_PAGE) - # Take care of the previously chosen selector. if self._current_selector and self._initialized: log.debug("current selector: %s" % self._current_selector._device) log.debug("new selector: %s" % selector._device) - self._save_right_side(self._current_selector) + nb_page = self._partitionsNotebook.get_current_page() + log.debug("notebook page = %s" % nb_page) + if nb_page != NOTEBOOK_LUKS_PAGE: + self._save_right_side(self._current_selector) + self._current_selector.set_chosen(False)
+ if selector._device.format.type == "luks" and \ + selector._device.format.exists: + self._partitionsNotebook.set_current_page(NOTEBOOK_LUKS_PAGE) + selectedDeviceLabel = self.builder.get_object("encryptedDeviceLabel") + selectedDeviceDescLabel = self.builder.get_object("encryptedDeviceDescriptionLabel") + selectedDeviceLabel.set_text(selector.props.name) + selectedDeviceDescLabel.set_text(self._description(selector.props.name)) + selector.set_chosen(True) + self._current_selector = selector + self._configButton.set_sensitive(False) + self._removeButton.set_sensitive(True) + return + + # Make sure we're showing details instead of the "here's how you create + # a new OS" label. + self._partitionsNotebook.set_current_page(NOTEBOOK_DETAILS_PAGE) + # Set up the newly chosen selector. self._populate_right_side(selector) selector.set_chosen(True) @@ -1706,3 +1815,43 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): def on_apply_clicked(self, button): """ call _save_right_side, then, perhaps, populate_right_side. """ self._save_right_side(self._current_selector) + + def on_unlock_clicked(self, button): + """ try to open the luks device, populate, then call _do_refresh. """ + self.clear_errors() + device = self._current_selector._device + log.info("trying to unlock %s..." % device.name) + entry = self.builder.get_object("passphraseEntry") + passphrase = entry.get_text() + device.format.passphrase = passphrase + try: + device.format.setup() + except CryptoError as e: + log.error("failed to unlock %s: %s" % (device.name, e)) + self._error = e + device.format.passphrase = None + entry.set_text("") + self.window.set_info(Gtk.MessageType.WARNING, + _("Failed to unlock encrypted block device. " + "Click for details")) + self.window.show_all() + return + + log.info("unlocked %s, now going to populate devicetree..." % device.name) + with ui_storage_logger(): + luks_dev = LUKSDevice(device.format.mapName, + parents=[device], + exists=True) + self.__storage.devicetree._addDevice(luks_dev) + # save the passphrase for possible reset and to try for other devs + self.__storage._Storage__luksDevs[device.format.uuid] = passphrase + self.__storage.devicetree._DeviceTree__luksDevs[device.format.uuid] = passphrase + # XXX What if the user has changed things using the shell? + self.__storage.devicetree.populate() + # look for new roots + self.__storage.roots = findExistingInstallations(self.__storage.devicetree) + + self._devices = self.__storage.devices + self._unused_devices = None # why do we cache this? + self._current_selector = None + self._do_refresh() diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py index a55eb52..8295e99 100644 --- a/pyanaconda/ui/gui/spokes/storage.py +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -283,7 +283,6 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.data.autopart.autopart = True
self.autopart = self.data.autopart.autopart - # FIXME: This needs to be set to a real value via some TBD UI. self.clearPartType = CLEARPART_TYPE_NONE
@@ -291,6 +290,8 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.data.ignoredisk.onlyuse = self.selected_disks[:] self.data.clearpart.drives = self.selected_disks[:] self.data.autopart.autopart = self.autopart + self.data.autopart.encrypted = self.encrypted + self.data.autopart.passphrase = self.passphrase
# no thanks, lvm self.data.autopart.type = AUTOPART_TYPE_PLAIN @@ -314,6 +315,8 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.data.clearpart.type = self.clearPartType self.storage.config.update(self.data) self.storage.autoPartType = self.data.autopart.type + self.storage.encryptedAutoPart = self.data.autopart.encrypted + self.storage.encryptionPassphrase = self.data.autopart.passphrase
# If autopart is selected we want to remove whatever has been # created/scheduled to make room for autopart. @@ -399,6 +402,8 @@ class StorageSpoke(NormalSpoke, StorageChecker): # synchronize our local data store with the global ksdata self.selected_disks = self.data.ignoredisk.onlyuse[:] self.autopart = self.data.autopart.autopart + self.encrypted = self.data.autopart.encrypted + self.passphrase = self.data.autopart.passphrase
# update the selections in the ui overviews = self.local_disks_box.get_children()
Activating the checkbutton effectively sets the default behavior of applying encryption to all new block devices, even in the custom spoke. --- pyanaconda/ui/gui/spokes/custom.py | 5 +++++ pyanaconda/ui/gui/spokes/storage.glade | 30 +++++++++++++++++++++++++++++- pyanaconda/ui/gui/spokes/storage.py | 17 +++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 5af61c2..ec60cad 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -1449,6 +1449,11 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): (mountpoint and mountpoint.startswith("/boot"))): device_type = AUTOPART_TYPE_PLAIN
+ # some devices should never be encrypted + if ((mountpoint and mountpoint.startswith("/boot")) or + fstype in ("biosboot", "prepboot")): + encrypted = False + disks = self._clearpartDevices self.clear_errors()
diff --git a/pyanaconda/ui/gui/spokes/storage.glade b/pyanaconda/ui/gui/spokes/storage.glade index 981f6b4..ec24e65 100644 --- a/pyanaconda/ui/gui/spokes/storage.glade +++ b/pyanaconda/ui/gui/spokes/storage.glade @@ -710,7 +710,35 @@ <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkCheckButton" id="encryption_checkbutton"> + <property name="label" translatable="yes">Encrypt my data. I'll set a passphrase later.</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> </packing> </child> <child> diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py index 8295e99..52790da 100644 --- a/pyanaconda/ui/gui/spokes/storage.py +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -44,6 +44,7 @@ from gi.repository import AnacondaWidgets from pyanaconda.ui.gui import GUIObject, communication from pyanaconda.ui.gui.spokes import NormalSpoke from pyanaconda.ui.gui.spokes.lib.cart import SelectedDisksDialog +from pyanaconda.ui.gui.spokes.lib.passphrase import PassphraseDialog from pyanaconda.ui.gui.spokes.lib.detailederror import DetailedErrorDialog from pyanaconda.ui.gui.categories.storage import StorageCategory from pyanaconda.ui.gui.utils import enlightbox, gdk_threaded @@ -405,6 +406,9 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.encrypted = self.data.autopart.encrypted self.passphrase = self.data.autopart.passphrase
+ encrypt_checkbutton = self.builder.get_object("encryption_checkbutton") + encrypt_checkbutton.set_active(self.encrypted) + # update the selections in the ui overviews = self.local_disks_box.get_children() for overview in overviews: @@ -580,8 +584,21 @@ class StorageSpoke(NormalSpoke, StorageChecker): # depending on custom/autopart, either set up autopart or show # custom partitioning ui self.autopart = not dialog.custom + + # even if they're not doing autopart, setting autopart.encrypted + # establishes a default of encrypting new devices + encrypt_button = self.builder.get_object("encryption_checkbutton") + self.encrypted = encrypt_button.get_active() + if dialog.custom: self.skipTo = "CustomPartitioningSpoke" + elif self.encrypted: + dialog = PassphraseDialog(self.data) + rc = self.run_lightbox_dialog(dialog) + if rc == 0: + return + + self.passphrase = dialog.passphrase
self.on_back_clicked(self.window) elif rc == dialog.RESPONSE_CANCEL:
@@ -405,6 +406,9 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.encrypted = self.data.autopart.encrypted self.passphrase = self.data.autopart.passphrase
encrypt_checkbutton = self.builder.get_object("encryption_checkbutton")
encrypt_checkbutton.set_active(self.encrypted)
# update the selections in the ui overviews = self.local_disks_box.get_children() for overview in overviews:
If there's a passphrase already set (via self.data.autopart.passphrase, above) will it get stuck into the dialog's entry automatically?
- Chris
On Mon, 2012-10-08 at 16:54 -0400, Chris Lumens wrote:
@@ -405,6 +406,9 @@ class StorageSpoke(NormalSpoke, StorageChecker): self.encrypted = self.data.autopart.encrypted self.passphrase = self.data.autopart.passphrase
encrypt_checkbutton = self.builder.get_object("encryption_checkbutton")
encrypt_checkbutton.set_active(self.encrypted)
# update the selections in the ui overviews = self.local_disks_box.get_children() for overview in overviews:
If there's a passphrase already set (via self.data.autopart.passphrase, above) will it get stuck into the dialog's entry automatically?
Yes -- near the bottom of PassphraseDialog.refresh.
- Chris
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
anaconda-patches@lists.fedorahosted.org