Revision 0b45b84e
Added by dsorber almost 9 years ago
| software/pwmgr/pwmgr.py | ||
|---|---|---|
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import time
|
||
|
import threading
|
||
|
|
||
|
import gi
|
||
|
gi.require_version('Gtk', '3.0')
|
||
|
from gi.repository import Gtk, Pango, Gdk
|
||
|
from gi.repository import Gtk, Pango, Gdk, GLib
|
||
|
|
||
|
MOUNT_PATH = '/mnt/pw_ramdisk'
|
||
|
PWD_FILE_PATH = '/home/dsorber/Desktop/network'
|
||
| ... | ... | |
|
ENC_TMP_FILE_PATH = '/home/dsorber/Documents/chicken_soup.enc.tmp'
|
||
|
KEY_FILE_PATH = '/mnt/pw_ramdisk/.f05d11ef-000c-45c2-ae14-56b56c23e1c5'
|
||
|
|
||
|
VERSION = '0.0.3'
|
||
|
VERSION = '0.0.4'
|
||
|
|
||
|
class SearchDialog(Gtk.Dialog):
|
||
|
|
||
| ... | ... | |
|
self.show_all()
|
||
|
|
||
|
|
||
|
class WarningDialog(Gtk.Dialog):
|
||
|
class WarningDialog(Gtk.MessageDialog):
|
||
|
|
||
|
def __init__(self, parent, title, message):
|
||
|
Gtk.MessageDialog.__init__(self, parent,
|
||
| ... | ... | |
|
message)
|
||
|
|
||
|
self.set_title(title)
|
||
|
|
||
|
# Make hitting ENTER trigger the OK button
|
||
|
ok_button = self.get_widget_for_response(response_id=Gtk.ResponseType.OK)
|
||
|
ok_button.set_can_default(True)
|
||
|
ok_button.grab_default()
|
||
|
|
||
|
self.show_all()
|
||
|
|
||
|
def get_user_pw(parent, message, title=''):
|
||
| ... | ... | |
|
dialog.set_title(title)
|
||
|
|
||
|
box = dialog.get_content_area()
|
||
|
box.set_border_width(10)
|
||
|
pw_entry = Gtk.Entry()
|
||
|
pw_entry.set_visibility(False)
|
||
|
pw_entry.set_invisible_char('*')
|
||
| ... | ... | |
|
if (response == Gtk.ResponseType.OK) and (text != ''):
|
||
|
return text
|
||
|
else:
|
||
|
return None
|
||
|
return None
|
||
|
|
||
|
class ProgressBarWindow(Gtk.Window):
|
||
|
|
||
|
def __init__(self, parent, title):
|
||
|
Gtk.Window.__init__(self, title=title)
|
||
|
self.set_border_width(10)
|
||
|
|
||
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=3)
|
||
|
self.add(vbox)
|
||
|
|
||
|
self.progressbar = Gtk.ProgressBar()
|
||
|
vbox.pack_start(self.progressbar, True, True, 0)
|
||
|
|
||
|
self.progressbar.set_text('Zee text')
|
||
|
self.progressbar.set_show_text(True)
|
||
|
|
||
|
self.set_modal(True)
|
||
|
#~ self.set_decorated(False)
|
||
|
self.set_deletable(False)
|
||
|
self.set_transient_for(parent)
|
||
|
|
||
|
|
||
|
def update_text(self, text):
|
||
|
self.progressbar.set_text(text)
|
||
|
|
||
|
def update_complete(self, fraction):
|
||
|
self.progressbar.set_fraction(fraction)
|
||
|
|
||
|
|
||
|
class TextViewWindow(Gtk.Window):
|
||
|
|
||
| ... | ... | |
|
|
||
|
|
||
|
self.mounted = False
|
||
|
self.pass_data_loaded = False
|
||
|
self.pwd_file_fd = None
|
||
|
|
||
|
|
||
|
self.pbar_win = None
|
||
|
self.should_quit = False
|
||
|
|
||
|
def async_quit(self):
|
||
|
if self.should_quit:
|
||
|
if self.pbar_win is not None:
|
||
|
self.pbar_win.destroy()
|
||
|
Gtk.main_quit()
|
||
|
print('REAL QUIT')
|
||
|
return True
|
||
|
|
||
|
def _key_press_event(self, widget, event):
|
||
|
keyval = event.keyval
|
||
| ... | ... | |
|
"""
|
||
|
|
||
|
# Get password
|
||
|
passwd = get_user_pw(self, 'Please enter your password', 'Password')
|
||
|
if passwd is None:
|
||
|
return
|
||
|
if not self.pass_data_loaded:
|
||
|
passwd = get_user_pw(self, 'Please enter your password', 'Password')
|
||
|
if passwd is None:
|
||
|
return
|
||
|
|
||
|
if not self.mounted:
|
||
|
os.makedirs(MOUNT_PATH, 0o600, exist_ok=True)
|
||
| ... | ... | |
|
self.textbuffer.set_text(pwd_file_fd.read())
|
||
|
self.textview.set_editable(True)
|
||
|
self.textview.set_cursor_visible(True)
|
||
|
|
||
|
# Mark state that pasword data is loaded
|
||
|
self.pass_data_loaded = True
|
||
|
|
||
|
def save_pwd_file(self, widget):
|
||
|
"""
|
||
|
Save handler
|
||
|
"""
|
||
|
|
||
|
if self.mounted:
|
||
|
if self.mounted and self.pass_data_loaded:
|
||
|
|
||
|
# Write the password store datat to the sratch file
|
||
|
with open(SCRATCH_FILE_PATH, 'w') as pwd_file_fd:
|
||
| ... | ... | |
|
self.textbuffer.set_text('')
|
||
|
self.textview.set_editable(False)
|
||
|
self.textview.set_cursor_visible(False)
|
||
|
|
||
|
# Mark password data as not loaded
|
||
|
self.pass_data_loaded = False
|
||
|
|
||
|
def _remove_mount_files(self):
|
||
|
# Remove files in the mount path
|
||
|
for file_ in glob.glob('{:s}/*'.format(MOUNT_PATH)):
|
||
|
os.remove(file_)
|
||
|
|
||
|
def close_pwd_file(self, widget, other):
|
||
|
def do_mount_cleanup(self):
|
||
|
"""
|
||
|
Close handler
|
||
|
Clean up ramdisk by overwriting, then unmount
|
||
|
"""
|
||
|
GLib.idle_add(self.pbar_win.update_text, 'Starting ramdisk cleanup')
|
||
|
|
||
|
|
||
|
#~ dialog = WarningDialog(self, 'Close?', 'Have you saved?')
|
||
|
#~ response = dialog.run()
|
||
|
#~ dialog.destroy()
|
||
|
|
||
|
# Clear the buffer and disable the textview
|
||
|
self.textbuffer.set_text('')
|
||
|
self.textview.set_editable(False)
|
||
|
self.textview.set_cursor_visible(False)
|
||
|
|
||
|
rand_write_cmd = 'dd if=/dev/urandom of={:s} bs=16M count=1 status=none'
|
||
|
rand_write_cmd = rand_write_cmd.format(os.path.join(MOUNT_PATH, 'data'))
|
||
|
|
||
|
zero_write_cmd = 'dd if=/dev/zero of={:s} bs=16M count=1 status=none'
|
||
|
zero_write_cmd = zero_write_cmd.format(os.path.join(MOUNT_PATH, 'data'))
|
||
|
|
||
|
if self.mounted:
|
||
|
self._remove_mount_files()
|
||
|
|
||
|
# Overwrite the ramdisk a few times
|
||
|
for ctr in range(10):
|
||
|
print(ctr)
|
||
|
message = 'Overwrite {:d} of 10'.format(ctr + 1)
|
||
|
GLib.idle_add(self.pbar_win.update_text, message)
|
||
|
|
||
|
subprocess.call(rand_write_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
subprocess.call(zero_write_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
|
||
|
# Overwrite a few times
|
||
|
for ctr in range(10):
|
||
|
print(ctr)
|
||
|
subprocess.call(rand_write_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
subprocess.call(zero_write_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
GLib.idle_add(self.pbar_win.update_complete, (ctr + 1) / 10)
|
||
|
|
||
|
GLib.idle_add(self.pbar_win.update_text, 'Unmounting ramdisk')
|
||
|
umount_cmd = 'umount {:s}'.format(MOUNT_PATH)
|
||
|
subprocess.call(umount_cmd, shell=True, timeout=5)
|
||
|
GLib.idle_add(self.pbar_win.update_text, 'Complete')
|
||
|
|
||
|
self.should_quit = True
|
||
|
print('SET should quit')
|
||
|
|
||
|
def close_pwd_file(self, widget, other):
|
||
|
"""
|
||
|
Close handler
|
||
|
"""
|
||
|
|
||
|
# If data is loaded ask to save before closing
|
||
|
if self.pass_data_loaded:
|
||
|
dialog = WarningDialog(self, 'Save changes?',
|
||
|
'Save changes to password data?')
|
||
|
response = dialog.run()
|
||
|
dialog.destroy()
|
||
|
|
||
|
if response == Gtk.ResponseType.OK:
|
||
|
self.save_pwd_file(widget)
|
||
|
|
||
|
# Clear the buffer and disable the textview
|
||
|
self.textbuffer.set_text('')
|
||
|
self.textview.set_editable(False)
|
||
|
self.textview.set_cursor_visible(False)
|
||
|
|
||
|
if self.mounted:
|
||
|
# Start async polling of the quit flag
|
||
|
GLib.idle_add(self.async_quit)
|
||
|
|
||
|
# Create the progress window
|
||
|
self.pbar_win = ProgressBarWindow(self, 'Closing...')
|
||
|
self.pbar_win.show_all()
|
||
|
|
||
|
umount_cmd = 'umount {:s}'.format(MOUNT_PATH)
|
||
|
subprocess.call(umount_cmd, shell=True, timeout=5)
|
||
|
# Start the work thread that does the cleanup
|
||
|
thread = threading.Thread(target=self.do_mount_cleanup)
|
||
|
thread.start()
|
||
|
else:
|
||
|
Gtk.main_quit()
|
||
|
|
||
|
Gtk.main_quit()
|
||
|
print('CLOSE')
|
||
|
|
||
|
def on_button_clicked(self, widget, tag):
|
||
|
bounds = self.textbuffer.get_selection_bounds()
|
||
|
if len(bounds) != 0:
|
||
|
start, end = bounds
|
||
|
self.textbuffer.apply_tag(tag, start, end)
|
||
|
|
||
|
def on_clear_clicked(self, widget):
|
||
|
start = self.textbuffer.get_start_iter()
|
||
|
end = self.textbuffer.get_end_iter()
|
||
pwmgr v0.4.0 -- Added save warning before quit dialog. Added improved state tracking. Finally, added progress pop on close to give user feedback while ramdisk cleanup is happening.