output of log action fixed
added some RFCs added some unittests for CryptoBox config handling
This commit is contained in:
parent
3b97f675bf
commit
3fd2064439
5 changed files with 139 additions and 86 deletions
|
@ -34,6 +34,11 @@ class CryptoBox:
|
||||||
put things like logging, conf and oter stuff in here,
|
put things like logging, conf and oter stuff in here,
|
||||||
that might be used by more classes, it will be passed on to them'''
|
that might be used by more classes, it will be passed on to them'''
|
||||||
def __init__(self, config_file=None):
|
def __init__(self, config_file=None):
|
||||||
|
# choose an exit function
|
||||||
|
if __name__ == "__main__":
|
||||||
|
self.errorExit = self.errorExitProg
|
||||||
|
else:
|
||||||
|
self.errorExit = self.errorExitMod
|
||||||
self.__initLogging()
|
self.__initLogging()
|
||||||
self.__initPreferences(config_file)
|
self.__initPreferences(config_file)
|
||||||
self.__runTests()
|
self.__runTests()
|
||||||
|
@ -60,7 +65,7 @@ class CryptoBox:
|
||||||
self.log.info("loggingsystem is up'n running")
|
self.log.info("loggingsystem is up'n running")
|
||||||
## from now on everything can be logged via self.log...
|
## from now on everything can be logged via self.log...
|
||||||
except:
|
except:
|
||||||
sys.errorExit("SystemError","Couldn't initialise the loggingsystem. I give up.")
|
self.errorExit("SystemError","Couldn't initialise the loggingsystem. I give up.")
|
||||||
|
|
||||||
|
|
||||||
def __initPreferences(self, config_file):
|
def __initPreferences(self, config_file):
|
||||||
|
@ -99,19 +104,24 @@ class CryptoBox:
|
||||||
self.cbxPrefs["Main"]["NameDatabase"])
|
self.cbxPrefs["Main"]["NameDatabase"])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.errorExit("ConfigError","could not find one of these configuration settings: [Main]->DataDir and [Main]->NameDatabase - please check your config file(%s)" % config_file)
|
self.errorExit("ConfigError","could not find one of these configuration settings: [Main]->DataDir and [Main]->NameDatabase - please check your config file(%s)" % config_file)
|
||||||
if os.path.exists(nameDB_file):
|
|
||||||
self.nameDB = configobj.ConfigObj(nameDB_file)
|
|
||||||
else:
|
|
||||||
self.nameDB = configobj.ConfigObj(nameDB_file, create_empty=True)
|
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
self.errorExit("ConfigError","Error during parsing of name database file (%s).\n" % (nameDB_file, ))
|
self.errorExit("ConfigError","Error during parsing of name database file (%s).\n" % (nameDB_file, ))
|
||||||
# TODO: check if nameDB file was created successfully?
|
## create nameDB is necessary
|
||||||
|
if os.path.exists(nameDB_file):
|
||||||
|
self.nameDB = configobj.ConfigObj(nameDB_file)
|
||||||
|
else:
|
||||||
|
self.nameDB = configobj.ConfigObj(nameDB_file, create_empty=True)
|
||||||
|
## check if nameDB file was created successfully?
|
||||||
|
if not os.path.exists(nameDB_file):
|
||||||
|
self.errorExit("ConfigError","failed to create name database (%s)" % nameDB_file)
|
||||||
# get the loglevel
|
# get the loglevel
|
||||||
try:
|
try:
|
||||||
log_level = self.cbxPrefs["Log"]["Level"].upper()
|
log_level = self.cbxPrefs["Log"]["Level"].upper()
|
||||||
log_level_avail = ["DEBUG", "INFO", "WARN", "ERROR"]
|
log_level_avail = ["DEBUG", "INFO", "WARN", "ERROR"]
|
||||||
if not log_level in log_level_avail:
|
if not log_level in log_level_avail:
|
||||||
self.errorExit("ConfigError","invalid log level: %s is not in %s" % (self.cbxPrefs["Log"]["Level"], log_level_avail))
|
self.errorExit("ConfigError","invalid log level: %s is not in %s" % (self.cbxPrefs["Log"]["Level"], log_level_avail))
|
||||||
|
except KeyError:
|
||||||
|
self.errorExit("ConfigError","could not find the configuration setting [Log]->Level in the config file (%s)" % config_file)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
self.errorExit("ConfigError","invalid log level: %s" % self.cbxPrefs["Log"]["Level"])
|
self.errorExit("ConfigError","invalid log level: %s" % self.cbxPrefs["Log"]["Level"])
|
||||||
try:
|
try:
|
||||||
|
@ -121,8 +131,9 @@ class CryptoBox:
|
||||||
self.errorExit("ConfigError","could not find a configuration setting: [Log]->Details - please check your config file(%s)" % config_file)
|
self.errorExit("ConfigError","could not find a configuration setting: [Log]->Details - please check your config file(%s)" % config_file)
|
||||||
new_handler.setFormatter(logging.Formatter('%(asctime)s %(module)s %(levelname)s: %(message)s'))
|
new_handler.setFormatter(logging.Formatter('%(asctime)s %(module)s %(levelname)s: %(message)s'))
|
||||||
self.log.addHandler(new_handler)
|
self.log.addHandler(new_handler)
|
||||||
# do not call parent's handlers
|
## do not call parent's handlers
|
||||||
self.log.propagate = False
|
self.log.propagate = False
|
||||||
|
## use 'getattr' as 'log_level' is a string
|
||||||
self.log.setLevel(getattr(logging,log_level))
|
self.log.setLevel(getattr(logging,log_level))
|
||||||
except IOError:
|
except IOError:
|
||||||
self.errorExit("ConfigError","could not open logfile: %s" % self.cbxPrefs["Log"]["Details"])
|
self.errorExit("ConfigError","could not open logfile: %s" % self.cbxPrefs["Log"]["Details"])
|
||||||
|
@ -130,6 +141,7 @@ class CryptoBox:
|
||||||
|
|
||||||
# do some initial checks
|
# do some initial checks
|
||||||
def __runTests(self):
|
def __runTests(self):
|
||||||
|
## try to run 'super' with 'CryptoBoxRootActions'
|
||||||
try:
|
try:
|
||||||
devnull = open(os.devnull, "w")
|
devnull = open(os.devnull, "w")
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -144,6 +156,8 @@ class CryptoBox:
|
||||||
"check"])
|
"check"])
|
||||||
except OSError:
|
except OSError:
|
||||||
self.errorExit("ConfigError","could not find: %s" % self.cbxPrefs["Programs"]["super"])
|
self.errorExit("ConfigError","could not find: %s" % self.cbxPrefs["Programs"]["super"])
|
||||||
|
except KeyError:
|
||||||
|
self.errorExit("ConfigError","could not find one of these configurations settings: [Programs]->super or [Programs]->CryptoBoxRootActions in the config file")
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
self.errorExit("ConfigError","Could not call CryptoBoxRootActions by 'super' - maybe you did not add the appropriate line to /etc/super.tab?")
|
self.errorExit("ConfigError","Could not call CryptoBoxRootActions by 'super' - maybe you did not add the appropriate line to /etc/super.tab?")
|
||||||
|
@ -210,6 +224,31 @@ class CryptoBoxProps(CryptoBox):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def getLogData(self, lines=None, maxSize=None):
|
||||||
|
"""get the most recent log entries of the cryptobox
|
||||||
|
|
||||||
|
the maximum number and size of these entries can be limited by 'lines' and 'maxSize'
|
||||||
|
"""
|
||||||
|
# return nothing if the currently selected log output is not a file
|
||||||
|
empty = [""]
|
||||||
|
try:
|
||||||
|
if self.cbxPrefs["Log"]["Destination"].upper() != "FILE": return empty
|
||||||
|
log_file = self.cbxPrefs["Log"]["Details"]
|
||||||
|
except KeyError:
|
||||||
|
self.log.error("could not evaluate one of the following config settings: [Log]->Destination or [Log]->Details")
|
||||||
|
return empty
|
||||||
|
try:
|
||||||
|
fd = open(log_file, "r")
|
||||||
|
if maxSize: content = fd.readlines(maxSize)
|
||||||
|
else: content = fd.readlines()
|
||||||
|
fd.close()
|
||||||
|
except IOError:
|
||||||
|
self.log.warn("failed to read the log file (%s)" % log_file)
|
||||||
|
return empty
|
||||||
|
if lines: content = content[-lines:]
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
def getContainerList(self, filterType=None, filterName=None):
|
def getContainerList(self, filterType=None, filterName=None):
|
||||||
"retrieve the list of all containers of this cryptobox"
|
"retrieve the list of all containers of this cryptobox"
|
||||||
try:
|
try:
|
||||||
|
@ -349,11 +388,6 @@ class CryptoBoxProps(CryptoBox):
|
||||||
except OSError:
|
except OSError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# choose an exit function
|
|
||||||
if __name__ == "__main__":
|
|
||||||
CryptoBox.errorExit = CryptoBox.errorExitProg
|
|
||||||
else:
|
|
||||||
CryptoBox.errorExit = CryptoBox.errorExitMod
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cb = CryptoBox()
|
cb = CryptoBox()
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#!/usr/bin/env python2.4
|
#!/usr/bin/env python2.4
|
||||||
|
|
||||||
"""
|
## check python version
|
||||||
TODO: implement "getCapacity"
|
|
||||||
"""
|
|
||||||
|
|
||||||
# check python version
|
|
||||||
import sys
|
import sys
|
||||||
(ver_major, ver_minor, ver_sub, ver_desc, ver_subsub) = sys.version_info
|
(ver_major, ver_minor, ver_sub, ver_desc, ver_subsub) = sys.version_info
|
||||||
if (ver_major < 2) or ((ver_major == 2) and (ver_minor < 4)):
|
if (ver_major < 2) or ((ver_major == 2) and (ver_minor < 4)):
|
||||||
|
@ -39,7 +35,7 @@ class CryptoBoxContainer:
|
||||||
__fsTypes = {
|
__fsTypes = {
|
||||||
"plain":["ext3", "ext2", "vfat", "reiser"],
|
"plain":["ext3", "ext2", "vfat", "reiser"],
|
||||||
"swap":["swap"]}
|
"swap":["swap"]}
|
||||||
"TODO: mehr Dateisystemtypen? / 'reiser' pruefen"
|
# TODO: more filesystem types? / check 'reiser'
|
||||||
|
|
||||||
__dmDir = "/dev/mapper"
|
__dmDir = "/dev/mapper"
|
||||||
|
|
||||||
|
@ -57,7 +53,6 @@ class CryptoBoxContainer:
|
||||||
|
|
||||||
|
|
||||||
def setName(self, new_name):
|
def setName(self, new_name):
|
||||||
"TODO: den Test-Code pruefen"
|
|
||||||
if new_name == self.name: return
|
if new_name == self.name: return
|
||||||
if self.isMounted():
|
if self.isMounted():
|
||||||
raise "VolumeIsActive", "the container must be inactive during renaming"
|
raise "VolumeIsActive", "the container must be inactive during renaming"
|
||||||
|
@ -148,6 +143,7 @@ class CryptoBoxContainer:
|
||||||
errorMsg = "Could not add a new luks key: %s - %s" % (output.strip(), errout.strip(), )
|
errorMsg = "Could not add a new luks key: %s - %s" % (output.strip(), errout.strip(), )
|
||||||
self.log.error(errorMsg)
|
self.log.error(errorMsg)
|
||||||
raise "ChangePasswordError", errorMsg
|
raise "ChangePasswordError", errorMsg
|
||||||
|
## retrieve the key slot we used for unlocking
|
||||||
keys_found = re.search(r'key slot (\d{1,3}) unlocked', output).groups()
|
keys_found = re.search(r'key slot (\d{1,3}) unlocked', output).groups()
|
||||||
if keys_found:
|
if keys_found:
|
||||||
keyslot = int(keys_found[0])
|
keyslot = int(keys_found[0])
|
||||||
|
|
|
@ -5,7 +5,7 @@ import CryptoBoxWebserverSites
|
||||||
try:
|
try:
|
||||||
import cherrypy
|
import cherrypy
|
||||||
except:
|
except:
|
||||||
print "could not import cherrypy module! Try apt-get install python-cherrypy."
|
print "Could not import the cherrypy module! Try 'apt-get install python-cherrypy'."
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
class CryptoBoxWebserver:
|
class CryptoBoxWebserver:
|
||||||
|
@ -17,6 +17,8 @@ class CryptoBoxWebserver:
|
||||||
#I currently have no idea how to cleanly extract the stylesheet path from
|
#I currently have no idea how to cleanly extract the stylesheet path from
|
||||||
#the config object without an extra CryptoBox.CryptoBoxProps instance.
|
#the config object without an extra CryptoBox.CryptoBoxProps instance.
|
||||||
#perhaps put config handling into a seperate class in CryptoBox.py?
|
#perhaps put config handling into a seperate class in CryptoBox.py?
|
||||||
|
# [l] why do we need to map the css manually? Shouldn't the whole
|
||||||
|
# www-data path be accessible anyway?
|
||||||
cherrypy.config.configMap.update(
|
cherrypy.config.configMap.update(
|
||||||
{
|
{
|
||||||
"/cryptobox.css": {
|
"/cryptobox.css": {
|
||||||
|
|
|
@ -3,6 +3,8 @@ import CryptoBoxWebserverSettings
|
||||||
import CryptoBoxWebserverRender
|
import CryptoBoxWebserverRender
|
||||||
website = CryptoBoxWebserverRender.CryptoBoxWebserverRender()
|
website = CryptoBoxWebserverRender.CryptoBoxWebserverRender()
|
||||||
|
|
||||||
|
# is it necessary to inherit these both classes?
|
||||||
|
# for clarity they should be just instanciated - or not?
|
||||||
class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettings.CryptoBoxWebserverSettings):
|
class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettings.CryptoBoxWebserverSettings):
|
||||||
'''
|
'''
|
||||||
url2func = {'index':'show_status','doc':'show_doc','logs':'show_log'}
|
url2func = {'index':'show_status','doc':'show_doc','logs':'show_log'}
|
||||||
|
@ -14,9 +16,11 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
The default site to render is 'show_status'.
|
The default site to render is 'show_status'.
|
||||||
Self.settings is filled by the following methodcall
|
Self.settings is filled by the following methodcall
|
||||||
thus every rendered site will get actual values from the configfile.
|
thus every rendered site will get actual values from the configfile.
|
||||||
After that the concrete site-method (e.g. doc) may set individual values.
|
After that the corresponding site-method (e.g. doc) may set individual values.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
# RFC: the following line somehow implicitly calls 'setSettings(self, self)'
|
||||||
|
# should it be that way? [l]
|
||||||
self.setSettings(self)
|
self.setSettings(self)
|
||||||
#self.settings
|
#self.settings
|
||||||
self.settings["Data.Action"] = action
|
self.settings["Data.Action"] = action
|
||||||
|
@ -29,7 +33,9 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
Every single site method has to call this before even looking
|
Every single site method has to call this before even looking
|
||||||
at url-given parameters.
|
at url-given parameters.
|
||||||
This has to be called manually, since I don't see any other way of
|
This has to be called manually, since I don't see any other way of
|
||||||
sanitizing input automatically for all sites.'''
|
sanitizing input automatically for all sites.
|
||||||
|
# RFC: why shouldn't it be called in __init__? [l]
|
||||||
|
'''
|
||||||
#TODO: generate languages from existing hdf files
|
#TODO: generate languages from existing hdf files
|
||||||
niceparams = { 'weblang': ('', 'de', 'en'),
|
niceparams = { 'weblang': ('', 'de', 'en'),
|
||||||
'loglevel': ('','info', 'warn', 'debug', 'error'),
|
'loglevel': ('','info', 'warn', 'debug', 'error'),
|
||||||
|
@ -38,7 +44,7 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
for evilkey in evilparams.keys():
|
for evilkey in evilparams.keys():
|
||||||
## if the param isn't in the niceparams list, ignore it
|
## if the param isn't in the niceparams list, ignore it
|
||||||
if not niceparams.get(evilkey):
|
if not niceparams.get(evilkey):
|
||||||
self.log.warn("irgnoring \"%s\"" % evilkey)
|
self.log.warn("ignoring \"%s\"" % evilkey)
|
||||||
return False
|
return False
|
||||||
#TODO: until now only a warning message is printed
|
#TODO: until now only a warning message is printed
|
||||||
## if the param has no such value, set it to a default (the first in the list)
|
## if the param has no such value, set it to a default (the first in the list)
|
||||||
|
@ -47,28 +53,33 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
#TODO: set it to: niceparams.get(evilkey)[0]))
|
#TODO: set it to: niceparams.get(evilkey)[0]))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def __check_config(self):
|
def __check_config(self):
|
||||||
#TODO
|
#TODO
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def __check_init_running(self):
|
def __check_init_running(self):
|
||||||
#TODO
|
#TODO
|
||||||
pass
|
pass
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
## put real sites down here and don't forget to expose the mat the end
|
## put real sites down here and don't forget to expose them at the end
|
||||||
|
|
||||||
def logs(self, loglevel=""):
|
def logs(self, loglevel=""):
|
||||||
'''displays a HTML version of the logfile
|
'''displays a HTML version of the logfile
|
||||||
|
|
||||||
The loglevel has to be set and nothing else, as we just log in
|
The loglevel has to be set and nothing else, as we just log in english.
|
||||||
english.
|
RFC: what does this mean? We still have to save the current language - or not?
|
||||||
Be awar not to name this method just "log" as it seems to be a
|
|
||||||
reserved word.'''
|
Be aware not to name this method just "log" as it seems to be a
|
||||||
|
reserved word.
|
||||||
|
# RFC: maybe it conflicts with CryptoBoxProps.log - which we inherited?
|
||||||
|
'''
|
||||||
self.__sanitize_input({"loglevel":loglevel})
|
self.__sanitize_input({"loglevel":loglevel})
|
||||||
self.__prepare("show_log")
|
self.__prepare("show_log")
|
||||||
import filehandling
|
import filehandling
|
||||||
self.settings["Data.Log"] = filehandling.read_file(self.settings["Log.Details"])
|
self.settings["Data.Log"] = "<br/>".join(self.getLogData(lines=30, maxSize=2000))
|
||||||
#TODO: give the logs a nice format for displaying as html
|
#TODO: give the logs a nice format for displaying as html
|
||||||
# sed s/$/<\/br>/
|
# sed s/$/<\/br>/
|
||||||
return website.render(self)
|
return website.render(self)
|
||||||
|
@ -90,46 +101,52 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
self.settings["Data.Action"] = "show_status"
|
self.settings["Data.Action"] = "show_status"
|
||||||
self.settings["Data.Redirect.Delay"] = "60"
|
self.settings["Data.Redirect.Delay"] = "60"
|
||||||
return website.render(self)
|
return website.render(self)
|
||||||
|
|
||||||
|
|
||||||
def config(self,weblang=""):
|
def config(self,weblang=""):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def doc(self,action="",page="",weblang=""):
|
def doc(self,action="",page="",weblang=""):
|
||||||
'''prints the offline wikipage
|
'''prints the offline wikipage
|
||||||
|
|
||||||
TODO: action is unnessessary, remove here and from all html
|
TODO: action is unnessessary, remove here and from all html
|
||||||
files in doc/html/[de|en]/*
|
files in doc/html/[de|en]/*
|
||||||
'''
|
'''
|
||||||
|
# RFC: sanitize?
|
||||||
self.__prepare("show_doc")
|
self.__prepare("show_doc")
|
||||||
if page:
|
if page:
|
||||||
self.settings["Data.Doc.Page"] = page
|
self.settings["Data.Doc.Page"] = page
|
||||||
if page == "":
|
if page == "":
|
||||||
self.settings["Data.Doc.Page"] ="CryptoBoxUser"
|
self.settings["Data.Doc.Page"] ="CryptoBoxUser"
|
||||||
if not weblang == "":
|
if not weblang == "":
|
||||||
|
# TODO: check if there is a 'weblang' translation available for the docs
|
||||||
self.settings["Settings.DocLang"] = weblang
|
self.settings["Settings.DocLang"] = weblang
|
||||||
return website.render(self)
|
return website.render(self)
|
||||||
|
|
||||||
def system(self,type=""):
|
|
||||||
|
def system(self,typeOfShutdown=""):
|
||||||
self.__prepare("form_system")
|
self.__prepare("form_system")
|
||||||
if type == "reboot":
|
if typeOfShutdown == "reboot":
|
||||||
self.settings["Data.Success"] = "ReBoot"
|
self.settings["Data.Success"] = "ReBoot"
|
||||||
self.settings["Data.Redirect.Action"] = "show_status"
|
self.settings["Data.Redirect.Action"] = "show_status"
|
||||||
self.settings["Data.Redirect.Delay"] = "180"
|
self.settings["Data.Redirect.Delay"] = "180"
|
||||||
self.log.info("TODO: call function for system reboot")
|
self.log.info("TODO: call function for system reboot")
|
||||||
elif type == "poweroff":
|
elif typeOfShutdown == "poweroff":
|
||||||
self.settings["Data.Success"] = "PowerOff"
|
self.settings["Data.Success"] = "PowerOff"
|
||||||
self.log.info("TODO: call function for system shutdown")
|
self.log.info("TODO: call function for system shutdown")
|
||||||
else:
|
else:
|
||||||
self.log.warn("someone tried to shutdown the system")
|
self.log.warn("someone tried to shutdown the system in a broken way (%s)" % typeOfShutdown)
|
||||||
return website.render(self)
|
return website.render(self)
|
||||||
|
|
||||||
|
|
||||||
def index(self):
|
def index(self):
|
||||||
self.__prepare("show_status")
|
self.__prepare("show_status")
|
||||||
return website.render(self)
|
return website.render(self)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
## DONE: this functions are pythonized
|
## DONE: these functions are pythonized
|
||||||
#################### show_log #######################
|
#################### show_log #######################
|
||||||
##################### doc ############################
|
##################### doc ############################
|
||||||
##################### poweroff ######################
|
##################### poweroff ######################
|
||||||
|
@ -182,6 +199,7 @@ class CryptoBoxWebserverSites(CryptoBox.CryptoBoxProps, CryptoBoxWebserverSettin
|
||||||
#at cryptobox.pl line 568
|
#at cryptobox.pl line 568
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
## to make the sites visible through the webserver they must be exposed here
|
## to make the sites visible through the webserver they must be exposed here
|
||||||
index.exposed = True
|
index.exposed = True
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python2.4
|
#!/usr/bin/env python2.4
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
class CryptoBoxPropsDeviceTests(unittest.TestCase):
|
class CryptoBoxPropsDeviceTests(unittest.TestCase):
|
||||||
import CryptoBox
|
import CryptoBox
|
||||||
|
@ -34,49 +35,28 @@ class CryptoBoxPropsConfigTests(unittest.TestCase):
|
||||||
tmpdirname = ""
|
tmpdirname = ""
|
||||||
filenames = {}
|
filenames = {}
|
||||||
configContentOK = """
|
configContentOK = """
|
||||||
[Main]
|
[Main]
|
||||||
AllowedDevices = /dev/loop
|
AllowedDevices = /dev/loop
|
||||||
DefaultVolumePrefix = "Data "
|
DefaultVolumePrefix = "Data "
|
||||||
DataDir = %s
|
DataDir = %s
|
||||||
NameDatabase = cryptobox_names.db
|
NameDatabase = cryptobox_names.db
|
||||||
[System]
|
[System]
|
||||||
User = 1000
|
User = 1000
|
||||||
Group = 1000
|
Group = 1000
|
||||||
MountParentDir = %s/mnt
|
MountParentDir = %s/mnt
|
||||||
DefaultCipher = aes-cbc-essiv:sha256
|
DefaultCipher = aes-cbc-essiv:sha256
|
||||||
[Log]
|
[Log]
|
||||||
Level = debug
|
Level = debug
|
||||||
Destination = file
|
Destination = file
|
||||||
#Details = %s/cryptobox.log
|
Details = %s/cryptobox.log
|
||||||
Details = /tmp/cryptobox.log
|
[Programs]
|
||||||
[Programs]
|
blkid = /sbin/blkid
|
||||||
blkid = /sbin/blkid
|
cryptsetup = /sbin/cryptsetup
|
||||||
cryptsetup = /sbin/cryptsetup
|
super = /usr/bin/super
|
||||||
super = /usr/bin/super
|
CryptoBoxRootActions = CryptoBoxRootActions
|
||||||
CryptoBoxRootActions = CryptoBoxRootActions"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
configContentBroken = """
|
|
||||||
[Main]
|
|
||||||
AllowedDevices = /dev/loop
|
|
||||||
DefaultVolumePrefix = "Data "
|
|
||||||
#DataDir = %s
|
|
||||||
NameDatabase = cryptobox_names.db
|
|
||||||
[System]
|
|
||||||
User = 1000
|
|
||||||
Group = 1000
|
|
||||||
MountParentDir = %s/mnt
|
|
||||||
DefaultCipher = aes-cbc-essiv:sha256
|
|
||||||
[Log]
|
|
||||||
Level = debug
|
|
||||||
Destination = file
|
|
||||||
#Details = %s/cryptobox.log
|
|
||||||
Details = /tmp/cryptobox.log
|
|
||||||
[Programs]
|
|
||||||
blkid = /sbin/blkid
|
|
||||||
cryptsetup = /sbin/cryptsetup
|
|
||||||
super = /usr/bin/super
|
|
||||||
CryptoBoxRootActions = CryptoBoxRootActions"""
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
'''generate all files in tmp and remember the names'''
|
'''generate all files in tmp and remember the names'''
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -84,12 +64,7 @@ class CryptoBoxPropsConfigTests(unittest.TestCase):
|
||||||
self.tmpdirname = tempfile.mkdtemp(prefix="cbox-")
|
self.tmpdirname = tempfile.mkdtemp(prefix="cbox-")
|
||||||
for file in self.files.keys():
|
for file in self.files.keys():
|
||||||
self.filenames[file] = os.path.join(self.tmpdirname, self.files[file])
|
self.filenames[file] = os.path.join(self.tmpdirname, self.files[file])
|
||||||
cf = open(self.filenames["configFileOK"], "w")
|
self.writeConfig()
|
||||||
cf.write(self.configContentOK % (self.tmpdirname, self.tmpdirname, self.tmpdirname))
|
|
||||||
cf.close()
|
|
||||||
cf = open(self.filenames["configFileBroken"], "w")
|
|
||||||
cf.write(self.configContentBroken % (self.tmpdirname, self.tmpdirname, self.tmpdirname))
|
|
||||||
cf.close()
|
|
||||||
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -106,15 +81,43 @@ class CryptoBoxPropsConfigTests(unittest.TestCase):
|
||||||
|
|
||||||
def testConfigInit(self):
|
def testConfigInit(self):
|
||||||
'''Check various branches of config file loading'''
|
'''Check various branches of config file loading'''
|
||||||
|
import os
|
||||||
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/invalid/path/to/config/file")
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/invalid/path/to/config/file")
|
||||||
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/etc/shadow")
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/etc/shadow")
|
||||||
self.CryptoBox.CryptoBoxProps()
|
for a in self.CryptoBox.CONF_LOCATIONS:
|
||||||
|
if os.path.exists(a): self.CryptoBox.CryptoBoxProps()
|
||||||
|
else: self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps)
|
||||||
self.CryptoBox.CryptoBoxProps(self.filenames["configFileOK"])
|
self.CryptoBox.CryptoBoxProps(self.filenames["configFileOK"])
|
||||||
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,[])
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,[])
|
||||||
|
|
||||||
|
def testBrokenConfigs(self):
|
||||||
|
"""Check various broken configurations"""
|
||||||
|
self.writeConfig("NameDatabase", "#out", filename=self.filenames["configFileBroken"])
|
||||||
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
|
self.writeConfig("Level", "#out", filename=self.filenames["configFileBroken"])
|
||||||
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
|
self.writeConfig("Details", "#out", filename=self.filenames["configFileBroken"])
|
||||||
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
|
self.writeConfig("super", "super=/bin/invalid/no", filename=self.filenames["configFileBroken"])
|
||||||
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
|
self.writeConfig("CryptoBoxRootActions", "#not here", filename=self.filenames["configFileBroken"])
|
||||||
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
|
self.writeConfig("CryptoBoxRootActions", "CryptoBoxRootActions = /bin/false", filename=self.filenames["configFileBroken"])
|
||||||
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||||
# TODO: check details of different ConfigError-exceptions
|
# TODO: check details of different ConfigError-exceptions
|
||||||
# TODO: use different kind of broken setups ...
|
|
||||||
self.assertTrue(1)
|
|
||||||
|
def writeConfig(self, replace=None, newline=None, filename=None):
|
||||||
|
"""write a config file and (optional) replace a line in it"""
|
||||||
|
import re
|
||||||
|
if not filename: filename = self.filenames["configFileOK"]
|
||||||
|
content = self.configContentOK % (self.tmpdirname, self.tmpdirname, self.tmpdirname)
|
||||||
|
if replace:
|
||||||
|
pattern = re.compile('^' + replace + '\\s*=.*$', flags=re.M)
|
||||||
|
content = re.sub(pattern, newline, content)
|
||||||
|
cf = open(filename, "w")
|
||||||
|
cf.write(content)
|
||||||
|
cf.close()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Reference in a new issue