aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPapoteur <papoteur@mageia.org>2020-01-20 09:42:52 +0100
committerPapoteur <papoteur@mageia.org>2020-01-20 09:42:52 +0100
commit6bf666a534f5376ba813b0aaf8993691d2925496 (patch)
treedf20b98b0257618d994f2736107b08383cc82693
parent9f89ca4f026e708f7a5ddc59a0f0ee5f581ef37c (diff)
downloadisodumper-6bf666a534f5376ba813b0aaf8993691d2925496.tar
isodumper-6bf666a534f5376ba813b0aaf8993691d2925496.tar.gz
isodumper-6bf666a534f5376ba813b0aaf8993691d2925496.tar.bz2
isodumper-6bf666a534f5376ba813b0aaf8993691d2925496.tar.xz
isodumper-6bf666a534f5376ba813b0aaf8993691d2925496.zip
Add encryption for persistent partition
-rw-r--r--CHANGELOG14
-rw-r--r--README.md7
-rwxr-xr-xbackend/magiback21
-rwxr-xr-xbackend/raw_write.py101
-rwxr-xr-xlib/isodumper.py65
5 files changed, 155 insertions, 53 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 239c7be..a950cb9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,11 @@
The modifications are:
+IsoDumper 1.16
+--------------
+ - add format exFAT for formatting the device
+ - add eject instruction after writing operations
+ - add option for creation of encrypted persistent partition, could be used for Mageia 8 and later
+
IsoDumper 1.15
--------------
- Rework udisks2 information usage to be more reliable
@@ -15,7 +21,7 @@ IsoDumper 1.13
IsoDumper 1.11
--------------
- Raise error when an instance is already running
-
+
IsoDumper 1.10
--------------
- Correction to sr.po to allow generation of all translation catalogs
@@ -46,7 +52,7 @@ IsoDumper 1.05
IsoDumper 1.04
--------------
- Separate getting key and checking signature in a thread
- - Review the logic of checking
+ - Review the logic of checking
IsoDumper 1.03
--------------
@@ -99,7 +105,7 @@ IsoDumper 0.55
IsoDumper 0.54
------------
- - Updating translations in Sapnish, Romanian, Sweadidh, Basque and Latvian
+ - Updating translations in Sapnish, Romanian, Sweadidh, Basque and Latvian
- Adding links of the source in About dialog (mga#18405)
IsoDumper 0.53
@@ -131,7 +137,7 @@ IsoDumper 0.50
------------
- yui release.
-
+
IsoDumper 0.48
------------
- Better management of drive names (mga#18411).
diff --git a/README.md b/README.md
index 634a6ac..9fde56d 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ isodumper
A tool for USB sticks and removable memory devices like SD-cards.
Features:
-* dump ISO file on the device;
+* dump ISO file on the device; optionnally create a persistent partition, encrypted or not, in the remaining space;
* format the device in one partition of ext4, NTFS or FAT32 type;
* backup the device as a whole.
@@ -19,6 +19,9 @@ Requirements
- udisks2
- libyui and declanation of ncurses, gtk or Qt
- libyui-mga
+- cryptsetup
+- fdisk
+- e2fsprogs
License
@@ -29,7 +32,7 @@ This software is distributed under the terms of the
The [isodumper icon](isodumper.svg) is licensed under the terms of the
[GNU Lesser General Public License version 2.1 (LGPLv2.1+)](COPYING.LGPL).
-It is part of the Crystal Clear icon set by Everaldo Coelho.
+It is created by Thimothée Giet.
Authors
--------
diff --git a/backend/magiback b/backend/magiback
index 6bf0202..e7541c3 100755
--- a/backend/magiback
+++ b/backend/magiback
@@ -40,6 +40,7 @@ class Isodumper(raw_write.Dumper):
<method name='do_persistence'>
<arg type='s' name='target' direction='in'/>
<arg type='s' name='label' direction='in'/>
+ <arg type='s' name='key' direction='in'/>
</method>
<method name='get_sum'>
<arg type='s' name='source' direction='in'/>
@@ -75,7 +76,7 @@ class Isodumper(raw_write.Dumper):
self.signature_checked = False
self.writing_perm = False
self.writing_target = ""
-
+
def do_write(self,source, target, size, dbus_context):
self.finished.clear()
@@ -90,19 +91,19 @@ class Isodumper(raw_write.Dumper):
logging.debug(self.return_message)
self.finished.set()
- def do_persistence(self, target, label):
+ def do_persistence(self, target, label, key):
self.finished.clear()
if self.writing_perm and self.writing_target == target :
- self._do_persistence(target, label)
+ self._do_persistence(target, label, key)
else:
self.return_message = "Persistence: Access denied"
self.writing_perm = False
self.writing_target = ""
-
+
@property
def done(self):
return self.finished.wait(1)
-
+
@property
def message(self):
return self.return_message
@@ -128,13 +129,13 @@ class Isodumper(raw_write.Dumper):
def get_sum(self, source):
self.key_thread = threading.Thread(target=self._get_sum, args=(source,))
self.key_thread.start()
-
+
def check_write(self,target, source):
if hasattr(self, 'key_thread'):
self.key_thread.join()
self.thread = threading.Thread(target=self._check_write, args=(target, source,))
self.thread.start()
-
+
def run(self):
self.loop.run()
@@ -142,7 +143,7 @@ def check_permission(action, dbus_context):
""" Check permission
"""
return dbus_context.is_authorized(action, {'polkit.icon_name': 'isodumper.png',}, interactive=True)
-
+
class ConfFile(object):
"""
<node>
@@ -161,7 +162,7 @@ class ConfFile(object):
"""
def __init__(self):
super().__init__()
-
+
def setName(self,file_name):
self.file_name = file_name
@@ -175,7 +176,7 @@ class ConfFile(object):
break
content += line
return content
-
+
def saveFile(self, tc, dbus_context):
if check_permission('org.mageia.Magiback.write',dbus_context):
try:
diff --git a/backend/raw_write.py b/backend/raw_write.py
index 699d1fc..9f06295 100755
--- a/backend/raw_write.py
+++ b/backend/raw_write.py
@@ -29,13 +29,14 @@
#import locale
import os
import io
+import sys
import gettext
from subprocess import call, Popen, PIPE
import hashlib
import gnupg
import time
import logging
-
+
class Dumper(object):
def _do_write(self,source,target, b):
@@ -150,6 +151,7 @@ class Dumper(object):
message += _('Error, umount returned {}').format(str(retcode))
except OSError as e:
message += _('Execution failed: {}').format(str(e))
+ print(message, file=sys.stderr)
logging.info(message)
return not bool(retcode), message
@@ -167,7 +169,7 @@ class Dumper(object):
with open(sig_file, 'rb') as g:
self.signature_found = True
verified = gpg.verify_file(g, source + ".sha512")
- if verified.valid:
+ if verified.valid:
self.signature_checked = True
logging.debug("signature checked")
else:
@@ -205,7 +207,7 @@ class Dumper(object):
if checked > steps[indice]:
self._progress = indice
indice +=1
- checked+=1024
+ checked+=1024
block = f.read(b-ncuts*1024)
sha512func.update(block)
sha512sumcalc=sha512func.hexdigest()
@@ -220,36 +222,97 @@ class Dumper(object):
self.return_message +="\n" + _("The sha512 sum check is OK and the sum is signed")
else :
self.return_message +="\n" + _("The sha512 sum check is OK but the signature can't be found")
- else:
+ else:
self.return_message +="\n" + _("/!\\The computed and stored sums don't match")
#except:
#pass
self._progress = 100
-
+
logging.info(self.return_message)
self.return_state = True
self.finished.set()
- def _do_persistence(self, target, label):
+ def _do_persistence(self, target, label, key):
logging.debug("Start doing persistence partition")
p = Popen(["fdisk",target], stdin = PIPE)
p.communicate(input=b'n\np\n3\n\n\nw\n')
# example mkfs.ext4 -L mgalive-persist /dev/sdf3
- process = Popen(['mkfs.ext4','-L', label, target+"3"])
- working=True
- while working:
- time.sleep(0.5)
- process.poll()
- rc=process.returncode
- if rc is None:
- working=True
- else:
- process = None
- working= False
- logging.debug("Persistence partition done")
+
+ if key == "":
+ print("No key provided", file=sys.stderr)
+ process = Popen(['mkfs.ext4','-L', label, target+"3"])
+ p.communicate()
+ working=True
+ while working:
+ time.sleep(0.5)
+ process.poll()
+ rc=process.returncode
+ if rc is None:
+ working=True
+ else:
+ process = None
+ working= False
+ logging.debug("Persistence partition done")
+ else:
+ # cryptsetup luksFormat /dev/sdb3
+ print("Crypt key provided",file=sys.stderr)
+ base_target = os.path.basename(target) + "3"
+ process = Popen(['cryptsetup','luksFormat','-q', target+"3", '-d', '-'],stdin=PIPE)
+ process.communicate(input=key.encode('utf-8'))
+ working=True
+ while working:
+ time.sleep(0.5)
+ process.poll()
+ rc=process.returncode
+ if rc is None:
+ working=True
+ else:
+ process = None
+ working= False
+ # cryptsetup open /dev/sdb3 crypt_sdb3
+
+ process = Popen(['cryptsetup','luksOpen', target + "3", 'crypt_' + base_target ,'-d','-'],stdin=PIPE)
+ process.communicate(input=key.encode('utf-8'))
+ working=True
+ while working:
+ time.sleep(0.5)
+ process.poll()
+ rc=process.returncode
+ if rc is None:
+ working=True
+ else:
+ process = None
+ working= False
+ # mkfs.ext4 -L mgalive-persist /dev/mapper/crypt_sdb3
+ process = Popen(['mkfs.ext4','-L', label, '/dev/mapper/crypt_' + base_target])
+ process.communicate()
+ working=True
+ while working:
+ time.sleep(0.5)
+ process.poll()
+ rc=process.returncode
+ if rc is None:
+ working=True
+ else:
+ process = None
+ working= False
+ # cryptsetup close crypt_sdb3
+
+ process = Popen(['cryptsetup','luksClose', 'crypt_' + base_target ])
+ process.communicate()
+ working=True
+ while working:
+ time.sleep(0.5)
+ process.poll()
+ rc=process.returncode
+ if rc is None:
+ working=True
+ else:
+ process = None
+ working= False
return rc
-
+
def __init__(self):
gettext.install('isodumper', localedir='/usr/share/locale')
diff --git a/lib/isodumper.py b/lib/isodumper.py
index 785c996..23c506b 100755
--- a/lib/isodumper.py
+++ b/lib/isodumper.py
@@ -116,7 +116,7 @@ class Info(object):
self.richtext=richtext
self.text=text
-
+
class IsoDumper(object):
RELEASE="v1.15"
@@ -212,12 +212,14 @@ class IsoDumper(object):
self.progress.setDisabled()
self.refreshbt.setEnabled()
self.persistencecb.setDisabled()
+ self.cryptcb.setDisabled()
+ self.cryptkey.setDisabled()
def onProgress(self, frac):
self.logger(_('Wrote: {}% '.format(frac)))
self.progress.setValue(frac)
self.dialog.pollEvent()
-
+
def raw_format(self, usb_path, fstype, label):
self.operation=True
if os.geteuid() > 0:
@@ -310,7 +312,6 @@ class IsoDumper(object):
success, message = iface.do_unmount(target)
if success:
#Writing step
- #Dump mode
iface.do_write(source, target, b)
iface.get_sum(source)
progress = iface.progress
@@ -324,8 +325,8 @@ class IsoDumper(object):
self.logger(_('Image {source} successfully written to {target}').format( source=source.split('/')[-1], target=target))
self.logger(_('Bytes written: ')+str(b))
self.progress.setLabel(_('Checking ')+target.split('/')[-1])
- self.progress.setValue(0)
- self.dialog.pollEvent()
+ self.progress.setValue(0)
+ self.dialog.pollEvent()
# Checking
iface.check_write(target, source)
progress = iface.progress
@@ -340,13 +341,20 @@ class IsoDumper(object):
self.dialog.pollEvent()
self.logger(message)
# Add persistent partition if asked
- if self.persistencecb.value():
+ if self.persistencecb.isChecked():
self.logger(_("Adding persistent partition"))
- iface.do_persistence(target,"mgalive-persist")
- self.logger(_("Added persistent partition"))
+ if self.cryptcb.isChecked():
+ if self.cryptkey.value() == "":
+ self.logger(_("No key for crypted partition provided. Adding the partition aborted."))
+ else:
+ iface.do_persistence(target,"mgalive-persist",self.cryptkey.value())
+ self.logger(_("Added crypted persistent partition"))
+ else:
+ iface.do_persistence(target,"mgalive-persist", "")
+ self.logger(_("Added persistent partition"))
#Eject
self.u.eject(target)
- self.success()
+ self.success()
else:
self.emergency(message)
else:
@@ -401,7 +409,7 @@ class IsoDumper(object):
self.backupbt.setDisabled()
self.refreshbt.setDisabled()
self.persistencecb.setDisabled()
-
+
def close(self):
self.write_logfile()
self.dialog.destroy()
@@ -473,13 +481,13 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
#TODO Read log level from command line
-
+
# define size of the selected device
self.deviceSize=0
# Operation running
self.operation=False
-
+
self.ChooseImage = _("Choose an image")
self.warning = _("Warning\nThis will destroy all data on the target device,\n\
are you sure you want to proceed?\n\
@@ -528,8 +536,17 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
self.writebt = self.atelier.createPushButton(self.writebox, _("&Write to device" ))
self.writebt.setDisabled()
self.persistencebox = self.atelier.createHBox(self.box)
- self.persistencecb = self.atelier.createCheckBox(self.persistencebox, _("Add a persistent partition in the remaining space"))
+ self.persistencecol1 = self.atelier.createVBox(self.persistencebox)
+ self.persistencecol2 = self.atelier.createVBox(self.persistencebox)
+ self.persistencecb = self.atelier.createCheckBox(self.persistencecol1, _("Add a persistent partition in the remaining space"))
+ self.persistencebox2 = self.atelier.createHBox(self.box)
+ self.cryptcb = self.atelier.createCheckBox(self.persistencecol1, _("Crypt partition"))
+ self.cryptkey = self.atelier.createInputField(self.persistencecol2, _("Key:"))
self.persistencecb.setDisabled()
+ self.persistencecb.setNotify()
+ self.cryptcb.setDisabled()
+ self.cryptcb.setNotify()
+ self.cryptkey.setDisabled()
self.backupbox = self.atelier.createHBox(self.box)
self.atelier.createLabel(self.backupbox,_("Backup to:"))
# add file picker for backup file name
@@ -576,7 +593,7 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
self.ancrage.showChild()
def ask_format(self):
- atelier = yui.YUI.widgetFactory()
+ atelier = yui.YUI.widgetFactory()
dialog = atelier.createPopupDialog()
# dialog.setTitle(_("Choose format"))
vb=atelier.createVBox(dialog)
@@ -626,7 +643,7 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
return True,format_type,format_label
else:
return False," "," "
-
+
def ask_OK(self, info):
yui.YUI.widgetFactory
@@ -655,7 +672,7 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
dlg = mgafactory.createAboutDialog("Isodumper", self.RELEASE, "GPLv2",
_("Oliver Grawert<BR />Papoteur<BR />Pictures : Timothée Giet"), _("A tool for writing ISO images to a device")+"<BR />http://gitweb.mageia.org/software/isodumper", "")
dlg.show();
-
+
def nodevDialog(self):
yui.YUI.widgetFactory
mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga"))
@@ -685,6 +702,19 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
self.writebt.setEnabled()
self.activate_devicelist()
self.persistencecb.setEnabled()
+ if event.widget() == self.persistencecb:
+ print(self.persistencecb.value)
+ if self.persistencecb.isChecked() :
+ self.cryptcb.setEnabled()
+ else:
+ self.cryptcb.setDisabled()
+ self.cryptkey.setDisabled()
+ self.cryptcb.setChecked(False)
+ if event.widget() == self.cryptcb:
+ if self.cryptcb.isChecked() :
+ self.cryptkey.setEnabled()
+ else:
+ self.cryptkey.setDisabled()
if event.widget() == self.writebt:
self.wip_unsensitive()
self.do_write()
@@ -728,7 +758,7 @@ NTFS or ext. You can specify a volume name and the format in a new dialog box.<B
except Exception as e:
print(str(e))
yui.YDialog.deleteAllDialogs()
-
+
if __name__ == "__main__":
app = IsoDumper()
@@ -736,4 +766,3 @@ if __name__ == "__main__":
# next line seems to be a workaround to prevent the qt-app from crashing
# see https://github.com/libyui/libyui-qt/issues/41
yui.YUILoader.deleteUI()
-