Revision cf157731
Added by dsorber almost 9 years ago
| software/pwmgr/pwmgr.py | ||
|---|---|---|
|
#!/usr/bin/python3
|
||
|
import glob
|
||
|
import os
|
||
|
import shutil
|
||
|
import subprocess
|
||
| ... | ... | |
|
|
||
|
import gi
|
||
|
gi.require_version('Gtk', '3.0')
|
||
|
from gi.repository import Gtk, Pango
|
||
|
from gi.repository import Gtk, Pango, Gdk
|
||
|
|
||
|
MOUNT_PATH = '/mnt/pw_ramdisk'
|
||
|
PWD_FILE_PATH = '/home/dsorber/Desktop/network'
|
||
| ... | ... | |
|
ENC_FILE_PATH = '/home/dsorber/Documents/chicken_soup.enc'
|
||
|
SCRATCH_FILE_PATH = '/mnt/pw_ramdisk/chicken_soup.txt'
|
||
|
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.2'
|
||
|
VERSION = '0.0.3'
|
||
|
|
||
|
class SearchDialog(Gtk.Dialog):
|
||
|
|
||
| ... | ... | |
|
box.add(label)
|
||
|
|
||
|
self.entry = Gtk.Entry()
|
||
|
self.entry.set_activates_default(True)
|
||
|
box.add(self.entry)
|
||
|
|
||
|
# 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()
|
||
|
|
||
|
|
||
| ... | ... | |
|
Gtk.MessageType.QUESTION,
|
||
|
Gtk.ButtonsType.OK_CANCEL,
|
||
|
message)
|
||
|
|
||
|
|
||
|
dialog.set_title(title)
|
||
|
|
||
|
box = dialog.get_content_area()
|
||
| ... | ... | |
|
pw_entry.set_visibility(False)
|
||
|
pw_entry.set_invisible_char('*')
|
||
|
pw_entry.set_size_request(200, 0)
|
||
|
pw_entry.set_activates_default(True)
|
||
|
|
||
|
box.add(pw_entry)
|
||
|
#~ box.pack_end(pw_entry, False, False, 0)
|
||
|
|
||
|
# Make hitting ENTER trigger the OK button
|
||
|
ok_button = dialog.get_widget_for_response(response_id=Gtk.ResponseType.OK)
|
||
|
ok_button.set_can_default(True)
|
||
|
ok_button.grab_default()
|
||
|
|
||
|
dialog.show_all()
|
||
|
response = dialog.run()
|
||
| ... | ... | |
|
self.create_textview()
|
||
|
self.create_toolbar()
|
||
|
self.create_bottom()
|
||
|
self.connect("key-press-event", self._key_press_event)
|
||
|
|
||
|
|
||
|
self.mounted = False
|
||
|
self.pwd_file_fd = None
|
||
|
self.pwd = None
|
||
|
|
||
|
|
||
|
|
||
|
def _key_press_event(self, widget, event):
|
||
|
keyval = event.keyval
|
||
|
keyval_name = Gdk.keyval_name(keyval)
|
||
|
state = event.state
|
||
|
|
||
|
ctrl = (state & Gdk.ModifierType.CONTROL_MASK)
|
||
|
|
||
|
# Bind existing handlers to keys
|
||
|
if ctrl and keyval_name == 'f':
|
||
|
self.on_search_clicked(widget)
|
||
|
elif ctrl and keyval_name == 'o':
|
||
|
self.open_pwd_file(widget)
|
||
|
elif ctrl and keyval_name == 's':
|
||
|
self.save_pwd_file(widget)
|
||
|
elif ctrl and keyval_name == 'q':
|
||
|
self.close_pwd_file(widget, None)
|
||
|
else:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
def create_toolbar(self):
|
||
|
toolbar = Gtk.Toolbar()
|
||
| ... | ... | |
|
"""
|
||
|
Open handler
|
||
|
"""
|
||
|
|
||
|
|
||
|
# Get password
|
||
|
self.pwd = get_user_pw(self, 'Please enter your password', 'Password')
|
||
|
if self.pwd is None:
|
||
|
passwd = get_user_pw(self, 'Please enter your password', 'Password')
|
||
|
if passwd is None:
|
||
|
return
|
||
|
|
||
|
#~ print('User entered: {:s}'.format(self.pwd))
|
||
|
|
||
|
if not self.mounted:
|
||
|
os.makedirs(MOUNT_PATH, 0o600, exist_ok=True)
|
||
|
|
||
| ... | ... | |
|
subprocess.call(mnt_cmd, shell=True, timeout=5)
|
||
|
self.mounted = True
|
||
|
|
||
|
cmd = 'openssl enc -aes-256-cbc -d -in {:s} -out {:s} -pass pass:{:s}'
|
||
|
cmd = cmd.format(ENC_FILE_PATH, SCRATCH_FILE_PATH, self.pwd)
|
||
|
# Store password
|
||
|
with open(KEY_FILE_PATH, 'w') as pass_wd_file:
|
||
|
pass_wd_file.write(passwd)
|
||
|
os.chmod(KEY_FILE_PATH, 0o600)
|
||
|
|
||
|
# Decrypt password store
|
||
|
cmd = 'openssl enc -aes-256-cbc -d -in {:s} -out {:s} -pass file:{:s}'
|
||
|
cmd = cmd.format(ENC_FILE_PATH, SCRATCH_FILE_PATH, KEY_FILE_PATH)
|
||
|
subprocess.call(cmd, shell=True, timeout=5)
|
||
|
|
||
|
# Open and load file; make textview editable
|
||
| ... | ... | |
|
|
||
|
if self.mounted:
|
||
|
|
||
|
# Write the password store datat to the sratch file
|
||
|
with open(SCRATCH_FILE_PATH, 'w') as pwd_file_fd:
|
||
|
pwd_file_fd.write(
|
||
|
self.textbuffer.get_text(self.textbuffer.get_start_iter(),
|
||
| ... | ... | |
|
True))
|
||
|
print('Write complete')
|
||
|
|
||
|
cmd = 'openssl enc -aes-256-cbc -salt -in {:s} -out {:s} -pass pass:{:s}'
|
||
|
cmd = cmd.format(SCRATCH_FILE_PATH, ENC_TMP_FILE_PATH, self.pwd)
|
||
|
# Encrypt the password store
|
||
|
cmd = 'openssl enc -aes-256-cbc -salt -in {:s} -out {:s} -pass file:{:s}'
|
||
|
cmd = cmd.format(SCRATCH_FILE_PATH, ENC_TMP_FILE_PATH, KEY_FILE_PATH)
|
||
|
subprocess.call(cmd, shell=True, timeout=5)
|
||
|
print('enc complete')
|
||
|
print('Enc complete')
|
||
|
|
||
|
# Remove the key file, then copy over the encrypted file with the
|
||
|
# just created temp one
|
||
|
os.remove(KEY_FILE_PATH)
|
||
|
os.remove(ENC_FILE_PATH)
|
||
|
os.rename(ENC_TMP_FILE_PATH, ENC_FILE_PATH)
|
||
|
|
||
|
# Clear the buffer and disable the textview
|
||
|
self.textbuffer.set_text('')
|
||
|
self.textview.set_editable(False)
|
||
|
self.textview.set_cursor_visible(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):
|
||
|
"""
|
||
|
Close handler
|
||
| ... | ... | |
|
#~ 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 = zero_write_cmd.format(os.path.join(MOUNT_PATH, 'data'))
|
||
|
|
||
|
if self.mounted:
|
||
|
#~ shutil.rmtree(os.path.join(MOUNT_PATH, '*'), ignore_errors=True)
|
||
|
rm_cmd = 'rm -rf {:s}'.format(os.path.join(MOUNT_PATH, '*'))
|
||
|
subprocess.call(rm_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)
|
||
|
subprocess.call(rm_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
subprocess.call(zero_write_cmd, shell=True, timeout=5)
|
||
|
subprocess.call(rm_cmd, shell=True, timeout=5)
|
||
|
self._remove_mount_files()
|
||
|
|
||
|
umount_cmd = 'umount {:s}'.format(MOUNT_PATH)
|
||
|
subprocess.call(umount_cmd, shell=True, timeout=5)
|
||
| ... | ... | |
|
match = start.forward_search(text, 0, end)
|
||
|
|
||
|
if match != None:
|
||
|
match_start, match_end = match
|
||
|
match_start, match_end = match
|
||
|
self.textbuffer.apply_tag(self.tag_found, match_start, match_end)
|
||
|
|
||
|
# Scroll so the match appears in the middle of the screen
|
||
pwmgr v0.3.0 -- Improved security of encryption/decryption operations, bound ENTER to dialog OK buttons to improve ease of use, and implemented key bindings for common operations.