anaconda: Modify user configuration spoke for Qubes OS

This commit is contained in:
M. Vefa Bicakci 2016-04-10 00:00:00 -04:00
parent 34e37e3dc8
commit ed17da5dc6
No known key found for this signature in database
GPG Key ID: 1DF87CE3B3A5DFAF
3 changed files with 24 additions and 154 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.19.0 -->
<interface>
<requires lib="gtk+" version="3.6"/>
<requires lib="AnacondaWidgets" version="1.0"/>
@ -53,33 +53,15 @@
<property name="can_focus">False</property>
<property name="row_spacing">8</property>
<property name="column_spacing">9</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes" context="GUI|User">_Full name</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">t_fullname</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes" context="GUI|User">_User name</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">t_username</property>
<property name="xalign">1</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@ -89,23 +71,6 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="t_fullname">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="caps_lock_warning">False</property>
<signal name="changed" handler="full_name_changed" swapped="no"/>
<child internal-child="accessible">
<object class="AtkObject" id="t_fullname-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Full Name</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="t_username">
<property name="visible">True</property>
@ -126,11 +91,11 @@
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes" context="GUI|User">_Password</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">t_password</property>
<property name="xalign">1</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@ -144,11 +109,11 @@
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes" context="GUI|User">_Confirm password</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">t_verifypassword</property>
<property name="xalign">1</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@ -197,9 +162,9 @@
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Tip:&lt;/b&gt; Keep your user name shorter than 32 characters and do not use spaces.</property>
<property name="use_markup">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
@ -266,44 +231,10 @@
</packing>
</child>
<child>
<object class="GtkCheckButton" id="c_admin">
<property name="label" translatable="yes" context="GUI|User">_Make this user administrator</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
<placeholder/>
</child>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="b_advanced">
<property name="label" translatable="yes" context="GUI|User">_Advanced...</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_advanced_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">8</property>
</packing>
<placeholder/>
</child>
<child>
<placeholder/>

View File

@ -40,7 +40,7 @@ from pyanaconda.constants import ANACONDA_ENVIRON, FIRSTBOOT_ENVIRON,\
PW_ASCII_CHARS, PASSWORD_ASCII
from pyanaconda.regexes import GECOS_VALID, USERNAME_VALID, GROUPNAME_VALID, GROUPLIST_FANCY_PARSE
__all__ = ["UserSpoke", "AdvancedUserDialog"]
__all__ = ["UserSpoke"]
class AdvancedUserDialog(GUIObject, GUIDialogInputCheckHandler):
"""
@ -232,7 +232,7 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
builderObjects = ["userCreationWindow"]
mainWidgetName = "userCreationWindow"
focusWidgetName = "t_fullname"
focusWidgetName = "t_username"
uiFile = "spokes/user.glade"
helpFile = "UserSpoke.xml"
@ -243,9 +243,6 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
@classmethod
def should_run(cls, environment, data):
# The Qubes installer still uses old firstboot to create users (TODO)
return False
# the user spoke should run always in the anaconda and in firstboot only
# when doing reconfig or if no user has been created in the installation
if environment == ANACONDA_ENVIRON:
@ -271,17 +268,17 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
self._user = self.data.user.userList[0]
else:
self._user = self.data.UserData()
self._wheel = self.data.GroupData(name="wheel")
self._groupDict = {"wheel": self._wheel}
self._qubes = self.data.GroupData(name="qubes")
self._groupDict = {"wheel": self._wheel, "qubes": self._qubes}
# placeholders for the text boxes
self.fullname = self.builder.get_object("t_fullname")
self.username = self.builder.get_object("t_username")
self.pw = self.builder.get_object("t_password")
self.confirm = self.builder.get_object("t_verifypassword")
self.admin = self.builder.get_object("c_admin")
self.usepassword = self.builder.get_object("c_usepassword")
self.b_advanced = self.builder.get_object("b_advanced")
# Counters for checks that ask the user to click Done to confirm
self._waiveStrengthClicks = 0
@ -336,8 +333,6 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
self.add_re_check(self.username, re.compile(USERNAME_VALID.pattern + r'|^$'),
_("Invalid user name"))
self.add_re_check(self.fullname, GECOS_VALID, _("Full name cannot contain colon characters"))
# Modify the GUI based on the kickstart and policy information
# This needs to happen after the input checks have been created, since
# the Gtk signal handlers use the input check variables.
@ -358,18 +353,12 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
# User isn't allowed to change whether password is required or not
self.usepassword.set_sensitive(False)
self._advanced = AdvancedUserDialog(self._user, self._groupDict,
self.data)
self._advanced.initialize()
def refresh(self):
# Enable the input checks in case they were disabled on the last exit
for check in self.checks:
check.enabled = True
self.username.set_text(self._user.name)
self.fullname.set_text(self._user.gecos)
self.admin.set_active(self._wheel.name in self._user.groups)
self.pw.emit("changed")
self.confirm.emit("changed")
@ -377,12 +366,8 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
if self.username.get_text() and self.usepassword.get_active() and \
self._user.password == "":
self.pw.grab_focus()
elif self.fullname.get_text():
self.username.grab_focus()
else:
self.fullname.grab_focus()
self.b_advanced.set_sensitive(bool(self._user.name))
self.username.grab_focus()
@property
def status(self):
@ -420,7 +405,6 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
self._user.password_kickstarted = False
self._user.name = self.username.get_text()
self._user.gecos = self.fullname.get_text()
# Remove any groups that were created in a previous visit to this spoke
self.data.group.groupList = [g for g in self.data.group.groupList \
@ -428,15 +412,14 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
# the user will be created only if the username is set
if self._user.name:
if self.admin.get_active() and \
self._wheel.name not in self._user.groups:
if self._wheel.name not in self._user.groups:
self._user.groups.append(self._wheel.name)
elif not self.admin.get_active() and \
self._wheel.name in self._user.groups:
self._user.groups.remove(self._wheel.name)
if self._qubes.name not in self._user.groups:
self._user.groups.append(self._qubes.name)
anaconda_groups = [self._groupDict[g] for g in self._user.groups
if g != self._wheel.name]
if g not in (self._wheel.name, self._qubes.name)]
self.data.group.groupList += anaconda_groups
@ -515,28 +498,13 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
if editable.get_text() == "":
self.guesser[editable] = True
self.b_advanced.set_sensitive(False)
else:
self.guesser[editable] = False
self.b_advanced.set_sensitive(True)
# Re-run the password checks against the new username
self.pw.emit("changed")
self.confirm.emit("changed")
def full_name_changed(self, editable=None, data=None):
"""Called by Gtk callback when the full name field changes.
It guesses the username and hostname, strips diacritics
and make those lowercase.
"""
# after the text is updated in guesser, the guess has to be reenabled
if self.guesser[self.username]:
fullname = self.fullname.get_text()
username = guess_username(fullname)
self.username.set_text(username)
self.guesser[self.username] = True
def _checkPasswordEmpty(self, inputcheck):
"""Check whether a password has been specified at all.
@ -637,26 +605,6 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
return InputCheck.CHECK_OK
def on_advanced_clicked(self, _button, data=None):
"""Handler for the Advanced.. button. It starts the Advanced dialog
for setting homedit, uid, gid and groups.
"""
self._user.name = self.username.get_text()
if self.admin.get_active() and \
self._wheel.name not in self._user.groups:
self._user.groups.append(self._wheel.name)
elif not self.admin.get_active() and \
self._wheel.name in self._user.groups:
self._user.groups.remove(self._wheel.name)
self._advanced.refresh()
with self.main_window.enlightbox(self._advanced.window):
self._advanced.run()
self.admin.set_active(self._wheel.name in self._user.groups)
def on_back_clicked(self, button):
# If the failed check is for non-ASCII characters,
# add a click to the counter and check again

