3
# ecryptui.py, Copyright 2008 Mike Rooney (https://launchpad.net/~mrooney)
7
# This is a graphical GTK utility to manage an encrypted ~/Private
8
# directory, allowing the user to mount and unmount, as well as enable
9
# auto-mounting at login.
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the GNU General Public License as published by
13
# the Free Software Foundation, either version 3 of the License, or
14
# (at your option) any later version.
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
# GNU General Public License for more details.
21
# You should have received a copy of the GNU General Public License
22
# along with this program. If not, see <http://www.gnu.org/licenses/>.
24
# Lock icons courtesy of http://www.famfamfam.com/lab/icons/silk/, via the
25
# Creative Commons Attribution 2.5 License.
28
from panelcontroller import PanelController
30
from ecryptfs import ecryptapi
34
LOCKED_ICON = os.path.join(os.path.dirname(__file__), 'lock-secure.png')
35
UNLOCKED_ICON = os.path.join(os.path.dirname(__file__), 'lock-insecure.png')
36
LOCKED_STATUS = os.path.join(os.path.dirname(__file__), 'lock-secure-small.png')
37
UNLOCKED_STATUS = os.path.join(os.path.dirname(__file__), 'lock-insecure-small.png')
40
class Window(gtk.Window):
42
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
43
self.set_title("Encrypted Directories")
45
self.hbox = gtk.HBox()
48
# Initialize some bindings.
49
self.connect("destroy", self.destroy)
51
self.Controller = PanelController(self.showInstall, self.showSetup, self.showManage)
52
self.Controller.showAppropriateStep()
56
def showInstall(self):
57
print "Step 1: Install"
58
ipanel = InstallFrame()
59
self.hbox.pack_start(ipanel, False, False, 0)
65
self.hbox.pack_start(spanel, False, False, 0)
69
print "Step 3: Manage"
70
mpanel = ManageFrame()
71
self.hbox.pack_start(mpanel, False, False, 0)
74
def showError(self, title, msg):
75
"""Show an error dialog with the given title and message body."""
76
dialog = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
77
dialog.set_title(title)
81
def destroy(self, widget, data=None):
82
"""Destroy the main window and quit."""
86
"""All PyGTK applications need a main method (apparently)."""
90
class InstallFrame(gtk.Frame):
92
gtk.Frame.__init__(self)
93
label = gtk.Label("ecryptfs-utils is not currently installed.")
96
class SetupFrame(gtk.Frame):
98
gtk.Frame.__init__(self)
99
vbox = gtk.VBox(False, 5)
101
label = gtk.Label("Choose how your encrypted Private directory will be configured.")
102
label2 = gtk.Label("If you don't understand what a particular option does, leave it at its default value.")
104
self.encryptFilenamesCheckbox = gtk.CheckButton("Encrypt filenames")
105
self.encryptFilenamesCheckbox.set_active(True)
107
self.checkPasswordValidityCheckbox = gtk.CheckButton("Check the validity of the specified login password")
108
self.checkPasswordValidityCheckbox.set_active(True)
110
self.createPrivateButton = gtk.Button("Create Private directory")
112
vbox.pack_start(label, False, True, 5)
113
vbox.pack_start(label2, False, False, 5)
114
vbox.pack_start(self.encryptFilenamesCheckbox, False, False, 5)
115
vbox.pack_start(self.checkPasswordValidityCheckbox, False, False, 5)
116
vbox.pack_start(self.createPrivateButton, False, False, 5)
119
self.createPrivateButton.connect("clicked", self.onCreatePrivate, None)
121
def generateCommand(self):
122
args = ["ecryptfs-setup-private"]
123
if not self.encryptFilenamesCheckbox.get_active():
124
args.append("--no-fnek")
125
if not self.checkPasswordValidityCheckbox.get_active():
126
args.append("--nopwcheck")
128
command = " ".join(args)
131
def onCreatePrivate(self, widget, data=None):
132
print self.generateCommand()
134
class ManageFrame(gtk.Frame):
136
"""Create and layout the user interface."""
137
gtk.Frame.__init__(self)
139
# When this is True, ignore toggle events, such as when we manually set it.
140
# Initially True because we need to set the value.
141
self.autoMountFrozen = True
142
self.autoUnmountFrozen = True
144
# The state variable, later wrapped in a property.
145
self._MountedState = ecryptapi.get_mounted()
147
# The main, vertical sizer, for holding the controls.
148
hbox = gtk.HBox(False, 5)
149
vbox = gtk.VBox(False, 5)
150
hbox.pack_start(vbox, False, False, 5)
153
# Create the label controls with explain the current status.
154
labelHbox = gtk.HBox()
155
label = gtk.Label("Your Private directory is currently: ")
156
self.statusImage = gtk.Image()
157
self.buttonImage = gtk.Image()
158
self.statusLabel = gtk.Label("")
159
self.statusLabel.set_use_markup(True)
160
labelHbox.pack_start(label, False, False, 2)
161
#labelHbox.pack_start(gtk.Label(""), True, True, 0) # Just a spacer.
162
labelHbox.pack_start(self.statusLabel, False, False, 0)
163
labelHbox.pack_start(self.statusImage, False, False, 2)
165
# Create the button allowing the user to toggle the state.
166
self.toggleButton = gtk.Button("")
168
# Create a checkbox for toggling automounting.
169
self.autoCheck = gtk.CheckButton("Automatically unlock Private directory at login")
170
self.autoCheck.set_active(ecryptapi.get_automount())
171
self.autoMountFrozen = False # Now we set, unfreeze.
173
# Create a checkbox for toggling autounmounting.
174
self.autoCheck2 = gtk.CheckButton("Automatically lock Private directory at logoff")
175
self.autoCheck2.set_active(ecryptapi.get_autounmount())
176
self.autoUnmountFrozen = False # Now we set, unfreeze.
178
# Add everything to the main sizer.
179
vbox.pack_start(labelHbox, False, False, 5)
180
vbox.pack_start(self.toggleButton, False, False, 0)
181
vbox.pack_start(self.autoCheck, False, False, 0)
182
vbox.pack_start(self.autoCheck2, False, False, 0)
184
# Update the UI state from the current state.
185
self.updateFromState()
187
# Initilize some bindings
188
self.toggleButton.connect("clicked", self.onStateToggled, None)
189
self.autoCheck.connect("toggled", self.onAutoMountToggled, None)
190
self.autoCheck2.connect("toggled", self.onAutoUnmountToggled, None)
196
def SetMountedState(self, state):
197
"""Sets the internal mount state and triggers a UI update."""
198
self._MountedState = state
199
self.updateFromState()
201
def updateFromState(self):
203
When the state of the mount changes, this is called to update the GUI.
205
if self.MountedState:
206
status, action, actionIcon, statusIcon = "Unlocked", "Lock your Private directory", LOCKED_ICON, UNLOCKED_STATUS
208
status, action, actionIcon, statusIcon = "Locked", "Unlock your Private directory", UNLOCKED_ICON, LOCKED_STATUS
210
self.statusLabel.set_label("<b>%s</b>"%status)
211
self.toggleButton.set_property("image-position", gtk.POS_TOP)
212
self.toggleButton.set_label(action)
213
self.buttonImage.set_from_file(actionIcon)
214
self.statusImage.set_from_file(statusIcon)
215
self.toggleButton.set_image(self.buttonImage) # Does this only need to be called once in init?
217
def onAutoMountToggled(self, widget, data=None):
218
"""The event handler for the automount checkbutton."""
219
if not self.autoMountFrozen:
220
desiredState = widget.get_active()
221
status, output = ecryptapi.set_automount(desiredState)
223
# It failed, unset the checkbox and show the error.
224
self.autoMountFrozen = True
225
widget.set_active(not desiredState)
226
self.autoMountFrozen = False
227
self.showError("Error %s"%status, output)
229
def onAutoUnmountToggled(self, widget, data=None):
230
"""The event handler for the automount checkbutton."""
231
if not self.autoUnmountFrozen:
232
desiredState = widget.get_active()
233
status, output = ecryptapi.set_autounmount(desiredState)
235
# It failed, unset the checkbox and show the error.
236
self.autoUnmountFrozen = True
237
widget.set_active(not desiredState)
238
self.autoUnmountFrozen = False
239
self.showError("Error %s"%status, output)
241
def onStateToggled(self, widget, data=None):
242
"""The event handler for the mount toggle button."""
243
desiredState = not self.MountedState
244
status, output = ecryptapi.set_mounted(desiredState)
246
# The action was successful, update our state.
247
self.MountedState = desiredState
249
# The action failed, report the error.
250
self.showError("Error %s"%status, output)
252
MountedState = property(fget=lambda self: self._MountedState, fset=SetMountedState)
259
if __name__ == "__main__":