View File

@ -43,11 +43,9 @@ class UserSpoke(FirstbootSpokeMixIn, EditTUISpoke):
edit_fields = [
Entry("Create user", "_create", EditTUISpoke.CHECK, True),
Entry("Fullname", "gecos", GECOS_VALID, lambda self, args: args._create),
Entry("Username", "name", USERNAME_VALID, lambda self, args: args._create),
Entry("Use password", "_use_password", EditTUISpoke.CHECK, lambda self, args: args._create),
Entry("Password", "_password", EditTUISpoke.PASSWORD, lambda self, args: args._use_password and args._create),
Entry("Administrator", "_admin", EditTUISpoke.CHECK, lambda self, args: args._create),
Entry("Groups", "_groups", GROUPLIST_SIMPLE_VALID, lambda self, args: args._create)
]
@ -91,7 +89,6 @@ class UserSpoke(FirstbootSpokeMixIn, EditTUISpoke):
self.errors = []
def refresh(self, args=None):
self.args._admin = "wheel" in self.args.groups
self.args._groups = ", ".join(self.args.groups)
# if we have any errors, display them
@ -135,20 +132,14 @@ class UserSpoke(FirstbootSpokeMixIn, EditTUISpoke):
return _("User %s will be created") % self.data.user.userList[0].name
def apply(self):
if self.args.gecos and not self.args.name:
username = guess_username(self.args.gecos)
if not USERNAME_VALID.match(username):
self.errors.append(_("Invalid user name: %s.\n") % username)
else:
self.args.name = guess_username(self.args.gecos)
self.args.groups = [g.strip() for g in self.args._groups.split(",") if g]
# Add or remove the user from wheel group
if self.args._admin and "wheel" not in self.args.groups:
# Add the user to the wheel and qubes groups
if "wheel" not in self.args.groups:
self.args.groups.append("wheel")
elif not self.args._admin and "wheel" in self.args.groups:
self.args.groups.remove("wheel")
if "qubes" not in self.args.groups:
self.args.groups.append("qubes")
# Add or remove the user from userlist as needed
if self.args._create and (self.args not in self.data.user.userList and self.args.name):