changed coding style according to pylint
This commit is contained in:
parent
f6295a4b2d
commit
fe69eb38ae
|
@ -31,6 +31,8 @@ Syntax:
|
|||
this script will always return with an exitcode 0 (true), if "check" is the only argument
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
|
|
@ -24,16 +24,42 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import os, sys
|
||||
import cryptobox.web.sites
|
||||
from cryptobox.core.exceptions import *
|
||||
from optparse import OptionParser
|
||||
|
||||
## check python version
|
||||
(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)):
|
||||
sys.stderr.write("You need a python version >= 2.4\n")
|
||||
sys.stderr.write("Current version is: %s\n" % sys.version)
|
||||
sys.exit(1)
|
||||
|
||||
## check cherrypy dependency
|
||||
try:
|
||||
import cherrypy
|
||||
except:
|
||||
print "Could not import the cherrypy module! Try 'apt-get install python-cherrypy'."
|
||||
sys.stderr.write("Could not import the cherrypy module!\n")
|
||||
sys.stderr.write("Try 'apt-get install python-cherrypy'.\n")
|
||||
sys.exit(1)
|
||||
|
||||
## check clearsilver dependency
|
||||
try:
|
||||
import neo_cgi, neo_util
|
||||
except:
|
||||
sys.stderr.write("Could not import the clearsilver module!\n")
|
||||
sys.stderr.write("Try 'apt-get install python-clearsilver'.\n")
|
||||
sys.exit(1)
|
||||
|
||||
## check configobj dependency
|
||||
try:
|
||||
import configobj, validate
|
||||
except:
|
||||
sys.stderr.write("Could not import the configobj or validate module!\n")
|
||||
sys.stderr.write("Try 'apt-get install python-configobj'.\n")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
@ -129,17 +155,22 @@ def close_open_files():
|
|||
|
||||
|
||||
def write_pid_file(pid_file):
|
||||
if os.path.exists(pid_file):
|
||||
sys.stderr.write(
|
||||
"Warning: pid file (%s) already exists - overwriting ...\n" % pid_file)
|
||||
try:
|
||||
pidf = open(pid_file,"w")
|
||||
pidf.write(str(os.getpid()))
|
||||
pidf.close()
|
||||
except (IOError, OSError), errMsg:
|
||||
sys.stderr.write("Warning: failed to write pid file (%s): %s\n" % (pid_file, errMsg))
|
||||
sys.stderr.write(
|
||||
"Warning: failed to write pid file (%s): %s\n" % (pid_file, errMsg))
|
||||
## it is just a warning - no need to break
|
||||
|
||||
|
||||
def parseOptions():
|
||||
version = "%prog" + cryptobox.core.main.VERSION
|
||||
import cryptobox
|
||||
version = "%prog" + cryptobox.__version__
|
||||
parser = OptionParser(version=version)
|
||||
parser.set_defaults(conffile="/etc/cryptobox-server/cryptobox.conf",
|
||||
pidfile="/var/run/cryptobox-server/webserver.pid",
|
||||
|
|
33
bin/do_pylint.sh
Executable file
33
bin/do_pylint.sh
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# set some environmental variables for pylint
|
||||
#
|
||||
|
||||
PROJ_DIR=$(dirname "$0")/..
|
||||
PROJ_DIR=$(cd "$PROJ_DIR"; pwd)
|
||||
|
||||
PYLINTRC=$PROJ_DIR/src/pylintrc
|
||||
PYTHONPATH=$PROJ_DIR/src
|
||||
|
||||
function check_for_filename()
|
||||
{
|
||||
# maybe the argument is a file instead of a module name
|
||||
if echo "$1" | grep -q "\.py$" && test -e "$1"
|
||||
then local FILE_DIR=$(dirname "$1")
|
||||
local MODULE=$(basename "${1%.py}")
|
||||
ARGS="${ARGS} ${MODULE}"
|
||||
PYTHONPATH="${PYTHONPATH}:${FILE_DIR}"
|
||||
else ARGS="${ARGS} ${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
while test $# -gt 0
|
||||
do check_for_filename "$1"
|
||||
shift
|
||||
done
|
||||
|
||||
export PYTHONPATH
|
||||
export PYLINTRC
|
||||
|
||||
pylint $ARGS
|
||||
|
19
debian/cryptobox-server.init
vendored
19
debian/cryptobox-server.init
vendored
|
@ -16,7 +16,6 @@
|
|||
# Short-Description: start CryptoBox webserver
|
||||
### END INIT INFO
|
||||
|
||||
|
||||
# read the default setting file, if it exists
|
||||
[ -r /etc/default/cryptobox-server ] && source /etc/default/cryptobox-server
|
||||
|
||||
|
@ -33,6 +32,7 @@ CONF_FILE=/etc/cryptobox-server/cryptobox.conf
|
|||
[ "$NO_START" = "1" ] && exit 0
|
||||
|
||||
DAEMON=/usr/sbin/CryptoBoxWebserver
|
||||
PYTHON_EXEC=/usr/bin/python
|
||||
PIDFILE=/var/run/cryptobox-server/webserver.pid
|
||||
DESC="CryptoBox Daemon (webinterface)"
|
||||
OPTIONS="-B --pidfile=$PIDFILE --config=$CONF_FILE --logfile=$LOGFILE --host=$HOST --port=$PORT $SERVER_OPTS"
|
||||
|
@ -45,11 +45,7 @@ test -e "$DAEMON" || exit 0
|
|||
|
||||
case "$1" in
|
||||
start )
|
||||
# TODO: mount config dir
|
||||
# TODO: create certificate
|
||||
# TODO: run stunnel
|
||||
# the lines above should go into the live-cd scripts
|
||||
## create the directory of the pid file if necessary
|
||||
# create the directory of the pid file if necessary
|
||||
PIDDIR=$(dirname "$PIDFILE")
|
||||
if [ -d "$PIDDIR" ]
|
||||
then mkdir -p "$PIDDIR"
|
||||
|
@ -60,14 +56,21 @@ case "$1" in
|
|||
if start-stop-daemon \
|
||||
--chuid $RUNAS: --quiet --start \
|
||||
--user $RUNAS --pidfile "$PIDFILE" \
|
||||
--exec /usr/bin/python --startas "$DAEMON" -- $OPTIONS
|
||||
--startas "$PYTHON_EXEC" -- "$DAEMON" $OPTIONS
|
||||
then log_end_msg 0
|
||||
else log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
stop )
|
||||
log_daemon_msg "Stopping cryptobox webserver" "$DESC"
|
||||
if start-stop-daemon --quiet --stop \
|
||||
# if there is no pid file for some reason, then we try to find the process
|
||||
if test ! -e "$PIDFILE"
|
||||
then if start-stop-daemon --quiet --stop --user "$RUNAS" --exec "$PYTHON_EXEC"
|
||||
then log_end_msg 0
|
||||
else log_end_msg 1
|
||||
fi
|
||||
# there is a pid file - great!
|
||||
elif start-stop-daemon --quiet --stop \
|
||||
--pidfile "$PIDFILE" \
|
||||
--user "$RUNAS"
|
||||
then test -e "$PIDFILE" && rm "$PIDFILE"
|
||||
|
|
|
@ -18,29 +18,39 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Change date and time.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
|
||||
class date(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The date feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = False
|
||||
rank = 10
|
||||
|
||||
def doAction(self, store=None, year=0, month=0, day=0, hour=0, minute=0):
|
||||
def do_action(self, store=None, year=0, month=0, day=0, hour=0, minute=0):
|
||||
"""The action handler.
|
||||
"""
|
||||
import datetime
|
||||
if store:
|
||||
try:
|
||||
year, month, day = int(year), int(month), int(day)
|
||||
hour, minute = int(hour), int(minute)
|
||||
new_date = datetime.datetime(year, month, day, hour, minute)
|
||||
## check if the values are valid
|
||||
datetime.datetime(year, month, day, hour, minute)
|
||||
except ValueError:
|
||||
self.hdf["Data.Warning"] = "Plugins.date.InvalidDate"
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_date"
|
||||
date = "%02d%02d%02d%02d%d" % (month, day, hour, minute, year)
|
||||
if self.__setDate(date):
|
||||
if self.__set_date(date):
|
||||
self.cbox.log.info("changed date to: %s" % date)
|
||||
self.hdf["Data.Success"] = "Plugins.date.DateChanged"
|
||||
return None
|
||||
|
@ -48,33 +58,42 @@ class date(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
## a failure should usually be an invalid date (we do not check it really)
|
||||
self.cbox.log.info("failed to set date: %s" % date)
|
||||
self.hdf["Data.Warning"] = "Plugins.date.InvalidDate"
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_date"
|
||||
else:
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_date"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
now = self.__getCurrentDate()
|
||||
return "%d/%d/%d/%d/%d/%d" % (now.year, now.month, now.day, now.hour, now.minute, now.second)
|
||||
def get_status(self):
|
||||
"""Retrieve the status of the feature.
|
||||
"""
|
||||
now = self.__get_current_date()
|
||||
return "%d/%d/%d/%d/%d/%d" % \
|
||||
(now.year, now.month, now.day, now.hour, now.minute, now.second)
|
||||
|
||||
|
||||
def __prepareFormData(self):
|
||||
date = self.__getCurrentDate()
|
||||
self.hdf[self.hdf_prefix + "year"] = date.year
|
||||
self.hdf[self.hdf_prefix + "month"] = date.month
|
||||
self.hdf[self.hdf_prefix + "day"] = date.day
|
||||
self.hdf[self.hdf_prefix + "hour"] = date.hour
|
||||
self.hdf[self.hdf_prefix + "minute"] = date.minute
|
||||
def __prepare_form_data(self):
|
||||
"""Set some hdf values.
|
||||
"""
|
||||
cur_date = self.__get_current_date()
|
||||
self.hdf[self.hdf_prefix + "year"] = cur_date.year
|
||||
self.hdf[self.hdf_prefix + "month"] = cur_date.month
|
||||
self.hdf[self.hdf_prefix + "day"] = cur_date.day
|
||||
self.hdf[self.hdf_prefix + "hour"] = cur_date.hour
|
||||
self.hdf[self.hdf_prefix + "minute"] = cur_date.minute
|
||||
|
||||
|
||||
def __getCurrentDate(self):
|
||||
def __get_current_date(self):
|
||||
"""Retrieve the current date and time.
|
||||
"""
|
||||
import datetime
|
||||
return datetime.datetime(2000,1,1).now()
|
||||
return datetime.datetime(2000, 1, 1).now()
|
||||
|
||||
|
||||
def __setDate(self, date):
|
||||
def __set_date(self, date):
|
||||
"""Set a new date and time.
|
||||
"""
|
||||
import subprocess
|
||||
import os
|
||||
proc = subprocess.Popen(
|
||||
|
@ -83,7 +102,7 @@ class date(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
date])
|
||||
proc.wait()
|
||||
return proc.returncode == 0
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
|
||||
PLUGIN_TYPE = "cryptobox"
|
||||
|
|
|
@ -18,18 +18,20 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_get_date(self):
|
||||
"""retrieve the current date"""
|
||||
date = self._getCurrentDate()
|
||||
date = self._get_current_date()
|
||||
|
||||
|
||||
def test_change_date(self):
|
||||
"""set the date back and forth"""
|
||||
now = self._getCurrentDate()
|
||||
now = self._get_current_date()
|
||||
## copy current time
|
||||
new_date = dict(now)
|
||||
## move three minutes forward (more is not nice because of screensavers)
|
||||
|
@ -38,10 +40,10 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
new_date["hour"] = now["hour"] + ((now["minute"] + 3) / 60)
|
||||
## move forward ...
|
||||
self._setDate(new_date)
|
||||
self.assertEquals(new_date, self._getCurrentDate())
|
||||
self.assertEquals(new_date, self._get_current_date())
|
||||
## ... and backward
|
||||
self._setDate(now)
|
||||
self.assertEquals(now, self._getCurrentDate())
|
||||
self.assertEquals(now, self._get_current_date())
|
||||
|
||||
|
||||
def test_try_broken_date(self):
|
||||
|
@ -54,8 +56,8 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
self.cmd.find("invalid value for date")
|
||||
|
||||
|
||||
def _getCurrentDate(self):
|
||||
date_url = self.URL + "date"
|
||||
def _get_current_date(self):
|
||||
date_url = self.url + "date"
|
||||
self.register_auth(date_url)
|
||||
self.cmd.go(date_url)
|
||||
self.cmd.find("Data.Status.Plugins.date=([0-9]+/[0-9]+/[0-9]+/[0-9]+/[0-9]+/[0-9]+)$", "m")
|
||||
|
@ -73,7 +75,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def _setDate(self, date):
|
||||
"""for now we have to use this function instead of the one below"""
|
||||
date_url = self.URL + "date?weblang=en&store=1&year=%s&month=%s&day=%s&hour=%s&minute=%s"\
|
||||
date_url = self.url + "date?weblang=en&store=1&year=%s&month=%s&day=%s&hour=%s&minute=%s"\
|
||||
% (str(date["year"]), str(date["month"]), str(date["day"]),
|
||||
str(date["hour"]), str(date["minute"]))
|
||||
self.register_auth(date_url)
|
||||
|
@ -83,7 +85,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
def _setDateBroken(self, date):
|
||||
"""this should work, but the parsing of twill seems to be broken
|
||||
as soon as the twill bug is fixed, we should use this function"""
|
||||
date_url = self.URL + "date"
|
||||
date_url = self.url + "date"
|
||||
self.register_auth(date_url)
|
||||
self.cmd.go(date_url)
|
||||
self.cmd.formvalue("set_date", "year", str(date["year"]))
|
||||
|
|
|
@ -18,21 +18,31 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""The disks feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
class disks(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The disk feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "menu" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "menu" ]
|
||||
request_auth = False
|
||||
rank = 10
|
||||
|
||||
def doAction(self):
|
||||
self.cbox.reReadContainerList()
|
||||
def do_action(self):
|
||||
"""The action handler.
|
||||
"""
|
||||
self.cbox.reread_container_list()
|
||||
return "disks"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return ":".join([e.getDevice() for e in self.cbox.getContainerList()])
|
||||
|
||||
def get_status(self):
|
||||
"""Retrieve the current status of the feature.
|
||||
"""
|
||||
return ":".join([e.get_device() for e in self.cbox.get_container_list()])
|
||||
|
||||
|
|
|
@ -18,24 +18,26 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
'''display all devices'''
|
||||
self.register_auth(self.URL)
|
||||
self.cmd.go(self.URL + "disks?weblang=en")
|
||||
self.register_auth(self.url)
|
||||
self.cmd.go(self.url + "disks?weblang=en")
|
||||
self.cmd.find("Available disks")
|
||||
|
||||
|
||||
def test_is_device_in_list(self):
|
||||
"""check if the device-under-test is in the device list"""
|
||||
self.register_auth(self.URL)
|
||||
self.cmd.go(self.URL + "disks?weblang=en")
|
||||
self.register_auth(self.url)
|
||||
self.cmd.go(self.url + "disks?weblang=en")
|
||||
self.cmd.find("Available disks")
|
||||
self.cmd.find(u'Data.Status.Plugins.disks=(.*)$', "m")
|
||||
devices = self.locals["__match__"].split(":")
|
||||
self.assertTrue(len(devices)>0)
|
||||
self.assertTrue(("/dev/%s1" % self.device in devices) or ("/dev/%s2" % self.device in devices))
|
||||
self.assertTrue("/dev/%s" % self.device in devices)
|
||||
|
||||
|
|
|
@ -18,26 +18,34 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""The help feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
class help(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The help feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "menu" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "menu" ]
|
||||
request_auth = False
|
||||
rank = 80
|
||||
|
||||
default_lang = 'en'
|
||||
default_page = "CryptoBoxUser"
|
||||
|
||||
def doAction(self, page=""):
|
||||
def do_action(self, page=""):
|
||||
'''prints the offline wikipage
|
||||
'''
|
||||
import re,os
|
||||
import re, os
|
||||
## check for invalid characters and if the page exists in the default language
|
||||
if page and \
|
||||
not re.search(u'\W', page) and \
|
||||
os.path.isfile(os.path.join(self.cbox.prefs["Locations"]["DocDir"], self.default_lang, page + '.html')):
|
||||
os.path.isfile(os.path.join(self.cbox.prefs["Locations"]["DocDir"],
|
||||
self.default_lang, page + '.html')):
|
||||
## everything is ok
|
||||
pass
|
||||
else:
|
||||
|
@ -49,20 +57,23 @@ class help(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
## store the name of the page
|
||||
self.hdf[self.hdf_prefix + "Page"] = page
|
||||
## choose the right language
|
||||
for l in self.site.langOrder:
|
||||
if os.path.isfile(os.path.join(self.cbox.prefs["Locations"]["DocDir"], l, page + '.html')):
|
||||
lang = l
|
||||
for lang in self.site.lang_order:
|
||||
if os.path.isfile(os.path.join(self.cbox.prefs["Locations"]["DocDir"],
|
||||
lang, page + '.html')):
|
||||
doc_lang = lang
|
||||
break
|
||||
else:
|
||||
lang = self.default_lang
|
||||
self.hdf[self.hdf_prefix + "Language"] = lang
|
||||
doc_lang = self.default_lang
|
||||
self.hdf[self.hdf_prefix + "Language"] = doc_lang
|
||||
## store the current setting for a later "getStatus" call
|
||||
self.current_lang = lang
|
||||
self.current_lang = doc_lang
|
||||
self.current_page = page
|
||||
return "doc"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
"""Retrieve the current status of the feature.
|
||||
"""
|
||||
return "%s:%s" % (self.current_lang, self.current_page)
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
from twill.errors import *
|
||||
|
||||
|
@ -27,7 +29,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
'''help pages should be available in different languages'''
|
||||
|
||||
## check english help pages
|
||||
self.cmd.go(self.URL + "help?weblang=en")
|
||||
self.cmd.go(self.url + "help?weblang=en")
|
||||
self.cmd.find("Table of Contents")
|
||||
self.cmd.find("Getting started")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
|
@ -35,7 +37,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
## check german help pages
|
||||
self.cmd.go(self.URL + "help?weblang=de")
|
||||
self.cmd.go(self.url + "help?weblang=de")
|
||||
self.cmd.find("Table of Contents")
|
||||
self.cmd.find("Wie geht es los")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
|
@ -43,7 +45,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
## check slovene help pages
|
||||
self.cmd.go(self.URL + "help?weblang=sl")
|
||||
self.cmd.go(self.url + "help?weblang=sl")
|
||||
self.assertRaises(TwillAssertionError, self.cmd.notfind, "Table of Contents")
|
||||
## add a slovene text here, as soon as the help is translated
|
||||
(lang,page) = self._getHelpStatus()
|
||||
|
@ -52,7 +54,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
## check french help pages
|
||||
self.cmd.go(self.URL + "help?weblang=fr")
|
||||
self.cmd.go(self.url + "help?weblang=fr")
|
||||
self.assertRaises(TwillAssertionError, self.cmd.notfind, "Table of Contents")
|
||||
## add a french text here, as soon as the help is translated
|
||||
(lang,page) = self._getHelpStatus()
|
||||
|
@ -61,7 +63,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
## test a random language - it should fall back to english
|
||||
self.cmd.go(self.URL + "help?weblang=foobar")
|
||||
self.cmd.go(self.url + "help?weblang=foobar")
|
||||
self.assertRaises(TwillAssertionError, self.cmd.notfind, "Table of Contents")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
self.assertTrue(lang == "en")
|
||||
|
@ -70,18 +72,18 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_help_pages(self):
|
||||
"""check invalid page requests"""
|
||||
self.cmd.go(self.URL + "help?page=foobar")
|
||||
self.cmd.go(self.url + "help?page=foobar")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
self.cmd.go(self.URL + "help?page=CryptoBoxUser")
|
||||
self.cmd.go(self.url + "help?page=CryptoBoxUser")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
self.assertTrue(page == "CryptoBoxUser")
|
||||
|
||||
|
||||
def test_help_default_languages(self):
|
||||
"""check invalid page requests"""
|
||||
self.cmd.go(self.URL + "help?weblang=foobar")
|
||||
self.cmd.go(self.url + "help?weblang=foobar")
|
||||
(lang,page) = self._getHelpStatus()
|
||||
self.assertTrue(lang == "en")
|
||||
|
||||
|
|
|
@ -18,20 +18,31 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""The language_selection feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
|
||||
class language_selection(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The language_selection feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "menu", "preferences" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "menu", "preferences" ]
|
||||
request_auth = False
|
||||
rank = 60
|
||||
|
||||
def doAction(self):
|
||||
def do_action(self):
|
||||
"""Show all available languages.
|
||||
"""
|
||||
return "language_selection"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return ":".join(self.site.langOrder)
|
||||
def get_status(self):
|
||||
"""The current status of the feature is defined as the current language.
|
||||
"""
|
||||
return ":".join(self.site.lang_order)
|
||||
|
||||
|
|
|
@ -18,19 +18,21 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "language_selection?weblang=en"
|
||||
url = self.url + "language_selection?weblang=en"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('hoose an interface language')
|
||||
|
||||
|
||||
def test_check_language_list(self):
|
||||
url = self.URL + "language_selection"
|
||||
url = self.url + "language_selection"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find(u'Data.Status.Plugins.language_selection=(.*)$', "m")
|
||||
|
|
|
@ -18,56 +18,76 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
|
||||
"""The logs feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
import os
|
||||
|
||||
class logs(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The logs feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = False
|
||||
rank = 90
|
||||
|
||||
def doAction(self, lines=50, size=3000, pattern=None):
|
||||
def do_action(self, lines=50, size=3000, pattern=None):
|
||||
"""Show the latest part of the log file.
|
||||
"""
|
||||
import re
|
||||
## filter input
|
||||
try:
|
||||
lines = int(lines)
|
||||
if lines <= 0: raise(ValueError)
|
||||
if lines <= 0:
|
||||
raise(ValueError)
|
||||
except ValueError:
|
||||
lines = 50
|
||||
try:
|
||||
size = int(size)
|
||||
if size <= 0: raise(ValueError)
|
||||
if size <= 0:
|
||||
raise(ValueError)
|
||||
except ValueError:
|
||||
size = 3000
|
||||
if not pattern is None:
|
||||
pattern = str(pattern)
|
||||
if re.search(u'\W', pattern): pattern = None
|
||||
self.hdf[self.hdf_prefix + "Content"] = self.__getLogContent(lines, size, pattern)
|
||||
self.hdf[self.hdf_prefix + "StyleSheetFile"] = os.path.abspath(os.path.join(self.pluginDir, "logs.css"))
|
||||
if re.search(u'\W', pattern):
|
||||
pattern = None
|
||||
self.hdf[self.hdf_prefix + "Content"] = self.__get_log_content(
|
||||
lines, size, pattern)
|
||||
self.hdf[self.hdf_prefix + "StyleSheetFile"] = os.path.abspath(os.path.join(
|
||||
self.plugin_dir, "logs.css"))
|
||||
return "show_log"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
"""The current status includes the log configuration details.
|
||||
"""
|
||||
return "%s:%s:%s" % (
|
||||
self.cbox.prefs["Log"]["Level"],
|
||||
self.cbox.prefs["Log"]["Destination"],
|
||||
self.cbox.prefs["Log"]["Details"])
|
||||
|
||||
|
||||
def __getLogContent(self, lines, maxSize, pattern):
|
||||
import re
|
||||
def __get_log_content(self, lines, max_size, pattern):
|
||||
"""Filter, sort and shorten the log content.
|
||||
"""
|
||||
if pattern:
|
||||
content = []
|
||||
current_length = 0
|
||||
for line in self.cbox.getLogData():
|
||||
for line in self.cbox.get_log_data():
|
||||
if line.find(pattern) != -1:
|
||||
content.append(line)
|
||||
current_length += len(line)
|
||||
if lines and len(content) >=lines: break
|
||||
if maxSize and current_length >=maxSize: break
|
||||
if lines and len(content) >= lines:
|
||||
break
|
||||
if max_size and current_length >= max_size:
|
||||
break
|
||||
else:
|
||||
content = self.cbox.getLogData(lines, maxSize)
|
||||
content = self.cbox.get_log_data(lines, max_size)
|
||||
return "<br/>".join(content)
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_logs(self):
|
||||
log_url = self.URL + "logs"
|
||||
log_url = self.url + "logs"
|
||||
self.register_auth(log_url)
|
||||
self.cmd.go(log_url)
|
||||
self.cmd.find('class="console"')
|
||||
|
@ -31,13 +33,13 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
def test_write_logs(self):
|
||||
log_text = "unittest - just a marker - please ignore"
|
||||
self.cbox.log.error(log_text)
|
||||
log_url = self.URL + "logs"
|
||||
log_url = self.url + "logs"
|
||||
self.register_auth(log_url)
|
||||
self.cmd.go(log_url + "?pattern=ERROR")
|
||||
self.cmd.find(log_text)
|
||||
|
||||
def test_invalid_args(self):
|
||||
log_url = self.URL + "logs"
|
||||
log_url = self.url + "logs"
|
||||
self.cmd.go(log_url + "?lines=10")
|
||||
self.cmd.find('class="console"')
|
||||
self.cmd.go(log_url + "?lines=0")
|
||||
|
|
|
@ -18,23 +18,32 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""The network feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import cryptobox.plugins.base
|
||||
|
||||
|
||||
## specify (in seconds), how long we should wait before redirecting and ip change
|
||||
REDIRECT_DELAY=20
|
||||
CHANGE_IP_DELAY=1
|
||||
REDIRECT_DELAY = 10
|
||||
CHANGE_IP_DELAY = 2
|
||||
|
||||
class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The network feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = True
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = True
|
||||
rank = 30
|
||||
|
||||
def doAction(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""):
|
||||
def do_action(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""):
|
||||
"""Show a form containing the current IP - change it if requested.
|
||||
"""
|
||||
## if we were redirected, then we should display the default page
|
||||
self.cbox.log.debug("executing network plugin")
|
||||
if redirected == "1":
|
||||
|
@ -46,58 +55,68 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
try:
|
||||
for ip_in in (ip1, ip2, ip3, ip4):
|
||||
if (int(ip_in) < 0) or (int(ip_in) > 255):
|
||||
self.cbox.log.info("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4)))
|
||||
self.cbox.log.info("invalid IP supplied: %s" % \
|
||||
str((ip1, ip2, ip3, ip4)))
|
||||
raise ValueError
|
||||
ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
|
||||
new_ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
|
||||
except ValueError:
|
||||
self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_network"
|
||||
if self.__setIP(ip):
|
||||
self.cbox.log.info("the IP was successfully changed: %s" % ip)
|
||||
if self.__set_ip(new_ip):
|
||||
self.cbox.log.info("the IP was successfully changed: %s" % new_ip)
|
||||
self.hdf["Data.Success"] = "Plugins.network.IPChanged"
|
||||
self.hdf["Data.Redirect.URL"] = self.__getRedirectDestination(ip)
|
||||
self.hdf["Data.Redirect.URL"] = self.__get_redirect_destination(new_ip)
|
||||
self.hdf["Data.Redirect.Delay"] = REDIRECT_DELAY
|
||||
return None
|
||||
else:
|
||||
self.cbox.log.warn("failed to change IP address to: %s" % ip)
|
||||
self.cbox.log.warn("failed to change IP address to: %s" % new_ip)
|
||||
self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_network"
|
||||
else:
|
||||
self.cbox.log.debug("network plugin: show form")
|
||||
## just show the form
|
||||
self.__prepareFormData()
|
||||
self.__prepare_form_data()
|
||||
return "form_network"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return "%d.%d.%d.%d" % self.__getCurrentIP()
|
||||
def get_status(self):
|
||||
"""The current IP is the status of this feature.
|
||||
"""
|
||||
return "%d.%d.%d.%d" % self.__get_current_ip()
|
||||
|
||||
|
||||
def __getRedirectDestination(self, ip):
|
||||
def __get_redirect_destination(self, ip):
|
||||
"""Put the new URL together.
|
||||
"""
|
||||
import cherrypy
|
||||
req = cherrypy.request
|
||||
base_parts = req.base.split(":")
|
||||
dest = "%s:%s" % (base_parts[0], ip)
|
||||
dest = "%s://%s" % (base_parts[0], ip)
|
||||
if len(base_parts) == 3:
|
||||
dest += ":%s" % base_parts[2]
|
||||
return dest
|
||||
|
||||
|
||||
def __prepareFormData(self):
|
||||
(oc1, oc2, oc3, oc4) = self.__getCurrentIP()
|
||||
def __prepare_form_data(self):
|
||||
"""Set some hdf values.
|
||||
"""
|
||||
(oc1, oc2, oc3, oc4) = self.__get_current_ip()
|
||||
self.hdf[self.hdf_prefix + "ip.oc1"] = oc1
|
||||
self.hdf[self.hdf_prefix + "ip.oc2"] = oc2
|
||||
self.hdf[self.hdf_prefix + "ip.oc3"] = oc3
|
||||
self.hdf[self.hdf_prefix + "ip.oc4"] = oc4
|
||||
|
||||
|
||||
def __getCurrentIP(self):
|
||||
def __get_current_ip(self):
|
||||
"""Retrieve the current IP.
|
||||
"""
|
||||
import re
|
||||
import imp
|
||||
## load some values from the root_action.py script
|
||||
root_action_plug = imp.load_source("root_action", os.path.join(self.pluginDir, "root_action.py"))
|
||||
root_action_plug = imp.load_source("root_action",
|
||||
os.path.join(self.plugin_dir, "root_action.py"))
|
||||
## get the current IP of the network interface
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
|
@ -106,20 +125,25 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
root_action_plug.IFCONFIG_BIN,
|
||||
root_action_plug.IFACE])
|
||||
(stdout, stderr) = proc.communicate()
|
||||
if proc.returncode != 0: return (0,0,0,0)
|
||||
if proc.returncode != 0:
|
||||
return (0,0,0,0)
|
||||
## this regex matches the four numbers of the IP
|
||||
match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s', stdout)
|
||||
if match:
|
||||
## use the previously matched numbers
|
||||
return tuple([int(e) for e in match.groups()])
|
||||
else:
|
||||
return (0,0,0,0)
|
||||
return (0, 0, 0, 0)
|
||||
|
||||
|
||||
def __setIP(self, ip):
|
||||
def __set_ip(self, new_ip):
|
||||
"""Change the IP.
|
||||
"""
|
||||
import threading
|
||||
## call the root_action script after some seconds - so we can deliver the page before
|
||||
def delayedIPchange():
|
||||
def delayed_ip_change():
|
||||
"""A threaded function to change the IP.
|
||||
"""
|
||||
import time
|
||||
time.sleep(CHANGE_IP_DELAY)
|
||||
proc = subprocess.Popen(
|
||||
|
@ -129,19 +153,17 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
ip])
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
new_ip])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
self.cbox.log.warn("failed to change IP address: %s" % ip)
|
||||
self.cbox.log.warn("failed to change IP address: %s" % new_ip)
|
||||
self.cbox.log.warn("error output: %s" % str(proc.stderr.read()))
|
||||
return
|
||||
thread = threading.Thread()
|
||||
thread.run = delayedIPchange
|
||||
thread.run = delayed_ip_change
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
# TODO: how could we guess, if it failed?
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
#TODO: add netmask and gateway
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
from network import CHANGE_IP_DELAY
|
||||
|
||||
|
@ -28,43 +30,47 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
'''change of network address'''
|
||||
## the time module is necessary for the CHANGE_IP_DELAY
|
||||
import time
|
||||
self.register_auth(self.URL + "network")
|
||||
self.cmd.go(self.URL + "network")
|
||||
self.register_auth(self.url + "network")
|
||||
## do not follow redirects - they would break the test otherwise
|
||||
self.cmd.config("acknowledge_equiv_refresh", 0)
|
||||
self.cmd.go(self.url + "network")
|
||||
## extract the current IP from the network plugin output
|
||||
def getCurrentIP():
|
||||
self.cmd.go(self.URL + "network")
|
||||
def get_current_ip():
|
||||
self.register_auth(self.url + "network")
|
||||
self.cmd.go(self.url + "network")
|
||||
self.cmd.find(u'Data.Status.Plugins.network=([0-9\.]*)$', "m")
|
||||
return self.locals["__match__"]
|
||||
origIPtext = getCurrentIP()
|
||||
origIPocts = origIPtext.split(".")
|
||||
orig_ip_text = get_current_ip()
|
||||
orig_ip_octs = orig_ip_text.split(".")
|
||||
## check, if the original IP is valid (contains four octets)
|
||||
self.assertEquals(4, len(origIPocts))
|
||||
wrongIP = "192.168.123.321"
|
||||
def setIP((ip1, ip2, ip3, ip4)):
|
||||
self.cmd.go(self.URL + "network")
|
||||
self.assertEquals(4, len(orig_ip_octs))
|
||||
def set_ip((ip1, ip2, ip3, ip4)):
|
||||
self.cmd.go(self.url + "network")
|
||||
self.cmd.formvalue("set_ip", "ip1", str(ip1))
|
||||
self.cmd.formvalue("set_ip", "ip2", str(ip2))
|
||||
self.cmd.formvalue("set_ip", "ip3", str(ip3))
|
||||
self.cmd.formvalue("set_ip", "ip4", str(ip4))
|
||||
self.cmd.submit()
|
||||
## sleep a little bit longer than the delay necessary for ip-change
|
||||
time.sleep(CHANGE_IP_DELAY + 0.2)
|
||||
setIP([1,-2,0,1])
|
||||
self.assertEquals(origIPtext, getCurrentIP())
|
||||
setIP([1,0,0,256])
|
||||
self.assertEquals(origIPtext, getCurrentIP())
|
||||
setIP([1,"foo",0,1])
|
||||
self.assertEquals(origIPtext, getCurrentIP())
|
||||
setIP([10,12,0,2])
|
||||
self.assertEquals("10.12.0.2", getCurrentIP())
|
||||
setIP(origIPocts)
|
||||
self.assertEquals(origIPtext, getCurrentIP())
|
||||
time.sleep(CHANGE_IP_DELAY + 3)
|
||||
set_ip([1,-2,0,1])
|
||||
self.assertEquals(orig_ip_text, get_current_ip())
|
||||
set_ip([1,0,0,256])
|
||||
self.assertEquals(orig_ip_text, get_current_ip())
|
||||
set_ip([1,"foo",0,1])
|
||||
self.assertEquals(orig_ip_text, get_current_ip())
|
||||
new_ip = orig_ip_octs[:]
|
||||
new_ip[3] = str((int(orig_ip_octs[3]) + 128) % 256)
|
||||
set_ip(new_ip)
|
||||
self.assertEquals(".".join(new_ip), get_current_ip())
|
||||
set_ip(orig_ip_octs)
|
||||
self.assertEquals(orig_ip_text, get_current_ip())
|
||||
|
||||
|
||||
def test_inputs(self):
|
||||
self.register_auth(self.URL + "network")
|
||||
self.cmd.go(self.URL + "network" + "?redirected=1")
|
||||
self.register_auth(self.url + "network")
|
||||
self.cmd.go(self.url + "network" + "?redirected=1")
|
||||
self.cmd.notfind("problem")
|
||||
self.cmd.go(self.URL + "network" + "?store=1")
|
||||
self.cmd.go(self.url + "network" + "?store=1")
|
||||
self.cmd.find("invalid network address")
|
||||
|
||||
|
|
|
@ -18,114 +18,141 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""The partition feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import logging
|
||||
import cryptobox.core.tools as cbxTools
|
||||
import cryptobox.plugins.base
|
||||
|
||||
class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = True
|
||||
PARTTYPES = {
|
||||
"windows" : ["0xC", "vfat"],
|
||||
"linux" : ["L", "ext3"]}
|
||||
|
||||
CONFIGPARTITION = {
|
||||
"size" : 5, # size of configuration partition (if necessary) in MB
|
||||
"type" : "L",
|
||||
"fs" : "ext2"}
|
||||
|
||||
|
||||
class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
"""The partition feature of the CryptoBox.
|
||||
"""
|
||||
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = True
|
||||
rank = 80
|
||||
|
||||
PartTypes = {
|
||||
"windows" : ["0xC", "vfat"],
|
||||
"linux" : ["L", "ext3"]}
|
||||
|
||||
ConfigPartition = {
|
||||
"size" : 5, # size of configuration partition (if necessary) in MB
|
||||
"type" : "L",
|
||||
"fs" : "ext2"}
|
||||
|
||||
|
||||
def doAction(self, **args):
|
||||
def do_action(self, **args):
|
||||
"""Show the partitioning form and execute the requested action.
|
||||
"""
|
||||
## load default hdf values
|
||||
self.__prepareDataset()
|
||||
self.__prepare_dataset()
|
||||
## retrieve some values from 'args' - defaults are empty
|
||||
self.device = self.__getSelectedDevice(args)
|
||||
self.withConfigPartition = self.__isWithConfigPartition()
|
||||
self.device = self.__get_selected_device(args)
|
||||
self.with_config_partition = self.__is_with_config_partition()
|
||||
self.cbox.log.debug("partition plugin: selected device=%s" % str(self.device))
|
||||
self.deviceSize = self.__getAvailableDeviceSize(self.device)
|
||||
self.device_size = self.__get_available_device_size(self.device)
|
||||
try:
|
||||
step = args["step"]
|
||||
del args["step"]
|
||||
except KeyError:
|
||||
step = "select_device"
|
||||
try:
|
||||
## this way of selecting the easy setup is necessary: see select_device.py for details
|
||||
if args["easy"]: step = "easy"
|
||||
## this way of selecting the easy setup is necessary:
|
||||
## see select_device.cs for details (button values for ie)
|
||||
if args["easy"]:
|
||||
step = "easy"
|
||||
except KeyError:
|
||||
pass
|
||||
## no (or invalid) device was supplied
|
||||
if not self.device:
|
||||
step = "select_device"
|
||||
if step == "add_partition":
|
||||
return self.__actionAddPartition(args)
|
||||
return self.__action_add_partition(args)
|
||||
elif step == "del_partition":
|
||||
return self.__actionDelPartition(args)
|
||||
return self.__action_del_partition(args)
|
||||
elif step == "finish":
|
||||
return self.__actionFinish(args)
|
||||
return self.__action_finish(args)
|
||||
elif step == "easy":
|
||||
return self.__actionEasySetup(args)
|
||||
return self.__action_easy_setup()
|
||||
else: # for "select_device" and for invalid targets
|
||||
return self.__actionSelectDevice(args)
|
||||
return self.__action_select_device()
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return "%s / %s / %s" % (self.device, self.deviceSize, self.withConfigPartition)
|
||||
def get_status(self):
|
||||
"""The status of this plugin is the selected device and some information.
|
||||
"""
|
||||
return "%s / %s / %s" % (self.device, self.device_size,
|
||||
self.with_config_partition)
|
||||
|
||||
|
||||
def __prepareDataset(self):
|
||||
self.hdf[self.hdf_prefix + "StyleSheetFile"] = os.path.join(self.pluginDir, "partition.css")
|
||||
def __prepare_dataset(self):
|
||||
"""Set some hdf values.
|
||||
"""
|
||||
self.hdf[self.hdf_prefix + "StyleSheetFile"] = \
|
||||
os.path.join(self.plugin_dir, "partition.css")
|
||||
|
||||
|
||||
def __getSelectedDevice(self, args):
|
||||
def __get_selected_device(self, args):
|
||||
"""Check the selected device (valid, not busy, ...).
|
||||
"""
|
||||
try:
|
||||
device = args["block_device"]
|
||||
except KeyError:
|
||||
return None
|
||||
if not self.__isDeviceValid(device):
|
||||
if not self.__is_device_valid(device):
|
||||
return None
|
||||
if self.__isDeviceBusy(device):
|
||||
if self.__is_device_busy(device):
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy"
|
||||
return None
|
||||
return device
|
||||
|
||||
|
||||
def __isDeviceValid(self, device):
|
||||
def __is_device_valid(self, device):
|
||||
"""Check if the device is valid and allowed.
|
||||
"""
|
||||
if not device:
|
||||
return False
|
||||
if not self.cbox.isDeviceAllowed(device):
|
||||
if not self.cbox.is_device_allowed(device):
|
||||
return False
|
||||
if not device in cbxTools.getParentBlockDevices():
|
||||
if not device in cbxTools.get_parent_blockdevices():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def __isDeviceBusy(self, device):
|
||||
"""check if the device (or one of its partitions) is mounted"""
|
||||
def __is_device_busy(self, device):
|
||||
"""check if the device (or one of its partitions) is mounted
|
||||
"""
|
||||
# the config partition is ignored, as it will get unmounted if necessary
|
||||
import re
|
||||
for c in self.cbox.getContainerList():
|
||||
if re.match(device + "\d*$", c.getDevice()):
|
||||
if c.isMounted(): return True
|
||||
for cont in self.cbox.get_container_list():
|
||||
if re.match(device + "\d*$", cont.get_device()):
|
||||
if cont.is_mounted():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def __actionSelectDevice(self, args):
|
||||
def __action_select_device(self):
|
||||
"""Show a form to select the device for partitioning.
|
||||
"""
|
||||
block_devices = [e
|
||||
for e in cbxTools.getParentBlockDevices()
|
||||
if self.cbox.isDeviceAllowed(e)]
|
||||
for e in cbxTools.get_parent_blockdevices()
|
||||
if self.cbox.is_device_allowed(e)]
|
||||
counter = 0
|
||||
for a in block_devices:
|
||||
self.hdf[self.hdf_prefix + "BlockDevices.%d.name" % counter] = a
|
||||
self.hdf[self.hdf_prefix + "BlockDevices.%d.size" % counter] = cbxTools.getBlockDeviceSizeHumanly(a)
|
||||
self.cbox.log.debug("found a suitable block device: %s" % a)
|
||||
for dev in block_devices:
|
||||
self.hdf[self.hdf_prefix + "BlockDevices.%d.name" % counter] = dev
|
||||
self.hdf[self.hdf_prefix + "BlockDevices.%d.size" % counter] = \
|
||||
cbxTools.get_blockdevice_size_humanly(dev)
|
||||
self.cbox.log.debug("found a suitable block device: %s" % dev)
|
||||
counter += 1
|
||||
if self.withConfigPartition:
|
||||
if self.with_config_partition:
|
||||
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
|
||||
## there is no disk available
|
||||
if not block_devices:
|
||||
|
@ -133,59 +160,72 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return "select_device"
|
||||
|
||||
|
||||
def __actionAddPartition(self, args):
|
||||
def __action_add_partition(self, args):
|
||||
"""Add a selected partition to the currently proposed partition table.
|
||||
"""
|
||||
self.hdf[self.hdf_prefix + "Device"] = self.device
|
||||
self.hdf[self.hdf_prefix + "Device.Size"] = self.deviceSize
|
||||
parts = self.__getPartitionsFromArgs(args)
|
||||
self.__setPartitionData(parts)
|
||||
self.hdf[self.hdf_prefix + "Device.Size"] = self.device_size
|
||||
parts = self.__get_partitions_from_args(args)
|
||||
self.__set_partition_data(parts)
|
||||
return "set_partitions"
|
||||
|
||||
|
||||
def __actionDelPartition(self, args):
|
||||
def __action_del_partition(self, args):
|
||||
"""Remove a partition from the proposed partition table.
|
||||
"""
|
||||
try:
|
||||
part_num = int(args["del_num"])
|
||||
except (TypeError,KeyError):
|
||||
return self.__actionAddPartition(args)
|
||||
return self.__action_add_partition(args)
|
||||
self.hdf[self.hdf_prefix + "Device"] = self.device
|
||||
self.hdf[self.hdf_prefix + "Device.Size"] = self.deviceSize
|
||||
parts = self.__getPartitionsFromArgs(args)
|
||||
self.hdf[self.hdf_prefix + "Device.Size"] = self.device_size
|
||||
parts = self.__get_partitions_from_args(args)
|
||||
## valid partition number to be deleted?
|
||||
if part_num < len(parts):
|
||||
del parts[part_num]
|
||||
else:
|
||||
return self.__actionAddPartition(args)
|
||||
self.__setPartitionData(parts)
|
||||
return self.__action_add_partition(args)
|
||||
self.__set_partition_data(parts)
|
||||
return "set_partitions"
|
||||
|
||||
|
||||
def __actionFinish(self, args):
|
||||
parts = self.__getPartitionsFromArgs(args)
|
||||
def __action_finish(self, args):
|
||||
"""Write the partition table.
|
||||
"""
|
||||
parts = self.__get_partitions_from_args(args)
|
||||
if parts:
|
||||
self.__setPartitionData(parts)
|
||||
if cbxTools.isPartOfBlockDevice(self.device, self.cbox.prefs.getActivePartition()):
|
||||
self.cbox.prefs.umountPartition()
|
||||
if not self.__runFDisk(parts):
|
||||
self.__set_partition_data(parts)
|
||||
if cbxTools.is_part_of_blockdevice(self.device,
|
||||
self.cbox.prefs.get_active_partition()):
|
||||
self.cbox.prefs.umount_partition()
|
||||
if not self.__run_fdisk(parts):
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
|
||||
self.cbox.log.warn("partition: failed to partition device: %s" % self.device)
|
||||
return self.__actionAddPartition(args)
|
||||
self.cbox.log.warn(
|
||||
"partition: failed to partition device: %s" % self.device)
|
||||
return self.__action_add_partition(args)
|
||||
else:
|
||||
"""
|
||||
tricky problem: if the device was partitioned, then a created config partition is still part of the containerlist, as the label is not checked again - very ugly!!! So we will call reReadContainerList after formatting the last partition - see below
|
||||
"""
|
||||
self.cbox.reReadContainerList()
|
||||
## tricky problem: if the device was partitioned, then a created config
|
||||
## partition is still part of the containerlist, as the label is not
|
||||
## checked again - very ugly!!! So we will call reReadContainerList
|
||||
## after formatting the last partition - see below
|
||||
self.cbox.reread_container_list()
|
||||
def result_generator():
|
||||
"""Generate the results of formatting - may be threaded.
|
||||
"""
|
||||
counter = 0
|
||||
## initialize the generator
|
||||
formatPart_gen = self.__formatPartitions(parts)
|
||||
format_part_gen = self.__format_partitions(parts)
|
||||
while counter < len(parts):
|
||||
## first part: get the device name
|
||||
yield formatPart_gen.next()
|
||||
yield format_part_gen.next()
|
||||
counter += 1
|
||||
## second part: do the real formatting of a partition
|
||||
result = formatPart_gen.next()
|
||||
## after the first partiton, we can reRead the containerList (as the possible config partition was already created)
|
||||
if self.withConfigPartition and (counter == 1):
|
||||
## important: reRead the containerList - but somehow it breaks the flow (hanging process)
|
||||
result = format_part_gen.next()
|
||||
## after the first partiton, we can reRead the containerList
|
||||
## (as the possible config partition was already created)
|
||||
if self.with_config_partition and (counter == 1):
|
||||
## important: reRead the containerList - but somehow it
|
||||
## breaks the flow (hanging process)
|
||||
#self.cbox.reReadContainerList()
|
||||
## write config data
|
||||
self.cbox.prefs.mountPartition()
|
||||
|
@ -200,24 +240,28 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
"template": "show_format_progress",
|
||||
"generator": result_generator}
|
||||
else:
|
||||
return self.__actionAddPartition(args)
|
||||
return self.__action_add_partition(args)
|
||||
|
||||
|
||||
def __actionEasySetup(self, args):
|
||||
def __action_easy_setup(self):
|
||||
"""Do automatic partitioning (create only one big partition).
|
||||
"""
|
||||
import types
|
||||
## we do not have to take special care for a possible config partition
|
||||
parts = [ { "size": self.deviceSize, "type": "windows" } ]
|
||||
parts = [ { "size": self.device_size, "type": "windows" } ]
|
||||
## umount partition if necessary
|
||||
if cbxTools.isPartOfBlockDevice(self.device, self.cbox.prefs.getActivePartition()):
|
||||
self.cbox.prefs.umountPartition()
|
||||
if cbxTools.is_part_of_blockdevice(self.device,
|
||||
self.cbox.prefs.get_active_partition()):
|
||||
self.cbox.prefs.umount_partition()
|
||||
## partition it
|
||||
if not self.__runFDisk(parts):
|
||||
if not self.__run_fdisk(parts):
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
|
||||
return None
|
||||
## "formatPartitions" is a generator, returning device names and bolean values
|
||||
result = [e for e in self.__formatPartitions(parts) if type(e) == types.BooleanType]
|
||||
if self.withConfigPartition:
|
||||
self.cbox.prefs.mountPartition()
|
||||
result = [e for e in self.__format_partitions(parts)
|
||||
if type(e) == types.BooleanType]
|
||||
if self.with_config_partition:
|
||||
self.cbox.prefs.mount_partition()
|
||||
self.cbox.prefs.write()
|
||||
## check if there is a "False" return value
|
||||
if False in result:
|
||||
|
@ -229,50 +273,59 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
## operation was successful
|
||||
self.hdf["Data.Success"] = "Plugins.partition.EasySetup"
|
||||
self.cbox.log.info("easy partitioning succeeded")
|
||||
## do not show the disk overview immediately - it does not get updated that fast
|
||||
## do not show the disk overview immediately
|
||||
## it does not get updated that fast
|
||||
return { "plugin":"system_preferences", "values":[] }
|
||||
|
||||
|
||||
def __setPartitionData(self, parts):
|
||||
availSize = self.deviceSize
|
||||
def __set_partition_data(self, parts):
|
||||
"""Set some hdf values for the currently proposed partition table.
|
||||
"""
|
||||
avail_size = self.device_size
|
||||
i = 0
|
||||
for part in parts:
|
||||
self.cbox.log.debug(part)
|
||||
self.hdf[self.hdf_prefix + "Parts.%d.Size" % i] = part["size"]
|
||||
self.hdf[self.hdf_prefix + "Parts.%d.Type" % i] = part["type"]
|
||||
availSize -= part["size"]
|
||||
avail_size -= part["size"]
|
||||
i += 1
|
||||
self.hdf[self.hdf_prefix + "availSize"] = availSize
|
||||
if self.withConfigPartition:
|
||||
self.hdf[self.hdf_prefix + "availSize"] = avail_size
|
||||
if self.with_config_partition:
|
||||
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
|
||||
for t in self.PartTypes.keys():
|
||||
self.hdf[self.hdf_prefix + "Types.%s" % t] = t
|
||||
for ptype in PARTTYPES.keys():
|
||||
self.hdf[self.hdf_prefix + "Types.%s" % ptype] = ptype
|
||||
## store the currently existing partitions of the choosen block device
|
||||
current_containers = [ e for e in self.cbox.getContainerList() if cbxTools.isPartOfBlockDevice(self.device, e.getDevice()) ]
|
||||
for (index, t) in enumerate(current_containers):
|
||||
self.hdf[self.hdf_prefix + "ExistingContainers.%d.name" % index] = t.getName()
|
||||
self.hdf[self.hdf_prefix + "ExistingContainers.%d.size" % index] = cbxTools.getBlockDeviceSizeHumanly(t.getDevice())
|
||||
current_containers = [ e for e in self.cbox.get_container_list()
|
||||
if cbxTools.is_part_of_blockdevice(self.device, e.get_device()) ]
|
||||
for (index, cont) in enumerate(current_containers):
|
||||
self.hdf[self.hdf_prefix + "ExistingContainers.%d.name" % index] = \
|
||||
cont.get_name()
|
||||
self.hdf[self.hdf_prefix + "ExistingContainers.%d.size" % index] = \
|
||||
cbxTools.get_blockdevice_size_humanly(cont.get_device())
|
||||
|
||||
|
||||
def __getPartitionsFromArgs(self, args):
|
||||
def __get_partitions_from_args(self, args):
|
||||
"""Filter the given arguments and construct a partition table.
|
||||
"""
|
||||
parts = []
|
||||
done = False
|
||||
availSize = self.deviceSize
|
||||
avail_size = self.device_size
|
||||
i = -1
|
||||
while not done:
|
||||
i += 1
|
||||
try:
|
||||
size = int(args["part%d_size" % i])
|
||||
partType = args["part%d_type" % i]
|
||||
if int(size) > availSize:
|
||||
part_type = args["part%d_type" % i]
|
||||
if int(size) > avail_size:
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitionTooBig"
|
||||
continue
|
||||
if int(size) < 10:
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitionTooSmall"
|
||||
continue
|
||||
if not partType in self.PartTypes.keys(): continue
|
||||
parts.append({"size":size, "type":partType})
|
||||
availSize -= size
|
||||
if not part_type in PARTTYPES.keys():
|
||||
continue
|
||||
parts.append({"size":size, "type":part_type})
|
||||
avail_size -= size
|
||||
except TypeError:
|
||||
pass
|
||||
except KeyError:
|
||||
|
@ -280,33 +333,40 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return parts
|
||||
|
||||
|
||||
def __getAvailableDeviceSize(self, device):
|
||||
def __get_available_device_size(self, device):
|
||||
"""calculate the available size (MB) of the device
|
||||
also consider a (possible) configuration partition"""
|
||||
deviceSize = cbxTools.getBlockDeviceSize(device)
|
||||
if deviceSize < 0: return 0
|
||||
if self.withConfigPartition:
|
||||
deviceSize -= self.ConfigPartition["size"]
|
||||
return deviceSize
|
||||
also consider a (possible) configuration partition
|
||||
"""
|
||||
device_size = cbxTools.get_blockdevice_size(device)
|
||||
if device_size < 0:
|
||||
return 0
|
||||
if self.with_config_partition:
|
||||
device_size -= CONFIGPARTITION["size"]
|
||||
return device_size
|
||||
|
||||
|
||||
def __isWithConfigPartition(self):
|
||||
"""check if we have to create a configuration partition"""
|
||||
if self.cbox.prefs.requiresPartition():
|
||||
active = self.cbox.prefs.getActivePartition()
|
||||
def __is_with_config_partition(self):
|
||||
"""check if we have to create a configuration partition
|
||||
"""
|
||||
if self.cbox.prefs.requires_partition():
|
||||
active = self.cbox.prefs.get_active_partition()
|
||||
## we need a partition, if there is no active one
|
||||
if not active: return True
|
||||
if not active:
|
||||
return True
|
||||
## check if the active one is part of the current device
|
||||
return cbxTools.isPartOfBlockDevice(self.device, active)
|
||||
return cbxTools.is_part_of_blockdevice(self.device, active)
|
||||
return False
|
||||
|
||||
|
||||
def __runFDisk(self, parts):
|
||||
def __run_fdisk(self, parts):
|
||||
"""Call fdisk to partition the device.
|
||||
"""
|
||||
## check if the device is completely filled (to avoid some empty last blocks)
|
||||
avail_size = self.deviceSize
|
||||
for d in parts: avail_size -= d["size"]
|
||||
avail_size = self.device_size
|
||||
for one_part in parts:
|
||||
avail_size -= one_part["size"]
|
||||
self.cbox.log.debug("remaining size: %d" % avail_size)
|
||||
isFilled = avail_size == 0
|
||||
is_filled = avail_size == 0
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = subprocess.PIPE,
|
||||
|
@ -316,81 +376,91 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
"partition",
|
||||
self.device])
|
||||
for line in self.__getSFDiskLayout(parts, isFilled):
|
||||
for line in self.__get_sfdisk_layout(parts, is_filled):
|
||||
proc.stdin.write(line + "\n")
|
||||
(output, error) = proc.communicate()
|
||||
if proc.returncode != 0: self.cbox.log.debug("partitioning failed: %s" % error)
|
||||
if proc.returncode != 0:
|
||||
self.cbox.log.debug("partitioning failed: %s" % error)
|
||||
return proc.returncode == 0
|
||||
|
||||
|
||||
def __getSFDiskLayout(self, paramParts, isFilled):
|
||||
"""this generator returns the input lines for sfdisk"""
|
||||
parts = paramParts[:]
|
||||
def __get_sfdisk_layout(self, param_parts, is_filled):
|
||||
"""this generator returns the input lines for sfdisk
|
||||
"""
|
||||
parts = param_parts[:]
|
||||
## first a (possible) configuration partition - so it will be reusable
|
||||
if self.withConfigPartition:
|
||||
if self.with_config_partition:
|
||||
## fill the main table (including a config partition)
|
||||
yield ",%d,%s" % (self.ConfigPartition["size"], self.ConfigPartition["type"])
|
||||
yield ",%d,%s" % (CONFIGPARTITION["size"], CONFIGPARTITION["type"])
|
||||
## one primary partition
|
||||
if isFilled and (len(parts) == 1):
|
||||
if is_filled and (len(parts) == 1):
|
||||
## fill the rest of the device
|
||||
yield ",,%s,*" % self.PartTypes[parts[0]["type"]][0]
|
||||
yield ",,%s,*" % PARTTYPES[parts[0]["type"]][0]
|
||||
else:
|
||||
## only use the specified size
|
||||
yield ",%d,%s,*" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0])
|
||||
yield ",%d,%s,*" % (parts[0]["size"], PARTTYPES[parts[0]["type"]][0])
|
||||
del parts[0]
|
||||
## no extended partition, if there is only one disk
|
||||
if not parts: return
|
||||
if not parts:
|
||||
return
|
||||
## an extended container for the rest
|
||||
yield ",,E"
|
||||
## an empty partition in main table
|
||||
yield ";"
|
||||
## maybe another empty partition if there is no config partition
|
||||
if not self.withConfigPartition: yield ";"
|
||||
if not self.with_config_partition:
|
||||
yield ";"
|
||||
while parts:
|
||||
if isFilled and (len(parts) == 1):
|
||||
yield ",,%s" % (self.PartTypes[parts[0]["type"]][0],)
|
||||
if is_filled and (len(parts) == 1):
|
||||
yield ",,%s" % (PARTTYPES[parts[0]["type"]][0],)
|
||||
else:
|
||||
yield ",%d,%s" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0])
|
||||
yield ",%d,%s" % (parts[0]["size"], PARTTYPES[parts[0]["type"]][0])
|
||||
del parts[0]
|
||||
|
||||
|
||||
def __formatPartitions(self, paramParts):
|
||||
parts = paramParts[:]
|
||||
def __format_partitions(self, param_parts):
|
||||
"""Format all partitions of the device.
|
||||
"""
|
||||
parts = param_parts[:]
|
||||
part_num = 1
|
||||
## maybe a config partition?
|
||||
if self.withConfigPartition:
|
||||
if self.with_config_partition:
|
||||
dev_name = self.device + str(part_num)
|
||||
self.cbox.log.info("formatting config partition (%s)" % dev_name)
|
||||
if self.__formatOnePartition(dev_name, self.ConfigPartition["fs"]):
|
||||
self.__setLabelOfPartition(dev_name, self.cbox.prefs["Main"]["ConfigVolumeLabel"])
|
||||
if self.__format_one_partition(dev_name, CONFIGPARTITION["fs"]):
|
||||
self.__set_label_of_partition(dev_name,
|
||||
self.cbox.prefs["Main"]["ConfigVolumeLabel"])
|
||||
part_num += 1
|
||||
## the first data partition
|
||||
dev_name = self.device + str(part_num)
|
||||
partType = self.PartTypes[parts[0]["type"]][1]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
|
||||
part_type = PARTTYPES[parts[0]["type"]][1]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, part_type))
|
||||
yield dev_name
|
||||
yield self.__formatOnePartition(dev_name, partType)
|
||||
yield self.__format_one_partition(dev_name, part_type)
|
||||
del parts[0]
|
||||
## other data partitions
|
||||
part_num = 5
|
||||
while parts:
|
||||
dev_name = self.device + str(part_num)
|
||||
partType = self.PartTypes[parts[0]["type"]][1]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
|
||||
part_type = PARTTYPES[parts[0]["type"]][1]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % \
|
||||
(dev_name, part_type))
|
||||
yield dev_name
|
||||
yield self.__formatOnePartition(dev_name, partType)
|
||||
yield self.__format_one_partition(dev_name, part_type)
|
||||
part_num += 1
|
||||
del parts[0]
|
||||
return
|
||||
|
||||
|
||||
def __formatOnePartition(self, dev_name, type):
|
||||
def __format_one_partition(self, dev_name, fs_type):
|
||||
"""Format a single partition
|
||||
"""
|
||||
## first: retrieve UUID - it can be removed from the database afterwards
|
||||
volDB = self.cbox.prefs.volumesDB
|
||||
prev_name = [e.getName() for e in self.cbox.getContainerList() if e.getDevice() == dev_name]
|
||||
prev_name = [e.get_name() for e in self.cbox.get_container_list()
|
||||
if e.get_device() == dev_name]
|
||||
## call "mkfs"
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
|
@ -398,10 +468,10 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
"format",
|
||||
dev_name,
|
||||
type])
|
||||
fs_type])
|
||||
(output, error) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error))
|
||||
|
@ -409,11 +479,13 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
else:
|
||||
## remove unused volume entry
|
||||
if prev_name:
|
||||
self.cbox.prefs.volumesDB[prev_name[0]]
|
||||
del self.cbox.prefs.volumes_db[prev_name[0]]
|
||||
return True
|
||||
|
||||
|
||||
def __setLabelOfPartition(self, dev_name, label):
|
||||
def __set_label_of_partition(self, dev_name, label):
|
||||
"""Set the label of a partition - useful for the config partition.
|
||||
"""
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
|
@ -422,7 +494,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
"label",
|
||||
dev_name,
|
||||
label])
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
|
||||
PLUGIN_TYPE = "cryptobox"
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "partition?weblang=en"
|
||||
url = self.url + "partition?weblang=en"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('VERY careful')
|
||||
|
|
|
@ -7,7 +7,7 @@ The following directory structure is required:
|
|||
|
||||
Python code interface:
|
||||
- create a class with the same name as the plugin - it must inherit CryptoBoxPlugin
|
||||
- function "doAction":
|
||||
- function "do_action":
|
||||
- this function will get called whenever this plugins is involved in a request
|
||||
- all arguments should be optional (e.g. for displaying a form without previous input values)
|
||||
- the argument "store" should be used to process a form submission (just a recommendation)
|
||||
|
@ -27,15 +27,15 @@ Python code interface:
|
|||
* values: a dictionary of variables that should be defined for this plugin
|
||||
- an empty (e.g. None) return value can be used to go to the default page ("disks"
|
||||
or "volume_mount" (for volume plugins))
|
||||
- function "getStatus":
|
||||
- function "get_status":
|
||||
- returns a string, that describes a state connected to this plugin (e.g. the current date and
|
||||
time (for the "date" plugin))
|
||||
- the class variable "pluginCapabilities" must be an array of strings (supported: "system" and
|
||||
- the class variable "plugin_capabilities" must be an array of strings (supported: "system" and
|
||||
"volume")
|
||||
- the class variable "pluginVisibility" may contain one or more of the following items:
|
||||
menu/preferences/volume. This obviously should fit to the 'pluginCapabilities' variable.
|
||||
An empty list is interpreted as a disabled plugin.
|
||||
- the class variable "requestAuth" is boolean and defines, if admin authentication is necessary
|
||||
- the class variable "plugin_visibility" may contain one or more of the following items:
|
||||
menu/preferences/volume. This should fit to the 'plugin_capabilities' variable.
|
||||
An empty list is interpreted as an invisible plugin.
|
||||
- the class variable "request_auth" is boolean and defines, if admin authentication is necessary
|
||||
for this plugin
|
||||
- the class variable "rank" is an integer in the range of 0..100 - it determines the order
|
||||
of plugins in listings (lower value -> higher priority)
|
||||
|
|
|
@ -18,27 +18,31 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
import cryptobox.plugins.manage
|
||||
|
||||
|
||||
class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = True
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = True
|
||||
rank = 90
|
||||
|
||||
def doAction(self, store=None, action=None, plugin_name=None, **args):
|
||||
def do_action(self, store=None, action=None, plugin_name=None, **args):
|
||||
import re
|
||||
if plugin_name:
|
||||
## check for invalid characters
|
||||
if re.search(u'\W', plugin_name): return "plugin_list"
|
||||
pluginList = cryptobox.plugins.manage.PluginManager(self.cbox, self.cbox.prefs["Locations"]["PluginDir"])
|
||||
plugin = pluginList.getPlugin(plugin_name)
|
||||
plugin_manager = cryptobox.plugins.manage.PluginManager(
|
||||
self.cbox, self.cbox.prefs["Locations"]["PluginDir"])
|
||||
plugin = plugin_manager.get_plugin(plugin_name)
|
||||
if not plugin: return "plugin_list"
|
||||
## take only plugins, that are of the same type as the choosen one
|
||||
self.plugins = [e for e in pluginList.getPlugins() if e.pluginCapabilities == plugin.pluginCapabilities]
|
||||
self.plugins = [e for e in plugin_manager.get_plugins()
|
||||
if e.plugin_capabilities == plugin.plugin_capabilities]
|
||||
if action == "up":
|
||||
self.__move_up(plugin)
|
||||
elif action == "down":
|
||||
|
@ -50,44 +54,48 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
if not re.search(u'\W',key):
|
||||
self.__setConfig(key[:-7], args)
|
||||
else:
|
||||
self.cbox.log.info("plugin_manager: invalid plugin name (%s)" % str(key[:-7]))
|
||||
self.cbox.log.info("plugin_manager: invalid plugin name (%s)" % \
|
||||
str(key[:-7]))
|
||||
try:
|
||||
self.cbox.prefs.pluginConf.write()
|
||||
self.cbox.prefs.plugin_conf.write()
|
||||
except IOError:
|
||||
self.cbox.log.warn("failed to write plugin configuration")
|
||||
return "plugin_list"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "no status"
|
||||
|
||||
|
||||
def __sortPlugins(self):
|
||||
def __sort_plugins(self):
|
||||
"""sort all plugins in the list according to their rank"""
|
||||
def cmp_func(x,y):
|
||||
xRank = x.getRank()
|
||||
yRank = y.getRank()
|
||||
if xRank < yRank: return -1
|
||||
elif xRank == yRank: return 0
|
||||
else: return 1
|
||||
x_rank = x.get_rank()
|
||||
y_rank = y.get_rank()
|
||||
if x_rank < y_rank:
|
||||
return -1
|
||||
elif x_rank == y_rank:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
self.plugins.sort(cmp = cmp_func)
|
||||
|
||||
|
||||
def __distributeRanks(self):
|
||||
def __distribute_ranks(self):
|
||||
"""evenly distribute the 'rank' values according to the current order of
|
||||
the list"""
|
||||
dist = 100/len(self.plugins)
|
||||
for index,pl in enumerate(self.plugins):
|
||||
try:
|
||||
self.cbox.prefs.pluginConf[pl.getName()]["rank"] = dist*index
|
||||
self.cbox.prefs.plugin_conf[pl.get_name()]["rank"] = dist*index
|
||||
except KeyError:
|
||||
self.cbox.prefs.pluginConf[pl.getName()] = {}
|
||||
self.cbox.prefs.pluginConf[pl.getName()]["rank"] = dist*index
|
||||
self.cbox.prefs.pluginConf.write()
|
||||
self.cbox.prefs.plugin_conf[pl.get_name()] = {}
|
||||
self.cbox.prefs.plugin_conf[pl.get_name()]["rank"] = dist*index
|
||||
self.cbox.prefs.plugin_conf.write()
|
||||
|
||||
|
||||
def __move_up(self, plugin):
|
||||
self.__sortPlugins()
|
||||
self.__sort_plugins()
|
||||
try:
|
||||
index = self.plugins.index(plugin)
|
||||
## first elements may not move up
|
||||
|
@ -97,11 +105,11 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return
|
||||
self.plugins.remove(plugin)
|
||||
self.plugins.insert(index-1, plugin)
|
||||
self.__distributeRanks()
|
||||
self.__distribute_ranks()
|
||||
|
||||
|
||||
def __move_down(self, plugin):
|
||||
self.__sortPlugins()
|
||||
self.__sort_plugins()
|
||||
try:
|
||||
index = self.plugins.index(plugin)
|
||||
## last elements may not move down
|
||||
|
@ -111,7 +119,7 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return
|
||||
self.plugins.remove(plugin)
|
||||
self.plugins.insert(index+1, plugin)
|
||||
self.__distributeRanks()
|
||||
self.__distribute_ranks()
|
||||
|
||||
|
||||
def __setConfig(self, name, args):
|
||||
|
@ -137,5 +145,5 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
setting["requestAuth"] = True
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
self.cbox.prefs.pluginConf[name] = setting
|
||||
self.cbox.prefs.plugin_conf[name] = setting
|
||||
|
||||
|
|
|
@ -18,19 +18,21 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "plugin_manager?weblang=en"
|
||||
url = self.url + "plugin_manager?weblang=en"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('Plugin Manager')
|
||||
|
||||
|
||||
def test_set_options(self):
|
||||
url = self.URL + "plugin_manager"
|
||||
url = self.url + "plugin_manager"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + u"?plugin_name=t/-!")
|
||||
self.cmd.find('Plugin Manager')
|
||||
|
@ -55,8 +57,8 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
|
||||
def test_move_up(self):
|
||||
## TODO: if we want to be perfect, then we should check the change of the rank
|
||||
url = self.URL + "plugin_manager"
|
||||
#TODO: if we want to be perfect, then we should check the change of the rank
|
||||
url = self.url + "plugin_manager"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + u"?plugin_name=disks&action=up")
|
||||
self.cmd.find('Plugin Manager')
|
||||
|
@ -68,7 +70,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_move_down(self):
|
||||
## TODO: if we want to be perfect, then we should check the change of the rank
|
||||
url = self.URL + "plugin_manager"
|
||||
url = self.url + "plugin_manager"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + u"?plugin_name=disks&action=down")
|
||||
self.cmd.find('Plugin Manager')
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
|
||||
PLUGIN_TYPE = "cryptobox"
|
||||
|
|
|
@ -18,29 +18,31 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
REDIRECT_DELAY = 180
|
||||
|
||||
class shutdown(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences", "menu" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences", "menu" ]
|
||||
request_auth = False
|
||||
rank = 90
|
||||
|
||||
def doAction(self, type=None):
|
||||
def do_action(self, type=None):
|
||||
if not type:
|
||||
return "form_shutdown"
|
||||
elif type == "shutdown":
|
||||
if self.__doShutdown("shutdown"):
|
||||
if self.__do_shutdown("shutdown"):
|
||||
self.hdf["Data.Success"] = "Plugins.shutdown.Shutdown"
|
||||
return "progress_shutdown"
|
||||
else:
|
||||
self.hdf["Data.Warning"] = "Plugins.shutdown.ShutdownFailed"
|
||||
return "form_shutdown"
|
||||
elif type == "reboot":
|
||||
if self.__doShutdown("reboot"):
|
||||
if self.__do_shutdown("reboot"):
|
||||
self.hdf["Data.Success"] = "Plugins.shutdown.Reboot"
|
||||
self.hdf["Data.Redirect.URL"] = ""
|
||||
self.hdf["Data.Redirect.Delay"] = REDIRECT_DELAY
|
||||
|
@ -52,11 +54,11 @@ class shutdown(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return "form_shutdown"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "the box is up'n'running"
|
||||
|
||||
|
||||
def __doShutdown(self, action):
|
||||
def __do_shutdown(self, action):
|
||||
import subprocess
|
||||
import os
|
||||
proc = subprocess.Popen(
|
||||
|
@ -65,7 +67,7 @@ class shutdown(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"plugin",
|
||||
os.path.join(self.pluginDir, "root_action.py"),
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
action])
|
||||
proc.wait()
|
||||
return proc.returncode == 0
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
"""just read the form - I do not know of a way how to check success"""
|
||||
url = self.URL + "shutdown"
|
||||
url = self.url + "shutdown"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('shutdown')
|
||||
|
|
|
@ -18,20 +18,23 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
class system_preferences(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "menu" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "menu" ]
|
||||
request_auth = False
|
||||
rank = 20
|
||||
|
||||
def doAction(self):
|
||||
def do_action(self):
|
||||
return "show_plugins"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return ":".join([p.getName() for p in self.site.pluginList.getPlugins()])
|
||||
|
||||
def get_status(self):
|
||||
plugin_manager = cryptobox.plugins.manage.PluginManager(
|
||||
self.cbox, self.cbox.prefs["Locations"]["PluginDir"])
|
||||
return ":".join([p.get_name() for p in plugin_manager.get_plugins()])
|
||||
|
||||
|
|
|
@ -18,17 +18,19 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
self.cmd.go(self.URL + "system_preferences")
|
||||
self.cmd.go(self.url + "system_preferences")
|
||||
self.cmd.find("Preferences")
|
||||
|
||||
|
||||
def test_check_plugins(self):
|
||||
self.cmd.go(self.URL + "system_preferences")
|
||||
self.cmd.go(self.url + "system_preferences")
|
||||
self.cmd.find(u'Data.Status.Plugins.system_preferences=(.*)$', "m")
|
||||
plugins = self.locals["__match__"].split(":")
|
||||
self.assertTrue(len(plugins) > 1)
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
## this user may not be removed
|
||||
|
@ -35,7 +37,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_test_wrong_credentials(self):
|
||||
"""check if the user_manager is protected"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url,"foo","bar")
|
||||
self.cmd.go(url)
|
||||
self.cmd.notfind("Manage users")
|
||||
|
@ -43,7 +45,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_add_existing_user(self):
|
||||
"""adding an existing user should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self._add_user("admin","foo","foo")
|
||||
self.cmd.find("The choosen username does already exist")
|
||||
|
@ -51,7 +53,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_add_invalid_username(self):
|
||||
"""adding an invalid username should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self._add_user("foo/bar","foo","foo")
|
||||
self.cmd.find("Invalid username")
|
||||
|
@ -60,7 +62,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_add_without_password(self):
|
||||
"""adding a user without password should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("foo" in self._getUsers())
|
||||
self._add_user("foo","","foo")
|
||||
|
@ -70,7 +72,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_add_with_different_passwords(self):
|
||||
"""adding a user with different passwords should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("foo" in self._getUsers())
|
||||
self._add_user("foo","bar","foo")
|
||||
|
@ -80,7 +82,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_change_pw_for_invalid_user(self):
|
||||
"""changing a password of a non existing user should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("barfoo" in self._getUsers())
|
||||
self.cmd.go(url + "?store=change_password&user=foobar&new_pw=foo&new_pw2=foo")
|
||||
|
@ -89,7 +91,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_change_pw_without_password(self):
|
||||
"""changing a password without a new password should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("foo" in self._getUsers())
|
||||
self._add_user("foo","bar","bar")
|
||||
|
@ -102,7 +104,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_change_pw_wit_different_passwords(self):
|
||||
"""changing a password while supplying different passwords should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("foo" in self._getUsers())
|
||||
self._add_user("foo","bar","bar")
|
||||
|
@ -115,7 +117,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def _remove_reserved_user(self):
|
||||
"""removing a reserved user should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertTrue("admin" in self._getUsers())
|
||||
self._del_user("admin")
|
||||
|
@ -125,7 +127,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def _remove_non_existing_user(self):
|
||||
"""removing a non-existing user should fail"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.assertFalse("barfoo" in self._getUsers())
|
||||
self._del_user("barfoo")
|
||||
|
@ -134,7 +136,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_manage_users(self):
|
||||
"""add a new user, change its password and remove the user afterwards"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
## remove the user that should be added - just in case a previous run was unclean
|
||||
## check its existence before
|
||||
|
@ -158,13 +160,13 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_invalid_input(self):
|
||||
"""check all combinations of invalid input"""
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + "?store=foobar")
|
||||
|
||||
|
||||
def _add_user(self, username, pw, pw2):
|
||||
self.cmd.go(self.URL + "user_manager")
|
||||
self.cmd.go(self.url + "user_manager")
|
||||
self.cmd.formvalue("add_user","user",username)
|
||||
self.cmd.formvalue("add_user","new_pw",pw)
|
||||
self.cmd.formvalue("add_user","new_pw2",pw2)
|
||||
|
@ -172,13 +174,13 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
|
||||
def _del_user(self, username):
|
||||
self.cmd.go(self.URL + "user_manager")
|
||||
self.cmd.go(self.url + "user_manager")
|
||||
self.cmd.formvalue("del_user","user",username)
|
||||
self.cmd.submit()
|
||||
|
||||
|
||||
def _change_password(self, username, pw, pw2):
|
||||
self.cmd.go(self.URL + "user_manager")
|
||||
self.cmd.go(self.url + "user_manager")
|
||||
self.cmd.formvalue("change_password","user",username)
|
||||
self.cmd.formvalue("change_password","new_pw",pw)
|
||||
self.cmd.formvalue("change_password","new_pw2",pw2)
|
||||
|
@ -186,7 +188,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
|
||||
def _getUsers(self):
|
||||
url = self.URL + "user_manager"
|
||||
url = self.url + "user_manager"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find("Data.Status.Plugins.user_manager=([\w:]+)")
|
||||
|
|
|
@ -18,21 +18,23 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
RESERVED_USERS = [ "admin" ]
|
||||
|
||||
class user_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "system" ]
|
||||
pluginVisibility = [ "preferences" ]
|
||||
requestAuth = True
|
||||
plugin_capabilities = [ "system" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
request_auth = True
|
||||
rank = 45
|
||||
|
||||
def doAction(self, store=None, user=None, new_pw=None, new_pw2=None):
|
||||
def do_action(self, store=None, user=None, new_pw=None, new_pw2=None):
|
||||
import re
|
||||
adminDict = self.cbox.prefs.userDB["admins"]
|
||||
self.__cleanHDF()
|
||||
admin_dict = self.cbox.prefs.user_db["admins"]
|
||||
self.__clean_hdf()
|
||||
if store is None:
|
||||
pass
|
||||
elif store == "add_user":
|
||||
|
@ -42,13 +44,13 @@ class user_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.hdf["Data.Warning"] = "EmptyNewPassword"
|
||||
elif new_pw != new_pw2:
|
||||
self.hdf["Data.Warning"] = "DifferentPasswords"
|
||||
elif user in adminDict.keys():
|
||||
elif user in admin_dict.keys():
|
||||
self.hdf["Data.Warning"] = "Plugins.user_manager.UserAlreadyExists"
|
||||
else:
|
||||
adminDict[user] = self.cbox.prefs.userDB.getDigest(new_pw)
|
||||
admin_dict[user] = self.cbox.prefs.user_db.get_digest(new_pw)
|
||||
self.hdf["Data.Success"] = "Plugins.user_manager.UserAdded"
|
||||
try:
|
||||
self.cbox.prefs.userDB.write()
|
||||
self.cbox.prefs.user_db.write()
|
||||
except IOError:
|
||||
self.cbox.log.warn("failed to write user database")
|
||||
elif store == "change_password":
|
||||
|
@ -56,11 +58,11 @@ class user_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.hdf["Data.Warning"] = "EmptyNewPassword"
|
||||
elif new_pw != new_pw2:
|
||||
self.hdf["Data.Warning"] = "DifferentPasswords"
|
||||
elif user in adminDict.keys():
|
||||
adminDict[user] = self.cbox.prefs.userDB.getDigest(new_pw)
|
||||
elif user in admin_dict.keys():
|
||||
admin_dict[user] = self.cbox.prefs.user_db.get_digest(new_pw)
|
||||
self.hdf["Data.Success"] = "Plugins.user_manager.PasswordChanged"
|
||||
try:
|
||||
self.cbox.prefs.userDB.write()
|
||||
self.cbox.prefs.user_db.write()
|
||||
except IOError:
|
||||
self.cbox.log.warn("failed to write user database")
|
||||
else:
|
||||
|
@ -69,31 +71,31 @@ class user_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
if user in RESERVED_USERS:
|
||||
self.cbox.log.info("user_manager: tried to remove reserved user (%s)" % user)
|
||||
self.hdf["Data.Warning"] = "NeverRemoveReservedUser"
|
||||
elif user in adminDict.keys():
|
||||
del adminDict[user]
|
||||
elif user in admin_dict.keys():
|
||||
del admin_dict[user]
|
||||
self.hdf["Data.Success"] = "Plugins.user_manager.UserRemoved"
|
||||
try:
|
||||
self.cbox.prefs.userDB.write()
|
||||
self.cbox.prefs.user_db.write()
|
||||
except IOError:
|
||||
self.cbox.log.warn("failed to write user database")
|
||||
else:
|
||||
self.cbox.log.info("user_manager: tried to remove non-existing user (%s)" % str(user))
|
||||
else:
|
||||
self.cbox.log.info("user_manager: invalid value of 'store' (%s)" % store)
|
||||
self.__prepareHDF(adminDict)
|
||||
self.__prepare_hdf(admin_dict)
|
||||
return "user_list"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return ":".join(self.cbox.prefs.userDB["admins"].keys())
|
||||
def get_status(self):
|
||||
return ":".join(self.cbox.prefs.user_db["admins"].keys())
|
||||
|
||||
|
||||
def __cleanHDF(self):
|
||||
def __clean_hdf(self):
|
||||
for key in self.hdf.keys():
|
||||
del self.hdf[key]
|
||||
|
||||
|
||||
def __prepareHDF(self, dict):
|
||||
def __prepare_hdf(self, dict):
|
||||
## sort by name
|
||||
users = dict.keys()
|
||||
users.sort()
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
"""try to read automount form"""
|
||||
url = self.URL + "volume_automount?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_automount?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('Activate during startup')
|
||||
|
@ -32,21 +34,21 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
|||
|
||||
def test_toggle(self):
|
||||
"""try to toggle automount property"""
|
||||
url = self.URL + "volume_automount"
|
||||
url = self.url + "volume_automount"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s1&action=disable" % self.device)
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=disable" % self.device)
|
||||
self.cmd.find("Automatic activation disabled")
|
||||
self.cmd.find("is disabled")
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s1&action=enable" % self.device)
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=enable" % self.device)
|
||||
self.cmd.find("Automatic activation enabled")
|
||||
self.cmd.notfind("is disabled")
|
||||
|
||||
|
||||
def test_invalid_input(self):
|
||||
"""check invalid inputs"""
|
||||
url = self.URL + "volume_automount"
|
||||
url = self.url + "volume_automount"
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s1&action=foobar" % self.device)
|
||||
self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=foobar" % self.device)
|
||||
self.cmd.notfind("Automatic activation disabled")
|
||||
self.cmd.notfind("Automatic activation enabled")
|
||||
|
||||
|
|
|
@ -18,58 +18,60 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
|
||||
|
||||
class volume_automount(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "properties" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "properties" ]
|
||||
request_auth = False
|
||||
rank = 80
|
||||
|
||||
trueString = "yes"
|
||||
falseString = "no"
|
||||
true_string = "yes"
|
||||
false_string = "no"
|
||||
|
||||
|
||||
def doAction(self, action=None):
|
||||
container = self.cbox.getContainer(self.device)
|
||||
def do_action(self, action=None):
|
||||
container = self.cbox.get_container(self.device)
|
||||
if action is None:
|
||||
pass
|
||||
elif action == "enable":
|
||||
container.attributes["automount"] = self.trueString
|
||||
container.attributes["automount"] = self.true_string
|
||||
self.hdf["Data.Success"] = "Plugins.volume_automount.AutoMountEnabled"
|
||||
self.cbox.log.info("volume_automount: enabled for device '%s'" % self.device)
|
||||
self.cbox.prefs.volumesDB.write()
|
||||
self.cbox.prefs.volumes_db.write()
|
||||
elif action == "disable":
|
||||
container.attributes["automount"] = self.falseString
|
||||
container.attributes["automount"] = self.false_string
|
||||
self.hdf["Data.Success"] = "Plugins.volume_automount.AutoMountDisabled"
|
||||
self.cbox.log.info("volume_automount: disabled for device '%s'" % self.device)
|
||||
self.cbox.prefs.volumesDB.write()
|
||||
self.cbox.prefs.volumes_db.write()
|
||||
else:
|
||||
self.cbox.log.info("volume_automount: invalid action (%s)" % str(action))
|
||||
self.__prepareHDF()
|
||||
self.__prepare_hdf()
|
||||
return "volume_automount"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
return str(self.__isAutoMount())
|
||||
def get_status(self):
|
||||
return str(self.__is_auto_mount())
|
||||
|
||||
|
||||
def __prepareHDF(self):
|
||||
if self.__isAutoMount():
|
||||
def __prepare_hdf(self):
|
||||
if self.__is_auto_mount():
|
||||
self.hdf[self.hdf_prefix + "automount_setting"] = "1"
|
||||
else:
|
||||
self.hdf[self.hdf_prefix + "automount_setting"] = "0"
|
||||
|
||||
|
||||
def __isAutoMount(self):
|
||||
container = self.cbox.getContainer(self.device)
|
||||
def __is_auto_mount(self):
|
||||
container = self.cbox.get_container(self.device)
|
||||
if not container:
|
||||
return False
|
||||
if container.attributes.has_key("automount"):
|
||||
return container.attributes["automount"] == self.trueString
|
||||
return container.attributes["automount"] == self.true_string
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_chpasswd?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_chpasswd?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('hange')
|
||||
|
|
|
@ -18,24 +18,26 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
|
||||
|
||||
class volume_chpasswd(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "properties" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "properties" ]
|
||||
request_auth = False
|
||||
rank = 70
|
||||
|
||||
|
||||
def doAction(self, store=None, old_pw=None, new_pw=None, new_pw2=None):
|
||||
self.container = self.cbox.getContainer(self.device)
|
||||
def do_action(self, store=None, old_pw=None, new_pw=None, new_pw2=None):
|
||||
self.container = self.cbox.get_container(self.device)
|
||||
if not self.container:
|
||||
return None
|
||||
elif store == "change_pw":
|
||||
return self.__changePassword(old_pw, new_pw, new_pw2)
|
||||
return self.__change_password(old_pw, new_pw, new_pw2)
|
||||
elif not store:
|
||||
return "volume_chpasswd"
|
||||
else:
|
||||
|
@ -43,11 +45,11 @@ class volume_chpasswd(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return "volume_chpasswd"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "TODO"
|
||||
|
||||
|
||||
def __changePassword(self, old_pw, new_pw, new_pw2):
|
||||
def __change_password(self, old_pw, new_pw, new_pw2):
|
||||
if not old_pw:
|
||||
self.hdf["Data.Warning"] = "EmptyPassword"
|
||||
elif not new_pw:
|
||||
|
@ -59,13 +61,13 @@ class volume_chpasswd(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
pass
|
||||
else:
|
||||
try:
|
||||
self.container.changePassword(old_pw, new_pw)
|
||||
except CBInvalidType, errMsg:
|
||||
self.cbox.log.info("plugin 'volume_chpasswd' - cannot change passphrase for non-encrypted container (%s): %s" % (self.device, errMsg))
|
||||
self.container.change_password(old_pw, new_pw)
|
||||
except CBInvalidType, err_msg:
|
||||
self.cbox.log.info("plugin 'volume_chpasswd' - cannot change passphrase for non-encrypted container (%s): %s" % (self.device, err_msg))
|
||||
except CBVolumeIsActive:
|
||||
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
|
||||
except CBChangePasswordError, errMsg:
|
||||
self.cbox.log.warn("plugin 'volume_chpasswd' - cannot change password for device (%s): %s" % (self.device, errMsg))
|
||||
except CBChangePasswordError, err_msg:
|
||||
self.cbox.log.warn("plugin 'volume_chpasswd' - cannot change password for device (%s): %s" % (self.device, err_msg))
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_chpasswd.PasswordChange"
|
||||
else:
|
||||
self.hdf["Data.Success"] = "Plugins.volume_chpasswd.PasswordChange"
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_details?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_details?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('Technical details')
|
||||
|
|
|
@ -18,22 +18,24 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
|
||||
|
||||
class volume_details(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "volume" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "volume" ]
|
||||
request_auth = False
|
||||
rank = 100
|
||||
|
||||
|
||||
def doAction(self):
|
||||
def do_action(self):
|
||||
## all variables are already set somewhere else
|
||||
return "volume_details"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "no status"
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_format_fs?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_format_fs?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('Initializing filesystem')
|
||||
|
|
|
@ -18,32 +18,33 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
import cryptobox.core.container as cbxContainer
|
||||
import cryptobox.core.container as cbx_container
|
||||
|
||||
## map filesystem types to the appropriate arguments for 'mkfs'
|
||||
FSTYPES = {
|
||||
"windows": "vfat",
|
||||
"linux": "ext3" }
|
||||
|
||||
|
||||
class volume_format_fs(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "volume" ]
|
||||
requestAuth = True
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "volume" ]
|
||||
request_auth = True
|
||||
rank = 60
|
||||
|
||||
## map filesystem types to the appropriate arguments for 'mkfs'
|
||||
fsTypes = {
|
||||
"windows": "vfat",
|
||||
"linux": "ext3" }
|
||||
|
||||
containerTypes = [ "luks", "plain" ]
|
||||
|
||||
|
||||
def doAction(self, store=None, fs_type="windows", container_type="luks", crypto_password=None, crypto_password2=None, confirm=None):
|
||||
if not fs_type in self.fsTypes.keys():
|
||||
def do_action(self, store=None, fs_type="windows", container_type="luks", crypto_password=None, crypto_password2=None, confirm=None):
|
||||
if not fs_type in FSTYPES.keys():
|
||||
self.cbox.info
|
||||
return "format_volume"
|
||||
self.hdf[self.hdf_prefix + "fs_type"] = fs_type
|
||||
self.hdf[self.hdf_prefix + "container_type"] = container_type
|
||||
for t in self.fsTypes.keys():
|
||||
for t in FSTYPES.keys():
|
||||
self.hdf[self.hdf_prefix + "fs_types." + t] = t
|
||||
if store == "step1":
|
||||
if not confirm:
|
||||
|
@ -67,14 +68,14 @@ class volume_format_fs(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return "volume_format"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "no status"
|
||||
|
||||
|
||||
def __format_plain(self, fsType):
|
||||
try:
|
||||
container = self.cbox.getContainer(self.device)
|
||||
container.create(cbxContainer.ContainerTypes["plain"])
|
||||
container = self.cbox.get_container(self.device)
|
||||
container.create(cbx_container.CONTAINERTYPES["plain"])
|
||||
except CBVolumeIsActive:
|
||||
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
|
||||
self.cbox.log.info("initialization is not possible as long as the device (%s) is mounted" % self.device)
|
||||
|
@ -98,9 +99,9 @@ class volume_format_fs(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.hdf["Data.Warning"] = "DifferentPasswords"
|
||||
self.cbox.log.warn("the crypto password was not repeated correctly for initialization of device '%s'" % self.device)
|
||||
return "volume_format"
|
||||
container = self.cbox.getContainer(self.device)
|
||||
container = self.cbox.get_container(self.device)
|
||||
try:
|
||||
container.create(cbxContainer.ContainerTypes["luks"], pw)
|
||||
container.create(cbx_container.CONTAINERTYPES["luks"], pw)
|
||||
except CBVolumeIsActive:
|
||||
self.hdf["Data.Warning"] = "VolumeMayNotBeMounted"
|
||||
self.cbox.log.info("initialization is not possible as long as the device (%s) is mounted" % self.device)
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_mount?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_mount?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('ctivate volume')
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
import cryptobox.core.container as cbxContainer
|
||||
|
@ -25,20 +27,20 @@ import cryptobox.core.container as cbxContainer
|
|||
|
||||
class volume_mount(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "volume" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "volume" ]
|
||||
request_auth = False
|
||||
rank = 0
|
||||
|
||||
|
||||
def doAction(self, action=None, pw=None):
|
||||
self.container = self.cbox.getContainer(self.device)
|
||||
def do_action(self, action=None, pw=None):
|
||||
self.container = self.cbox.get_container(self.device)
|
||||
if action == "mount_plain":
|
||||
return self.__doMountPlain()
|
||||
return self.__do_mount_plain()
|
||||
elif action == "mount_luks":
|
||||
return self.__doMountLuks(pw)
|
||||
return self.__do_mount_luks(pw)
|
||||
elif action == "umount":
|
||||
return self.__doUmount()
|
||||
return self.__do_umount()
|
||||
elif not action:
|
||||
return "volume_status"
|
||||
else:
|
||||
|
@ -46,43 +48,43 @@ class volume_mount(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return None
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
container = self.cbox.getContainer(self.device)
|
||||
def get_status(self):
|
||||
container = self.cbox.get_container(self.device)
|
||||
if not self.container:
|
||||
return "invalid device"
|
||||
if container.isMounted():
|
||||
if container.is_mounted():
|
||||
return "active"
|
||||
else:
|
||||
return "passive"
|
||||
|
||||
|
||||
def __doMountPlain(self):
|
||||
if self.container.isMounted():
|
||||
def __do_mount_plain(self):
|
||||
if self.container.is_mounted():
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsAlreadyMounted"
|
||||
self.cbox.log.info("the device (%s) is already mounted" % self.device)
|
||||
return "volume_status"
|
||||
if self.container.getType() != cbxContainer.ContainerTypes["plain"]:
|
||||
if self.container.get_type() != cbxContainer.CONTAINERTYPES["plain"]:
|
||||
## not a plain container
|
||||
self.cbox.log.info("plugin 'volume_mount' - invalid container type")
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.InvalidContainerType"
|
||||
return "volume_status"
|
||||
try:
|
||||
self.container.mount()
|
||||
except CBMountError, errMsg:
|
||||
except CBMountError, err_msg:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountFailed"
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, err_msg))
|
||||
return "volume_status"
|
||||
except CBContainerError, errMsg:
|
||||
except CBContainerError, err_msg:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountFailed"
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, err_msg))
|
||||
return "volume_status"
|
||||
self.cbox.log.info("successfully mounted the volume: %s" % self.device)
|
||||
self.hdf["Data.Success"] = "Plugins.volume_mount.MountDone"
|
||||
return "volume_status"
|
||||
|
||||
|
||||
def __doMountLuks(self, pw):
|
||||
if self.container.isMounted():
|
||||
def __do_mount_luks(self, pw):
|
||||
if self.container.is_mounted():
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsAlreadyMounted"
|
||||
self.cbox.log.info("the device (%s) is already mounted" % self.device)
|
||||
return "volume_status"
|
||||
|
@ -90,35 +92,35 @@ class volume_mount(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.dataset["Data.Warning"] = "EmptyPassword"
|
||||
self.log.info("no password was supplied for mounting of device: '%s'" % self.device)
|
||||
return "volume_status"
|
||||
if self.container.getType() != cbxContainer.ContainerTypes["luks"]:
|
||||
if self.container.get_type() != cbxContainer.CONTAINERTYPES["luks"]:
|
||||
## not a luks container - fail silently
|
||||
self.cbox.log.info("plugin 'volume_mount' - invalid container type")
|
||||
return "volume_status"
|
||||
try:
|
||||
self.container.mount(pw)
|
||||
except CBMountError, errMsg:
|
||||
except CBMountError, err_msg:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountCryptoFailed"
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, err_msg))
|
||||
return "volume_status"
|
||||
except CBContainerError, errMsg:
|
||||
except CBContainerError, err_msg:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.MountCryptoFailed"
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, errMsg))
|
||||
self.cbox.log.warn("failed to mount the device (%s): %s" % (self.device, err_msg))
|
||||
return "volume_status"
|
||||
self.cbox.log.info("successfully mounted the volume: %s" % self.device)
|
||||
self.hdf["Data.Success"] = "Plugins.volume_mount.MountDone"
|
||||
return "volume_status"
|
||||
|
||||
|
||||
def __doUmount(self):
|
||||
if not self.container.isMounted():
|
||||
def __do_umount(self):
|
||||
if not self.container.is_mounted():
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_mount.IsNotMounted"
|
||||
self.cbox.log.info("the device (%s) is currently not mounted" % self.device)
|
||||
return "volume_status"
|
||||
try:
|
||||
self.container.umount()
|
||||
except CBUmountError, errMsg:
|
||||
except CBUmountError, err_msg:
|
||||
self.hdf["Data.Warning"] = "UmountFailed"
|
||||
self.cbox.log.warn("could not umount the volume (%s): %s" % (self.device, errMsg))
|
||||
self.cbox.log.warn("could not umount the volume (%s): %s" % (self.device, err_msg))
|
||||
return "volume_status"
|
||||
self.cbox.log.info("successfully unmounted the container: %s" % self.device)
|
||||
self.hdf["Data.Success"] = "Plugins.volume_mount.UmountDone"
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_props?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_props?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('Properties')
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
import cryptobox.plugins.manage
|
||||
from cryptobox.core.exceptions import *
|
||||
|
@ -25,51 +27,54 @@ from cryptobox.core.exceptions import *
|
|||
|
||||
class volume_props(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "volume" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "volume" ]
|
||||
request_auth = False
|
||||
rank = 30
|
||||
|
||||
|
||||
def doAction(self, **args):
|
||||
def do_action(self, **args):
|
||||
import os
|
||||
self.props_plugins = [e for e in cryptobox.plugins.manage.PluginManager(self.cbox, self.cbox.prefs["Locations"]["PluginDir"]).getPlugins() if "properties" in e.getVisibility()]
|
||||
self.props_plugins = [e for e in cryptobox.plugins.manage.PluginManager(self.cbox,
|
||||
self.cbox.prefs["Locations"]["PluginDir"]).get_plugins()
|
||||
if "properties" in e.get_visibility()]
|
||||
## sort plugins by rank
|
||||
self.props_plugins.sort(cmp = self.__cmpPluginsRank)
|
||||
self.props_plugins.sort(cmp = self.__cmp_plugins_rank)
|
||||
## set the name of the templates for every plugin
|
||||
loadString = ""
|
||||
load_string = ""
|
||||
for p in self.props_plugins:
|
||||
p.device = self.device
|
||||
plfname = os.path.join(p.pluginDir, str(p.doAction(**args)) + ".cs")
|
||||
loadString += "<?cs include:'%s' ?>" % plfname
|
||||
plfname = os.path.join(p.plugin_dir, str(p.do_action(**args)) + ".cs")
|
||||
load_string += "<?cs include:'%s' ?>" % plfname
|
||||
## this is a little bit ugly: as it is not possible, to load cs files via
|
||||
## 'linclude' (see clearsilver doc) if they use previously defined macros (see
|
||||
## clearsilver mailing list thread 'linclude file which calls a macro' - 27th
|
||||
## December 02005)
|
||||
## our workaround: define the appropriate "include" (not 'linclude') commands
|
||||
## as a hdf variable - then we can include it via 'evar'
|
||||
self.hdf[self.hdf_prefix + 'includePlugins'] = loadString
|
||||
self.hdf[self.hdf_prefix + 'includePlugins'] = load_string
|
||||
return "volume_properties"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
def get_status(self):
|
||||
return "TODO"
|
||||
|
||||
|
||||
def loadDataSet(self, hdf):
|
||||
def load_dataset(self, hdf):
|
||||
"""override the parent's function
|
||||
we have to get the data from all included plugins"""
|
||||
for p in self.props_plugins:
|
||||
p.loadDataSet(hdf)
|
||||
for plugin in self.props_plugins:
|
||||
plugin.load_dataset(hdf)
|
||||
## call our parent's method
|
||||
cryptobox.plugins.base.CryptoBoxPlugin.loadDataSet(self, hdf)
|
||||
cryptobox.plugins.base.CryptoBoxPlugin.load_dataset(self, hdf)
|
||||
|
||||
|
||||
def __cmpPluginsRank(self, p1, p2):
|
||||
order = p1.getRank() - p2.getRank()
|
||||
def __cmp_plugins_rank(self, p1, p2):
|
||||
order = p1.get_rank() - p2.get_rank()
|
||||
if order < 0:
|
||||
return -1
|
||||
elif order == 0:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.web.testclass
|
||||
|
||||
class unittests(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
|
||||
def test_read_form(self):
|
||||
url = self.URL + "volume_rename?weblang=en&device=%2Fdev%2F" + self.device + "1"
|
||||
url = self.url + "volume_rename?weblang=en&device=%2Fdev%2F" + self.device
|
||||
self.register_auth(url)
|
||||
self.cmd.go(url)
|
||||
self.cmd.find('name')
|
||||
|
|
|
@ -18,49 +18,51 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
|
||||
|
||||
class volume_rename(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||
|
||||
pluginCapabilities = [ "volume" ]
|
||||
pluginVisibility = [ "properties" ]
|
||||
requestAuth = False
|
||||
plugin_capabilities = [ "volume" ]
|
||||
plugin_visibility = [ "properties" ]
|
||||
request_auth = False
|
||||
rank = 60
|
||||
|
||||
|
||||
def doAction(self, store=None, vol_name=None):
|
||||
self.container = self.cbox.getContainer(self.device)
|
||||
def do_action(self, store=None, vol_name=None):
|
||||
self.container = self.cbox.get_container(self.device)
|
||||
if not self.container:
|
||||
return None
|
||||
self.__prepareHDF()
|
||||
self.__prepare_hdf()
|
||||
if store and vol_name:
|
||||
return self.__setVolumeName(vol_name)
|
||||
return self.__set_volume_name(vol_name)
|
||||
else:
|
||||
return "volume_rename"
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
self.container = self.cbox.getContainer(self.device)
|
||||
def get_status(self):
|
||||
self.container = self.cbox.get_container(self.device)
|
||||
if not self.container:
|
||||
return "invalid device"
|
||||
return "name=%s" % self.container.getName()
|
||||
return "name=%s" % self.container.get_name()
|
||||
|
||||
|
||||
def __prepareHDF(self):
|
||||
self.hdf[self.hdf_prefix + "vol_name"] = self.container.getName()
|
||||
def __prepare_hdf(self):
|
||||
self.hdf[self.hdf_prefix + "vol_name"] = self.container.get_name()
|
||||
|
||||
|
||||
def __setVolumeName(self, vol_name):
|
||||
def __set_volume_name(self, vol_name):
|
||||
if not vol_name:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_rename.InvalidVolumeName"
|
||||
return "volume_rename"
|
||||
if vol_name == self.container.getName():
|
||||
if vol_name == self.container.get_name():
|
||||
## nothing has to be done
|
||||
return "volume_rename"
|
||||
try:
|
||||
self.container.setName(vol_name)
|
||||
self.container.set_name(vol_name)
|
||||
self.hdf["Data.Success"] = "Plugins.volume_rename.VolumeNameChanged"
|
||||
except CBVolumeIsActive:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_rename.NoRenameIfActive"
|
||||
|
@ -71,6 +73,6 @@ class volume_rename(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
except CBContainerError:
|
||||
self.hdf["Data.Warning"] = "Plugins.volume_rename.SetVolumeNameFailed"
|
||||
## reread the volume name
|
||||
self.__prepareHDF()
|
||||
self.__prepare_hdf()
|
||||
return "volume_rename"
|
||||
|
||||
|
|
|
@ -1 +1,13 @@
|
|||
__all__ = ['core','web','plugins','tests']
|
||||
"""CryptoBox package
|
||||
|
||||
The CryptoBox is a webserver. It enables you to control your encrypted
|
||||
(cryptsetup-luks) and plaintext disks via an easy to use web interface.
|
||||
The CryptoBox is especially suitable for non-desktop fileservers with
|
||||
encrypted partitions.
|
||||
"""
|
||||
|
||||
__all__ = ['core', 'web', 'plugins', 'tests']
|
||||
__revision__ = "$Id$"
|
||||
|
||||
__version__ = "0.2.99~1"
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"""Core management functions of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
__all__ = [ 'main', 'container', 'exceptions', 'tools', 'settings' ]
|
||||
|
|
@ -18,21 +18,18 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
## check python version
|
||||
import sys
|
||||
(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)):
|
||||
sys.stderr.write("You need a python version >= 2.4\nCurrent version is:\n %s\n" % sys.version)
|
||||
sys.exit(1)
|
||||
"""Manage a single container of the CryptoBox
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
from cryptobox.core.exceptions import *
|
||||
|
||||
|
||||
ContainerTypes = {
|
||||
CONTAINERTYPES = {
|
||||
"unused":0,
|
||||
"plain":1,
|
||||
"luks":2,
|
||||
|
@ -46,11 +43,12 @@ MOUNT_DIR_MARKER = '_cryptobox_mount_dir_'
|
|||
|
||||
|
||||
class CryptoBoxContainer:
|
||||
"""Manage a container of the CryptoBox
|
||||
"""
|
||||
|
||||
__fsTypes = {
|
||||
"plain":["ext3", "ext2", "vfat", "reiser"],
|
||||
"plain":["ext3", "ext2", "vfat", "reiserfs"],
|
||||
"swap":["swap"]}
|
||||
# TODO: more filesystem types? / check 'reiser'
|
||||
|
||||
__dmDir = "/dev/mapper"
|
||||
|
||||
|
@ -58,41 +56,58 @@ class CryptoBoxContainer:
|
|||
def __init__(self, device, cbox):
|
||||
self.device = device
|
||||
self.cbox = cbox
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
self.resetObject()
|
||||
self.uuid = None
|
||||
self.name = None
|
||||
self.cont_type = None
|
||||
self.mount = None
|
||||
self.umount = None
|
||||
self.attributes = None
|
||||
self.reset_object()
|
||||
|
||||
|
||||
def getName(self):
|
||||
def get_name(self):
|
||||
"""Return a humanly readable name for the container.
|
||||
"""
|
||||
return self.name
|
||||
|
||||
|
||||
def __setAttributes(self):
|
||||
def __set_attributes(self):
|
||||
"""Define the default attributes of a container.
|
||||
|
||||
At least there should be a uuid.
|
||||
Other attributes may be added by features (e.g. automount).
|
||||
"""
|
||||
try:
|
||||
## is there already an entry in the database?
|
||||
self.attributes = self.cbox.prefs.volumesDB[self.getName()]
|
||||
self.attributes = self.cbox.prefs.volumes_db[self.get_name()]
|
||||
self.attributes["uuid"] = self.uuid
|
||||
except KeyError:
|
||||
## set default values
|
||||
self.attributes = { "uuid": self.uuid }
|
||||
self.cbox.prefs.volumesDB[self.getName()] = self.attributes
|
||||
self.cbox.prefs.volumes_db[self.get_name()] = self.attributes
|
||||
|
||||
|
||||
def setName(self, new_name):
|
||||
old_name = self.getName()
|
||||
if new_name == self.name: return
|
||||
def set_name(self, new_name):
|
||||
"""Define a humanly readable name of this container.
|
||||
|
||||
this also manages the name database
|
||||
"""
|
||||
old_name = self.get_name()
|
||||
if new_name == self.name:
|
||||
return
|
||||
## renaming is not possible, if the volume is active, as the mountpoint name
|
||||
## is the same as the volume name
|
||||
if self.isMounted():
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("the container must not be active during renaming")
|
||||
if not re.search(r'^[a-zA-Z0-9_\.\- ]+$', new_name):
|
||||
raise CBInvalidName("the supplied new name contains illegal characters")
|
||||
## check for another partitions with the same name
|
||||
if self.cbox.getContainerList(filterName=new_name):
|
||||
if self.cbox.get_container_list(filter_name=new_name):
|
||||
raise CBNameIsInUse("the supplied new name is already in use for anonther partition")
|
||||
## maybe there a is an entry in the volumes database (but the partition is not active
|
||||
try:
|
||||
## remove possibly existing inactive database item
|
||||
del self.cbox.prefs.volumesDB[new_name]
|
||||
del self.cbox.prefs.volumes_db[new_name]
|
||||
except KeyError:
|
||||
## no entry - so nothing happens
|
||||
pass
|
||||
|
@ -100,99 +115,116 @@ class CryptoBoxContainer:
|
|||
self.name = new_name
|
||||
## remove old database entry
|
||||
try:
|
||||
del self.cbox.prefs.volumesDB[old_name]
|
||||
del self.cbox.prefs.volumes_db[old_name]
|
||||
except KeyError:
|
||||
pass
|
||||
## set new volumes database entry
|
||||
self.cbox.prefs.volumesDB[new_name] = self.attributes
|
||||
self.cbox.prefs.volumesDB.write()
|
||||
self.cbox.prefs.volumes_db[new_name] = self.attributes
|
||||
self.cbox.prefs.volumes_db.write()
|
||||
|
||||
|
||||
def getDevice(self):
|
||||
def get_device(self):
|
||||
"""Return the device name of the container
|
||||
|
||||
e.g.: /dev/hdc1
|
||||
"""
|
||||
return self.device
|
||||
|
||||
|
||||
def getType(self):
|
||||
return self.type
|
||||
def get_type(self):
|
||||
"""Return the type (int) of this container.
|
||||
"""
|
||||
return self.cont_type
|
||||
|
||||
|
||||
def isMounted(self):
|
||||
return os.path.ismount(self.__getMountPoint())
|
||||
def is_mounted(self):
|
||||
"""Check if the container is currently mounted.
|
||||
"""
|
||||
return os.path.ismount(self.__get_mount_point())
|
||||
|
||||
|
||||
def getCapacity(self):
|
||||
"""return the current capacity state of the volume
|
||||
def get_capacity(self):
|
||||
"""Return the current capacity state of the volume.
|
||||
|
||||
the volume may not be mounted
|
||||
the result is a tuple of values in megabyte:
|
||||
(size, available, used)
|
||||
"""
|
||||
info = os.statvfs(self.__getMountPoint())
|
||||
info = os.statvfs(self.__get_mount_point())
|
||||
return (
|
||||
int(info.f_bsize*info.f_blocks/1024/1024),
|
||||
int(info.f_bsize*info.f_bavail/1024/1024),
|
||||
int(info.f_bsize*(info.f_blocks-info.f_bavail)/1024/1024))
|
||||
|
||||
|
||||
def getSize(self):
|
||||
def get_size(self):
|
||||
"""return the size of the block device (_not_ of the filesystem)
|
||||
|
||||
the result is a value in megabyte
|
||||
an error is indicated by "-1"
|
||||
"""
|
||||
import cryptobox.core.tools as cbxtools
|
||||
return cbxtools.getBlockDeviceSize(self.device)
|
||||
return cbxtools.get_blockdevice_size(self.device)
|
||||
|
||||
|
||||
def resetObject(self):
|
||||
def reset_object(self):
|
||||
""" recheck the information about this container
|
||||
this is especially useful after changing the type via 'create' """
|
||||
self.uuid = self.__getUUID()
|
||||
self.type = self.__getTypeOfPartition()
|
||||
self.name = self.__getNameOfContainer()
|
||||
self.__setAttributes()
|
||||
if self.type == ContainerTypes["luks"]:
|
||||
self.mount = self.__mountLuks
|
||||
self.umount = self.__umountLuks
|
||||
elif self.type == ContainerTypes["plain"]:
|
||||
self.mount = self.__mountPlain
|
||||
self.umount = self.__umountPlain
|
||||
self.uuid = self.__get_uuid()
|
||||
self.cont_type = self.__get_type_of_partition()
|
||||
self.name = self.__get_name_of_container()
|
||||
self.__set_attributes()
|
||||
if self.cont_type == CONTAINERTYPES["luks"]:
|
||||
self.mount = self.__mount_luks
|
||||
self.umount = self.__umount_luks
|
||||
elif self.cont_type == CONTAINERTYPES["plain"]:
|
||||
self.mount = self.__mount_plain
|
||||
self.umount = self.__umount_plain
|
||||
|
||||
|
||||
def create(self, type, password=None):
|
||||
old_name = self.getName()
|
||||
if type == ContainerTypes["luks"]:
|
||||
self.__createLuks(password)
|
||||
elif type == ContainerTypes["plain"]:
|
||||
self.__createPlain()
|
||||
def create(self, cont_type, password=None):
|
||||
"""Format a container.
|
||||
|
||||
Also set a password for encrypted container.
|
||||
"""
|
||||
old_name = self.get_name()
|
||||
if cont_type == CONTAINERTYPES["luks"]:
|
||||
self.__create_luks(password)
|
||||
elif cont_type == CONTAINERTYPES["plain"]:
|
||||
self.__create_plain()
|
||||
else:
|
||||
raise CBInvalidType("invalid container type (%d) supplied" % (type, ))
|
||||
raise CBInvalidType("invalid container type (%d) supplied" % (cont_type, ))
|
||||
## no exception was raised during creation -> we can continue
|
||||
## reset the properties (encryption state, ...) of the device
|
||||
self.resetObject()
|
||||
## restore the old name (must be after resetObject)
|
||||
self.setName(old_name)
|
||||
self.reset_object()
|
||||
## restore the old name (must be after reset_object)
|
||||
self.set_name(old_name)
|
||||
|
||||
|
||||
def changePassword(self, oldpw, newpw):
|
||||
if self.type != ContainerTypes["luks"]:
|
||||
def change_password(self, oldpw, newpw):
|
||||
"""Change the password of an encrypted container.
|
||||
|
||||
Raises an exception for plaintext container.
|
||||
"""
|
||||
if self.cont_type != CONTAINERTYPES["luks"]:
|
||||
raise CBInvalidType("changing of password is possible only for luks containers")
|
||||
if not oldpw:
|
||||
raise CBInvalidPassword("no old password supplied for password change")
|
||||
if not newpw:
|
||||
raise CBInvalidPassword("no new password supplied for password change")
|
||||
"return if new and old passwords are the same"
|
||||
if oldpw == newpw: return
|
||||
if self.isMounted():
|
||||
## return if new and old passwords are the same
|
||||
if oldpw == newpw:
|
||||
return
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("this container is currently active")
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
"remove any potential open luks mapping"
|
||||
self.__umountLuks()
|
||||
"create the luks header"
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
## remove any potential open luks mapping
|
||||
self.__umount_luks()
|
||||
## create the luks header
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = subprocess.PIPE,
|
||||
|
@ -208,16 +240,17 @@ class CryptoBoxContainer:
|
|||
proc.stdin.write("%s\n%s" % (oldpw, newpw))
|
||||
(output, errout) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not add a new luks key: %s - %s" % (output.strip(), errout.strip(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBChangePasswordError(errorMsg)
|
||||
error_msg = "Could not add a new luks key: %s - %s" \
|
||||
% (output.strip(), errout.strip(), )
|
||||
self.cbox.log.error(error_msg)
|
||||
raise CBChangePasswordError(error_msg)
|
||||
## retrieve the key slot we used for unlocking
|
||||
keys_found = re.search(r'key slot (\d{1,3}) unlocked', output).groups()
|
||||
if keys_found:
|
||||
keyslot = int(keys_found[0])
|
||||
else:
|
||||
raise CBChangePasswordError("could not get the old key slot")
|
||||
"remove the old key"
|
||||
## remove the old key
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -231,40 +264,43 @@ class CryptoBoxContainer:
|
|||
"%d" % (keyslot, )])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not remove the old luks key: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBChangePasswordError(errorMsg)
|
||||
error_msg = "Could not remove the old luks key: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.error(error_msg)
|
||||
raise CBChangePasswordError(error_msg)
|
||||
|
||||
|
||||
|
||||
" ****************** internal stuff ********************* "
|
||||
## ****************** internal stuff *********************
|
||||
|
||||
def __getNameOfContainer(self):
|
||||
def __get_name_of_container(self):
|
||||
"""retrieve the name of the container by querying the database
|
||||
call this function only for the initial setup of the container object"""
|
||||
found_name = None
|
||||
for key in self.cbox.prefs.volumesDB.keys():
|
||||
if self.cbox.prefs.volumesDB[key]["uuid"] == self.uuid:
|
||||
for key in self.cbox.prefs.volumes_db.keys():
|
||||
if self.cbox.prefs.volumes_db[key]["uuid"] == self.uuid:
|
||||
found_name = key
|
||||
if found_name: return found_name
|
||||
if found_name:
|
||||
return found_name
|
||||
## there is no name defined for this uuid - we will propose a good one
|
||||
prefix = self.cbox.prefs["Main"]["DefaultVolumePrefix"]
|
||||
unused_found = False
|
||||
counter = 1
|
||||
while not unused_found:
|
||||
guess = prefix + str(counter)
|
||||
if self.cbox.prefs.volumesDB.has_key(guess):
|
||||
if self.cbox.prefs.volumes_db.has_key(guess):
|
||||
counter += 1
|
||||
else:
|
||||
unused_found = True
|
||||
return guess
|
||||
|
||||
|
||||
def __getUUID(self):
|
||||
if self.__getTypeOfPartition() == ContainerTypes["luks"]:
|
||||
guess = self.__getLuksUUID()
|
||||
def __get_uuid(self):
|
||||
"""Retrieve the uuid of the container device.
|
||||
"""
|
||||
if self.__get_type_of_partition() == CONTAINERTYPES["luks"]:
|
||||
guess = self.__get_luks_uuid()
|
||||
else:
|
||||
guess = self.__getNonLuksUUID()
|
||||
guess = self.__get_non_luks_uuid()
|
||||
## did we get a valid value?
|
||||
if guess:
|
||||
return guess
|
||||
|
@ -273,7 +309,7 @@ class CryptoBoxContainer:
|
|||
return self.device.replace(os.path.sep, "_")
|
||||
|
||||
|
||||
def __getLuksUUID(self):
|
||||
def __get_luks_uuid(self):
|
||||
"""get uuid for luks devices"""
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
|
@ -284,17 +320,18 @@ class CryptoBoxContainer:
|
|||
self.device])
|
||||
(stdout, stderr) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
self.cbox.log.info("could not retrieve luks uuid (%s): %s", (self.device, stderr.strip()))
|
||||
self.cbox.log.info("could not retrieve luks uuid (%s): %s",
|
||||
(self.device, stderr.strip()))
|
||||
return None
|
||||
return stdout.strip()
|
||||
|
||||
|
||||
def __getNonLuksUUID(self):
|
||||
def __get_non_luks_uuid(self):
|
||||
"""return UUID for ext2/3 and vfat filesystems"""
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
proc = subprocess.Popen(
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
|
@ -309,30 +346,36 @@ class CryptoBoxContainer:
|
|||
devnull.close()
|
||||
## execution failed?
|
||||
if proc.returncode != 0:
|
||||
self.log.info("retrieving of partition type (%s) via 'blkid' failed: %s - maybe it is encrypted?" % (self.device, stderr.strip()))
|
||||
self.cbox.log.info("retrieving of partition type (" + str(self.device) \
|
||||
+ ") via 'blkid' failed: " + str(stderr.strip()) \
|
||||
+ " - maybe it is encrypted?")
|
||||
return None
|
||||
## return output of blkid
|
||||
return stdout.strip()
|
||||
|
||||
|
||||
def __getTypeOfPartition(self):
|
||||
"retrieve the type of the given partition (see cryptobox.core.container.ContainerTypes)"
|
||||
if self.__isLuksPartition(): return ContainerTypes["luks"]
|
||||
typeOfPartition = self.__getTypeIdOfPartition()
|
||||
if typeOfPartition in self.__fsTypes["plain"]:
|
||||
return ContainerTypes["plain"]
|
||||
if typeOfPartition in self.__fsTypes["swap"]:
|
||||
return ContainerTypes["swap"]
|
||||
return ContainerTypes["unused"]
|
||||
def __get_type_of_partition(self):
|
||||
"""Retrieve the type of the given partition.
|
||||
|
||||
see cryptobox.core.container.CONTAINERTYPES
|
||||
"""
|
||||
if self.__is_luks_partition():
|
||||
return CONTAINERTYPES["luks"]
|
||||
type_of_partition = self.__get_type_id_of_partition()
|
||||
if type_of_partition in self.__fsTypes["plain"]:
|
||||
return CONTAINERTYPES["plain"]
|
||||
if type_of_partition in self.__fsTypes["swap"]:
|
||||
return CONTAINERTYPES["swap"]
|
||||
return CONTAINERTYPES["unused"]
|
||||
|
||||
|
||||
def __getTypeIdOfPartition(self):
|
||||
def __get_type_id_of_partition(self):
|
||||
"returns the type of the partition (see 'man blkid')"
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
proc = subprocess.Popen(
|
||||
shell=False,
|
||||
stdin=None,
|
||||
|
@ -347,19 +390,20 @@ class CryptoBoxContainer:
|
|||
proc.wait()
|
||||
output = proc.stdout.read().strip()
|
||||
if proc.returncode != 0:
|
||||
self.log.warn("retrieving of partition type via 'blkid' failed: %s" % (proc.stderr.read().strip(), ))
|
||||
self.cbox.log.warn("retrieving of partition type via 'blkid' failed: %s" % \
|
||||
(proc.stderr.read().strip(), ))
|
||||
return None
|
||||
devnull.close()
|
||||
return output
|
||||
|
||||
|
||||
def __isLuksPartition(self):
|
||||
def __is_luks_partition(self):
|
||||
"check if the given device is a luks partition"
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -375,29 +419,30 @@ class CryptoBoxContainer:
|
|||
return proc.returncode == 0
|
||||
|
||||
|
||||
def __getMountPoint(self):
|
||||
def __get_mount_point(self):
|
||||
"return the name of the mountpoint of this volume"
|
||||
return os.path.join(self.cbox.prefs["Locations"]["MountParentDir"], self.name)
|
||||
|
||||
|
||||
def __mountLuks(self, password):
|
||||
def __mount_luks(self, password):
|
||||
"mount a luks partition"
|
||||
if not password:
|
||||
raise CBInvalidPassword("no password supplied for luksOpen")
|
||||
if self.isMounted(): raise CBVolumeIsActive("this container is already active")
|
||||
self.__umountLuks()
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("this container is already active")
|
||||
self.__umount_luks()
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.__cleanMountDirs()
|
||||
if not os.path.exists(self.__getMountPoint()):
|
||||
self.__createMountDirectory(self.__getMountPoint())
|
||||
if not os.path.exists(self.__getMountPoint()):
|
||||
errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBMountError(errorMsg)
|
||||
self.cbox.sendEventNotification("premount", self.__getEventArgs())
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.__clean_mount_dirs()
|
||||
if not os.path.exists(self.__get_mount_point()):
|
||||
self.__create_mount_directory(self.__get_mount_point())
|
||||
if not os.path.exists(self.__get_mount_point()):
|
||||
err_msg = "Could not create mountpoint (%s)" % (self.__get_mount_point(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
raise CBMountError(err_msg)
|
||||
self.cbox.send_event_notification("premount", self.__get_event_args())
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = subprocess.PIPE,
|
||||
|
@ -414,9 +459,9 @@ class CryptoBoxContainer:
|
|||
proc.stdin.write(password)
|
||||
(output, errout) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not open the luks mapping: %s" % (errout.strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBMountError(errorMsg)
|
||||
err_msg = "Could not open the luks mapping: %s" % (errout.strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBMountError(err_msg)
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -427,25 +472,25 @@ class CryptoBoxContainer:
|
|||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"mount",
|
||||
os.path.join(self.__dmDir, self.name),
|
||||
self.__getMountPoint()])
|
||||
self.__get_mount_point()])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBMountError(errorMsg)
|
||||
err_msg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBMountError(err_msg)
|
||||
devnull.close()
|
||||
self.cbox.sendEventNotification("postmount", self.__getEventArgs())
|
||||
self.cbox.send_event_notification("postmount", self.__get_event_args())
|
||||
|
||||
|
||||
def __umountLuks(self):
|
||||
def __umount_luks(self):
|
||||
"umount a luks partition"
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.sendEventNotification("preumount", self.__getEventArgs())
|
||||
if self.isMounted():
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.send_event_notification("preumount", self.__get_event_args())
|
||||
if self.is_mounted():
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -455,12 +500,12 @@ class CryptoBoxContainer:
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"umount",
|
||||
self.__getMountPoint()])
|
||||
self.__get_mount_point()])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBUmountError(errorMsg)
|
||||
err_msg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBUmountError(err_msg)
|
||||
if os.path.exists(os.path.join(self.__dmDir, self.name)):
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
|
@ -476,29 +521,30 @@ class CryptoBoxContainer:
|
|||
"--batch-mode"])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not remove the luks mapping: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBUmountError(errorMsg)
|
||||
err_msg = "Could not remove the luks mapping: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBUmountError(err_msg)
|
||||
devnull.close()
|
||||
self.cbox.sendEventNotification("postumount", self.__getEventArgs())
|
||||
self.cbox.send_event_notification("postumount", self.__get_event_args())
|
||||
|
||||
|
||||
def __mountPlain(self):
|
||||
def __mount_plain(self):
|
||||
"mount a plaintext partition"
|
||||
if self.isMounted(): raise CBVolumeIsActive("this container is already active")
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("this container is already active")
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.__cleanMountDirs()
|
||||
if not os.path.exists(self.__getMountPoint()):
|
||||
self.__createMountDirectory(self.__getMountPoint())
|
||||
if not os.path.exists(self.__getMountPoint()):
|
||||
errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBMountError(errorMsg)
|
||||
self.cbox.sendEventNotification("premount", self.__getEventArgs())
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.__clean_mount_dirs()
|
||||
if not os.path.exists(self.__get_mount_point()):
|
||||
self.__create_mount_directory(self.__get_mount_point())
|
||||
if not os.path.exists(self.__get_mount_point()):
|
||||
err_msg = "Could not create mountpoint (%s)" % (self.__get_mount_point(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
raise CBMountError(err_msg)
|
||||
self.cbox.send_event_notification("premount", self.__get_event_args())
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -509,27 +555,28 @@ class CryptoBoxContainer:
|
|||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"mount",
|
||||
self.device,
|
||||
self.__getMountPoint()])
|
||||
self.__get_mount_point()])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBMountError(errorMsg)
|
||||
err_msg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBMountError(err_msg)
|
||||
devnull.close()
|
||||
self.cbox.sendEventNotification("postmount", self.__getEventArgs())
|
||||
self.cbox.send_event_notification("postmount", self.__get_event_args())
|
||||
|
||||
|
||||
def __umountPlain(self):
|
||||
def __umount_plain(self):
|
||||
"umount a plaintext partition"
|
||||
if not self.isMounted():
|
||||
self.cbox.log.info("trying to umount while volume (%s) is mounted" % self.getDevice())
|
||||
if not self.is_mounted():
|
||||
self.cbox.log.info("trying to umount while volume (%s) is mounted" % \
|
||||
self.get_device())
|
||||
return
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.sendEventNotification("preumount", self.__getEventArgs())
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.send_event_notification("preumount", self.__get_event_args())
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -539,25 +586,25 @@ class CryptoBoxContainer:
|
|||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"umount",
|
||||
self.__getMountPoint()])
|
||||
self.__get_mount_point()])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.warn(errorMsg)
|
||||
raise CBUmountError(errorMsg)
|
||||
err_msg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.warn(err_msg)
|
||||
raise CBUmountError(err_msg)
|
||||
devnull.close()
|
||||
self.cbox.sendEventNotification("postumount", self.__getEventArgs())
|
||||
self.cbox.send_event_notification("postumount", self.__get_event_args())
|
||||
|
||||
|
||||
def __createPlain(self):
|
||||
def __create_plain(self):
|
||||
"make a plaintext partition"
|
||||
if self.isMounted():
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("deactivate the partition before filesystem initialization")
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -568,26 +615,27 @@ class CryptoBoxContainer:
|
|||
self.device])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBCreateError(errorMsg)
|
||||
err_msg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
raise CBCreateError(err_msg)
|
||||
devnull.close()
|
||||
|
||||
|
||||
def __createLuks(self, password):
|
||||
"make a luks partition"
|
||||
def __create_luks(self, password):
|
||||
"""Create a luks partition.
|
||||
"""
|
||||
if not password:
|
||||
raise CBInvalidPassword("no password supplied for new luks mapping")
|
||||
if self.isMounted():
|
||||
if self.is_mounted():
|
||||
raise CBVolumeIsActive("deactivate the partition before filesystem initialization")
|
||||
devnull = None
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
self.log.warn("Could not open %s" % (os.devnull, ))
|
||||
"remove any potential open luks mapping"
|
||||
self.__umountLuks()
|
||||
"create the luks header"
|
||||
self.cbox.log.warn("Could not open %s" % (os.devnull, ))
|
||||
## remove any potential open luks mapping
|
||||
self.__umount_luks()
|
||||
## create the luks header
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = subprocess.PIPE,
|
||||
|
@ -605,10 +653,10 @@ class CryptoBoxContainer:
|
|||
proc.stdin.write(password)
|
||||
(output, errout) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not create the luks header: %s" % (errout.strip(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBCreateError(errorMsg)
|
||||
"open the luks container for mkfs"
|
||||
err_msg = "Could not create the luks header: %s" % (errout.strip(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
raise CBCreateError(err_msg)
|
||||
## open the luks container for mkfs
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = subprocess.PIPE,
|
||||
|
@ -625,10 +673,10 @@ class CryptoBoxContainer:
|
|||
proc.stdin.write(password)
|
||||
(output, errout) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not open the new luks mapping: %s" % (errout.strip(), )
|
||||
self.log.error(errorMsg)
|
||||
raise CBCreateError(errorMsg)
|
||||
"make the filesystem"
|
||||
err_msg = "Could not open the new luks mapping: %s" % (errout.strip(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
raise CBCreateError(err_msg)
|
||||
## make the filesystem
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdin = None,
|
||||
|
@ -638,50 +686,54 @@ class CryptoBoxContainer:
|
|||
self.cbox.prefs["Programs"]["mkfs-data"],
|
||||
os.path.join(self.__dmDir, self.name)])
|
||||
proc.wait()
|
||||
"remove the mapping - for every exit status"
|
||||
self.__umountLuks()
|
||||
## remove the mapping - for every exit status
|
||||
self.__umount_luks()
|
||||
if proc.returncode != 0:
|
||||
errorMsg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.log.error(errorMsg)
|
||||
"remove the luks mapping"
|
||||
raise CBCreateError(errorMsg)
|
||||
err_msg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), )
|
||||
self.cbox.log.error(err_msg)
|
||||
## remove the luks mapping
|
||||
raise CBCreateError(err_msg)
|
||||
devnull.close()
|
||||
|
||||
|
||||
def __cleanMountDirs(self):
|
||||
def __clean_mount_dirs(self):
|
||||
""" remove all unnecessary subdirs of the mount parent directory
|
||||
this should be called for every (u)mount """
|
||||
subdirs = os.listdir(self.cbox.prefs["Locations"]["MountParentDir"])
|
||||
for d in subdirs:
|
||||
abs_dir = os.path.join(self.cbox.prefs["Locations"]["MountParentDir"], d)
|
||||
for one_dir in subdirs:
|
||||
abs_dir = os.path.join(self.cbox.prefs["Locations"]["MountParentDir"], one_dir)
|
||||
if (not os.path.islink(abs_dir)) \
|
||||
and os.path.isdir(abs_dir) \
|
||||
and (not os.path.ismount(abs_dir)) \
|
||||
and (os.path.isfile(os.path.join(abs_dir,MOUNT_DIR_MARKER))) \
|
||||
and (len(os.listdir(abs_dir)) == 1):
|
||||
try:
|
||||
os.remove(os.path.join(abs_dir,MOUNT_DIR_MARKER))
|
||||
os.remove(os.path.join(abs_dir, MOUNT_DIR_MARKER))
|
||||
os.rmdir(abs_dir)
|
||||
except OSError,errMsg:
|
||||
except OSError, err_msg:
|
||||
## we do not care too much about unclean cleaning ...
|
||||
self.log.info("failed to clean a mountpoint (%s): %s" % (abs_dir,str(errMsg)))
|
||||
self.cbox.log.info("failed to clean a mountpoint (%s): %s" % \
|
||||
(abs_dir, str(err_msg)))
|
||||
|
||||
|
||||
def __createMountDirectory(self,dirname):
|
||||
def __create_mount_directory(self, dirname):
|
||||
"""create and mark a mount directory
|
||||
this marking helps to remove old mountdirs safely"""
|
||||
os.mkdir(dirname)
|
||||
try:
|
||||
f = file(os.path.join(dirname,MOUNT_DIR_MARKER),"w")
|
||||
f.close()
|
||||
except OSError,errMsg:
|
||||
mark_file = file(os.path.join(dirname, MOUNT_DIR_MARKER), "w")
|
||||
mark_file.close()
|
||||
except OSError, err_msg:
|
||||
## we do not care too much about the marking
|
||||
self.log.info("failed to mark a mountpoint (%s): %s" % (dirname,str(errMsg)))
|
||||
self.cbox.log.info("failed to mark a mountpoint (%s): %s" % (dirname, str(err_msg)))
|
||||
|
||||
|
||||
def __getEventArgs(self):
|
||||
"""return an array of arguments for event scripts handling pre/post-mount/umount
|
||||
events"""
|
||||
typeText = [e for e in ContainerTypes.keys() if ContainerTypes[e] == self.getType()][0]
|
||||
return [self.getDevice(), self.getName(), typeText, self.__getMountPoint()]
|
||||
def __get_event_args(self):
|
||||
"""Return an array of arguments for event scripts.
|
||||
|
||||
for now supported: pre/post-mount/umount events
|
||||
"""
|
||||
type_text = [e for e in CONTAINERTYPES.keys()
|
||||
if CONTAINERTYPES[e] == self.get_type()][0]
|
||||
return [self.get_device(), self.get_name(), type_text, self.__get_mount_point()]
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
exceptions of the cryptobox package
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
class CBError(Exception):
|
||||
"""base class for exceptions of the cryptobox"""
|
||||
|
@ -54,13 +56,16 @@ class CBConfigUndefinedError(CBConfigError):
|
|||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
# is it a settings or a section?
|
||||
"""Output the appropriate string: for a setting or a section.
|
||||
"""
|
||||
if self.name:
|
||||
# setting
|
||||
return "undefined configuration setting: [%s]->%s - please check your configuration file" % (self.section, self.name)
|
||||
return "undefined configuration setting: [" + str(self.section) \
|
||||
+ "]->" + str(self.name) + " - please check your configuration file"
|
||||
else:
|
||||
# section
|
||||
return "undefined configuration section: [%s] - please check your configuration file" % (self.section, )
|
||||
return "undefined configuration section: [" + str(self.section) \
|
||||
+ "] - please check your configuration file"
|
||||
|
||||
|
||||
|
||||
|
@ -73,8 +78,12 @@ class CBConfigInvalidValueError(CBConfigError):
|
|||
self.value = value
|
||||
self.reason = reason
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "invalid configuration setting [%s]->%s (%s): %s" % (self.section, self.name, self.value, self.reason)
|
||||
"""Return the error description.
|
||||
"""
|
||||
return "invalid configuration setting [%s]->%s (%s): %s" % \
|
||||
(self.section, self.name, self.value, self.reason)
|
||||
|
||||
|
||||
class CBEnvironmentError(CBError):
|
||||
|
@ -86,42 +95,58 @@ class CBEnvironmentError(CBError):
|
|||
self.desc = desc
|
||||
|
||||
def __str__(self):
|
||||
"""Return the error description.
|
||||
"""
|
||||
return "misconfiguration detected: %s" % self.desc
|
||||
|
||||
|
||||
class CBContainerError(CBError):
|
||||
"""any error raised while manipulating a cryptobox container"""
|
||||
"""Any error raised while manipulating a cryptobox container.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
|
||||
def __str__(self):
|
||||
return self.desc
|
||||
|
||||
class CBCreateError(CBContainerError):
|
||||
"""Raised if a container could not be created (formatted).
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBVolumeIsActive(CBContainerError):
|
||||
"""Raised if a container was active even if it may not for a specific action.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBInvalidName(CBContainerError):
|
||||
"""Raised if someone tried to set an invalid container name.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBNameIsInUse(CBContainerError):
|
||||
"""Raised if the new name of a container is already in use.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBInvalidType(CBContainerError):
|
||||
"""Raised if a container is of an invalid type for a choosen action.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBInvalidPassword(CBContainerError):
|
||||
"""Someone tried to open an ecnrypted container with the wrong password.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBChangePasswordError(CBContainerError):
|
||||
"""Changing of the password of an encrypted container failed.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBMountError(CBContainerError):
|
||||
"""Failed to mount a container.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CBUmountError(CBContainerError):
|
||||
"""Failed to umount a container.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
|
@ -22,23 +22,17 @@
|
|||
This is the web interface for a fileserver managing encrypted filesystems.
|
||||
'''
|
||||
|
||||
# check python version
|
||||
import sys
|
||||
(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)):
|
||||
sys.stderr.write("You need a python version >= 2.4\nCurrent version is:\n %s\n" % sys.version)
|
||||
sys.exit(1)
|
||||
__revision__ = "$Id"
|
||||
|
||||
import sys
|
||||
import cryptobox.core.container as cbxContainer
|
||||
from cryptobox.core.exceptions import *
|
||||
from cryptobox.core.exceptions import CBEnvironmentError, CBConfigUndefinedError
|
||||
import re
|
||||
import os
|
||||
import cryptobox.core.tools as cbxTools
|
||||
import subprocess
|
||||
|
||||
|
||||
VERSION = "0.3~1"
|
||||
|
||||
class CryptoBox:
|
||||
'''this class rules them all!
|
||||
|
||||
|
@ -48,14 +42,15 @@ class CryptoBox:
|
|||
|
||||
def __init__(self, config_file=None):
|
||||
import cryptobox.core.settings as cbxSettings
|
||||
self.log = self.__getStartupLogger()
|
||||
self.log = self.__get_startup_logger()
|
||||
self.prefs = cbxSettings.CryptoBoxSettings(config_file)
|
||||
self.__runTests()
|
||||
self.__run_tests()
|
||||
self.__containers = []
|
||||
self.reread_container_list()
|
||||
|
||||
|
||||
def __getStartupLogger(self):
|
||||
import logging
|
||||
'''initialises the logging system
|
||||
def __get_startup_logger(self):
|
||||
"""Initialize the configured logging facility of the CryptoBox.
|
||||
|
||||
use it with: 'self.log.[debug|info|warning|error|critical](logmessage)'
|
||||
all classes should get the logging instance during __init__:
|
||||
|
@ -63,13 +58,15 @@ class CryptoBox:
|
|||
|
||||
first we output all warnings/errors to stderr
|
||||
as soon as we opened the config file successfully, we redirect debug output
|
||||
to the configured destination'''
|
||||
to the configured destination
|
||||
"""
|
||||
import logging
|
||||
## basicConfig(...) needs python >= 2.4
|
||||
try:
|
||||
log_handler = logging.getLogger("CryptoBox")
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s CryptoBox %(levelname)s: %(message)s',
|
||||
stderr=sys.stderr)
|
||||
format = '%(asctime)s CryptoBox %(levelname)s: %(message)s',
|
||||
stderr = sys.stderr)
|
||||
log_handler.setLevel(logging.ERROR)
|
||||
log_handler.info("loggingsystem is up'n running")
|
||||
## from now on everything can be logged via self.log...
|
||||
|
@ -78,19 +75,15 @@ class CryptoBox:
|
|||
return log_handler
|
||||
|
||||
|
||||
# do some initial checks
|
||||
def __runTests(self):
|
||||
#self.__runTestUID()
|
||||
self.__runTestRootPriv()
|
||||
def __run_tests(self):
|
||||
"""Do some initial tests.
|
||||
"""
|
||||
self.__run_test_root_priv()
|
||||
|
||||
|
||||
def __runTestUID(self):
|
||||
if os.geteuid() == 0:
|
||||
raise CBEnvironmentError("you may not run the cryptobox as root")
|
||||
|
||||
|
||||
def __runTestRootPriv(self):
|
||||
"""try to run 'super' with 'CryptoBoxRootActions'"""
|
||||
def __run_test_root_priv(self):
|
||||
"""Try to run 'super' with 'CryptoBoxRootActions'.
|
||||
"""
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
|
@ -110,46 +103,39 @@ class CryptoBox:
|
|||
stderr = devnull,
|
||||
args = [prog_super, prog_rootactions, "check"])
|
||||
except OSError:
|
||||
raise CBEnvironmentError("failed to execute 'super' (%s)" % self.prefs["Programs"]["super"])
|
||||
raise CBEnvironmentError(
|
||||
"failed to execute 'super' (%s)" % self.prefs["Programs"]["super"])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
raise CBEnvironmentError("failed to call CryptoBoxRootActions (%s) via 'super' - maybe you did not add the appropriate line to /etc/super.tab?" % prog_rootactions)
|
||||
raise CBEnvironmentError("failed to call CryptoBoxRootActions ("
|
||||
+ prog_rootactions + ") via 'super' - maybe you did not add the "
|
||||
+ "appropriate line to '/etc/super.tab'?")
|
||||
|
||||
|
||||
# this method just demonstrates inheritance effects - may be removed
|
||||
def cbx_inheritance_test(self, string="you lucky widow"):
|
||||
self.log.info(string)
|
||||
|
||||
def reread_container_list(self):
|
||||
"""Reinitialize the list of available containers.
|
||||
|
||||
# RFC: why should CryptoBoxProps inherit CryptoBox? [l]
|
||||
# RFC: shouldn't we move all useful functions of CryptoBoxProps to CryptoBox? [l]
|
||||
class CryptoBoxProps(CryptoBox):
|
||||
'''Get and set the properties of a CryptoBox
|
||||
|
||||
This class contains all available devices that may be accessed.
|
||||
All properties of the cryptobox can be accessed by this class.
|
||||
'''
|
||||
|
||||
def __init__(self, config_file=None):
|
||||
'''read config and fill class variables'''
|
||||
CryptoBox.__init__(self, config_file)
|
||||
self.reReadContainerList()
|
||||
|
||||
|
||||
def reReadContainerList(self):
|
||||
This should be called whenever the available containers may have changed.
|
||||
E.g.: after partitioning and after device addition/removal
|
||||
"""
|
||||
self.log.debug("rereading container list")
|
||||
self.containers = []
|
||||
for device in cbxTools.getAvailablePartitions():
|
||||
if self.isDeviceAllowed(device) and not self.isConfigPartition(device):
|
||||
self.containers.append(cbxContainer.CryptoBoxContainer(device, self))
|
||||
self.__containers = []
|
||||
for device in cbxTools.get_available_partitions():
|
||||
if self.is_device_allowed(device) and not self.is_config_partition(device):
|
||||
self.__containers.append(cbxContainer.CryptoBoxContainer(device, self))
|
||||
## sort by container name
|
||||
self.containers.sort(cmp = lambda x,y: x.getName() < y.getName() and -1 or 1)
|
||||
self.__containers.sort(cmp = lambda x, y: x.get_name() < y.get_name() and -1 or 1)
|
||||
|
||||
|
||||
def isConfigPartition(self, device):
|
||||
def is_config_partition(self, device):
|
||||
"""Check if a given partition contains configuration informations.
|
||||
|
||||
The check is done by comparing the label of the filesystem with a string.
|
||||
"""
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.prefs["Programs"]["blkid"],
|
||||
"-c", os.path.devnull,
|
||||
|
@ -160,70 +146,77 @@ class CryptoBoxProps(CryptoBox):
|
|||
return output.strip() == self.prefs["Main"]["ConfigVolumeLabel"]
|
||||
|
||||
|
||||
def isDeviceAllowed(self, devicename):
|
||||
def is_device_allowed(self, devicename):
|
||||
"check if a device is white-listed for being used as cryptobox containers"
|
||||
import types
|
||||
allowed = self.prefs["Main"]["AllowedDevices"]
|
||||
if type(allowed) == types.StringType: allowed = [allowed]
|
||||
if type(allowed) == types.StringType:
|
||||
allowed = [allowed]
|
||||
for a_dev in allowed:
|
||||
"remove double dots and so on ..."
|
||||
## remove double dots and so on ...
|
||||
real_device = os.path.realpath(devicename)
|
||||
if a_dev and re.search('^' + a_dev, real_device): return True
|
||||
if a_dev and re.search('^' + a_dev, real_device):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getLogData(self, lines=None, maxSize=None):
|
||||
def get_log_data(self, lines=None, max_size=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'
|
||||
the maximum number and size of these entries can be limited by
|
||||
'lines' and 'max_size'
|
||||
"""
|
||||
# return nothing if the currently selected log output is not a file
|
||||
try:
|
||||
if self.prefs["Log"]["Destination"].upper() != "FILE": return []
|
||||
if self.prefs["Log"]["Destination"].upper() != "FILE":
|
||||
return []
|
||||
log_file = self.prefs["Log"]["Details"]
|
||||
except KeyError:
|
||||
self.log.error("could not evaluate one of the following config settings: [Log]->Destination or [Log]->Details")
|
||||
self.log.error("could not evaluate one of the following config settings: "
|
||||
+ "[Log]->Destination or [Log]->Details")
|
||||
return []
|
||||
try:
|
||||
fd = open(log_file, "r")
|
||||
if maxSize: fd.seek(-maxSize, 2) # seek relative to the end of the file
|
||||
content = fd.readlines()
|
||||
fd.close()
|
||||
fdesc = open(log_file, "r")
|
||||
if max_size:
|
||||
fdesc.seek(-max_size, 2) # seek relative to the end of the file
|
||||
content = fdesc.readlines()
|
||||
fdesc.close()
|
||||
except IOError:
|
||||
self.log.warn("failed to read the log file (%s)" % log_file)
|
||||
return []
|
||||
if lines: content = content[-lines:]
|
||||
if lines:
|
||||
content = content[-lines:]
|
||||
content.reverse()
|
||||
return content
|
||||
|
||||
|
||||
def getContainerList(self, filterType=None, filterName=None):
|
||||
def get_container_list(self, filter_type=None, filter_name=None):
|
||||
"retrieve the list of all containers of this cryptobox"
|
||||
try:
|
||||
result = self.containers[:]
|
||||
if filterType != None:
|
||||
if filterType in range(len(cbxContainer.ContainerTypes)):
|
||||
return [e for e in self.containers if e.getType() == filterType]
|
||||
result = self.__containers[:]
|
||||
if filter_type != None:
|
||||
if filter_type in range(len(cbxContainer.CONTAINERTYPES)):
|
||||
return [e for e in self.__containers if e.get_type() == filter_type]
|
||||
else:
|
||||
self.log.info("invalid filterType (%d)" % filterType)
|
||||
self.log.info("invalid filter_type (%d)" % filter_type)
|
||||
result.clear()
|
||||
if filterName != None:
|
||||
result = [e for e in self.containers if e.getName() == filterName]
|
||||
if filter_name != None:
|
||||
result = [e for e in self.__containers if e.get_name() == filter_name]
|
||||
return result
|
||||
except AttributeError:
|
||||
return []
|
||||
|
||||
|
||||
def getContainer(self, device):
|
||||
def get_container(self, device):
|
||||
"retrieve the container element for this device"
|
||||
all = [e for e in self.getContainerList() if e.device == device]
|
||||
all = [e for e in self.get_container_list() if e.device == device]
|
||||
if all:
|
||||
return all[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def sendEventNotification(self, event, event_infos):
|
||||
def send_event_notification(self, event, event_infos):
|
||||
"""call all available scripts in the event directory with some event information"""
|
||||
event_dir = self.prefs["Locations"]["EventDir"]
|
||||
for fname in os.listdir(event_dir):
|
||||
|
@ -240,11 +233,14 @@ class CryptoBoxProps(CryptoBox):
|
|||
args = cmd_args)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
self.log.warn("an event script (%s) failed (exitcode=%d) to handle an event (%s): %s" % (real_fname, proc.returncode, event, stderr.strip()))
|
||||
self.log.warn(
|
||||
"an event script (%s) failed (exitcode=%d) to handle an event (%s): %s" %
|
||||
(real_fname, proc.returncode, event, stderr.strip()))
|
||||
else:
|
||||
self.log.info("event handler (%s) finished successfully: %s" % (real_fname, event))
|
||||
self.log.info("event handler (%s) finished successfully: %s" %
|
||||
(real_fname, event))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cb = CryptoBoxProps()
|
||||
CryptoBox()
|
||||
|
||||
|
|
|
@ -18,22 +18,21 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Manage the configuration of a CryptoBox
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
from cryptobox.core.exceptions import *
|
||||
import logging
|
||||
try:
|
||||
import validate
|
||||
except:
|
||||
raise CBEnvironmentError("couldn't import 'validate'! Try 'apt-get install python-formencode'.")
|
||||
import os
|
||||
import subprocess
|
||||
try:
|
||||
import configobj ## needed for reading and writing of the config file
|
||||
except:
|
||||
raise CBEnvironmentError("couldn't import 'configobj'! Try 'apt-get install python-configobj'.")
|
||||
|
||||
import os
|
||||
import configobj, validate
|
||||
|
||||
|
||||
class CryptoBoxSettings:
|
||||
"""Manage the various configuration files of the CryptoBox
|
||||
"""
|
||||
|
||||
CONF_LOCATIONS = [
|
||||
"./cryptobox.conf",
|
||||
|
@ -47,76 +46,85 @@ class CryptoBoxSettings:
|
|||
|
||||
def __init__(self, config_file=None):
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
config_file = self.__getConfigFileName(config_file)
|
||||
config_file = self.__get_config_filename(config_file)
|
||||
self.log.info("loading config file: %s" % config_file)
|
||||
self.prefs = self.__getPreferences(config_file)
|
||||
self.__validateConfig()
|
||||
self.__configureLogHandler()
|
||||
self.__checkUnknownPreferences()
|
||||
self.preparePartition()
|
||||
self.volumesDB = self.__getVolumesDatabase()
|
||||
self.pluginConf = self.__getPluginConfig()
|
||||
self.userDB = self.__getUserDB()
|
||||
self.misc_files = self.__getMiscFiles()
|
||||
self.prefs = self.__get_preferences(config_file)
|
||||
self.__validate_config()
|
||||
self.__configure_log_handler()
|
||||
self.__check_unknown_preferences()
|
||||
self.prepare_partition()
|
||||
self.volumes_db = self.__get_volumes_database()
|
||||
self.plugin_conf = self.__get_plugin_config()
|
||||
self.user_db = self.__get_user_db()
|
||||
self.misc_files = self.__get_misc_files()
|
||||
|
||||
|
||||
def write(self):
|
||||
"""
|
||||
write all local setting files including the content of the "misc" subdirectory
|
||||
"""
|
||||
ok = True
|
||||
status = True
|
||||
try:
|
||||
self.volumesDB.write()
|
||||
self.volumes_db.write()
|
||||
except IOError:
|
||||
self.log.warn("could not save the volume database")
|
||||
ok = False
|
||||
status = False
|
||||
try:
|
||||
self.pluginConf.write()
|
||||
self.plugin_conf.write()
|
||||
except IOError:
|
||||
self.log.warn("could not save the plugin configuration")
|
||||
ok = False
|
||||
status = False
|
||||
try:
|
||||
self.userDB.write()
|
||||
self.user_db.write()
|
||||
except IOError:
|
||||
self.log.warn("could not save the user database")
|
||||
ok = False
|
||||
status = False
|
||||
for misc_file in self.misc_files:
|
||||
if not misc_file.save():
|
||||
self.log.warn("could not save a misc setting file (%s)" % misc_file.filename)
|
||||
ok = False
|
||||
return ok
|
||||
status = False
|
||||
return status
|
||||
|
||||
|
||||
def requiresPartition(self):
|
||||
def requires_partition(self):
|
||||
return bool(self.prefs["Main"]["UseConfigPartition"])
|
||||
|
||||
|
||||
def getActivePartition(self):
|
||||
def get_active_partition(self):
|
||||
"""Return the currently active cnfiguration partition.
|
||||
"""
|
||||
settings_dir = self.prefs["Locations"]["SettingsDir"]
|
||||
if not os.path.ismount(settings_dir): return None
|
||||
if not os.path.ismount(settings_dir):
|
||||
return None
|
||||
for line in file("/proc/mounts"):
|
||||
fields = line.split(" ")
|
||||
mount_dir = fields[1]
|
||||
try:
|
||||
if os.path.samefile(mount_dir, settings_dir): return fields[0]
|
||||
if os.path.samefile(mount_dir, settings_dir):
|
||||
return fields[0]
|
||||
except OSError:
|
||||
pass
|
||||
## no matching entry found
|
||||
return None
|
||||
|
||||
|
||||
def mountPartition(self):
|
||||
def mount_partition(self):
|
||||
"""Mount a config partition.
|
||||
"""
|
||||
self.log.debug("trying to mount configuration partition")
|
||||
if not self.requiresPartition():
|
||||
self.log.warn("mountConfigPartition: configuration partition is not required - mounting anyway")
|
||||
if self.getActivePartition():
|
||||
self.log.warn("mountConfigPartition: configuration partition already mounted - not mounting again")
|
||||
if not self.requires_partition():
|
||||
self.log.warn("mountConfigPartition: configuration partition is "
|
||||
+ "not required - mounting anyway")
|
||||
if self.get_active_partition():
|
||||
self.log.warn("mountConfigPartition: configuration partition already "
|
||||
+ "mounted - not mounting again")
|
||||
return False
|
||||
confPartitions = self.getAvailablePartitions()
|
||||
if not confPartitions:
|
||||
self.log.error("no configuration partitions found - you have to create it first")
|
||||
conf_partitions = self.get_available_partitions()
|
||||
if not conf_partitions:
|
||||
self.log.error("no configuration partition found - you have to create "
|
||||
+ "it first")
|
||||
return False
|
||||
partition = confPartitions[0]
|
||||
partition = conf_partitions[0]
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
|
@ -136,8 +144,10 @@ class CryptoBoxSettings:
|
|||
return True
|
||||
|
||||
|
||||
def umountPartition(self):
|
||||
if not self.getActivePartition():
|
||||
def umount_partition(self):
|
||||
"""Umount the currently active configuration partition.
|
||||
"""
|
||||
if not self.get_active_partition():
|
||||
self.log.warn("umountConfigPartition: no configuration partition mounted")
|
||||
return False
|
||||
proc = subprocess.Popen(
|
||||
|
@ -158,7 +168,7 @@ class CryptoBoxSettings:
|
|||
return True
|
||||
|
||||
|
||||
def getAvailablePartitions(self):
|
||||
def get_available_partitions(self):
|
||||
"""returns a sequence of found config partitions"""
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
|
@ -169,14 +179,16 @@ class CryptoBoxSettings:
|
|||
"-t", "LABEL=%s" % self.prefs["Main"]["ConfigVolumeLabel"] ])
|
||||
(output, error) = proc.communicate()
|
||||
if output:
|
||||
return [e.strip().split(":",1)[0] for e in output.splitlines()]
|
||||
return [e.strip().split(":", 1)[0] for e in output.splitlines()]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def preparePartition(self):
|
||||
if self.requiresPartition() and not self.getActivePartition():
|
||||
self.mountPartition()
|
||||
def prepare_partition(self):
|
||||
"""Mount a config partition if necessary.
|
||||
"""
|
||||
if self.requires_partition() and not self.get_active_partition():
|
||||
self.mount_partition()
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
|
@ -184,7 +196,9 @@ class CryptoBoxSettings:
|
|||
return self.prefs[key]
|
||||
|
||||
|
||||
def __getPreferences(self, config_file):
|
||||
def __get_preferences(self, config_file):
|
||||
"""Load the CryptoBox configuration.
|
||||
"""
|
||||
import StringIO
|
||||
config_rules = StringIO.StringIO(self.validation_spec)
|
||||
try:
|
||||
|
@ -192,86 +206,111 @@ class CryptoBoxSettings:
|
|||
if prefs:
|
||||
self.log.info("found config: %s" % prefs.items())
|
||||
else:
|
||||
raise CBConfigUnavailableError("failed to load the config file: %s" % config_file)
|
||||
raise CBConfigUnavailableError(
|
||||
"failed to load the config file: %s" % config_file)
|
||||
except IOError:
|
||||
raise CBConfigUnavailableError("unable to open the config file: %s" % config_file)
|
||||
raise CBConfigUnavailableError(
|
||||
"unable to open the config file: %s" % config_file)
|
||||
return prefs
|
||||
|
||||
|
||||
def __validateConfig(self):
|
||||
def __validate_config(self):
|
||||
"""Check the configuration settings and cast value types.
|
||||
"""
|
||||
result = self.prefs.validate(CryptoBoxSettingsValidator(), preserve_errors=True)
|
||||
error_list = configobj.flatten_errors(self.prefs, result)
|
||||
if not error_list: return
|
||||
errorMsgs = []
|
||||
if not error_list:
|
||||
return
|
||||
error_msgs = []
|
||||
for sections, key, text in error_list:
|
||||
section_name = "->".join(sections)
|
||||
if not text:
|
||||
errorMsg = "undefined configuration value (%s) in section '%s'" % (key, section_name)
|
||||
error_msg = "undefined configuration value (%s) in section '%s'" % \
|
||||
(key, section_name)
|
||||
else:
|
||||
errorMsg = "invalid configuration value (%s) in section '%s': %s" % (key, section_name, text)
|
||||
errorMsgs.append(errorMsg)
|
||||
raise CBConfigError, "\n".join(errorMsgs)
|
||||
error_msg = "invalid configuration value (%s) in section '%s': %s" % \
|
||||
(key, section_name, text)
|
||||
error_msgs.append(error_msg)
|
||||
raise CBConfigError, "\n".join(error_msgs)
|
||||
|
||||
|
||||
def __checkUnknownPreferences(self):
|
||||
def __check_unknown_preferences(self):
|
||||
"""Check the configuration file for unknown settings to avoid spelling mistakes.
|
||||
"""
|
||||
import StringIO
|
||||
config_rules = configobj.ConfigObj(StringIO.StringIO(self.validation_spec), list_values=False)
|
||||
self.__recursiveConfigSectionCheck("", self.prefs, config_rules)
|
||||
config_rules = configobj.ConfigObj(StringIO.StringIO(self.validation_spec),
|
||||
list_values=False)
|
||||
self.__recursive_section_check("", self.prefs, config_rules)
|
||||
|
||||
|
||||
def __recursiveConfigSectionCheck(self, section_path, section_config, section_rules):
|
||||
"""should be called by '__checkUnknownPreferences' for every section
|
||||
def __recursive_section_check(self, section_path, section_config, section_rules):
|
||||
"""should be called by '__check_unknown_preferences' for every section
|
||||
sends a warning message to the logger for every undefined (see validation_spec)
|
||||
configuration setting
|
||||
"""
|
||||
for e in section_config.keys():
|
||||
element_path = section_path + e
|
||||
if e in section_rules.keys():
|
||||
if isinstance(section_config[e], configobj.Section):
|
||||
if isinstance(section_rules[e], configobj.Section):
|
||||
self.__recursiveConfigSectionCheck(element_path + "->", section_config[e], section_rules[e])
|
||||
for section in section_config.keys():
|
||||
element_path = section_path + section
|
||||
if section in section_rules.keys():
|
||||
if isinstance(section_config[section], configobj.Section):
|
||||
if isinstance(section_rules[section], configobj.Section):
|
||||
self.__recursive_section_check(element_path + "->",
|
||||
section_config[section], section_rules[section])
|
||||
else:
|
||||
self.log.warn("configuration setting should be a value instead of a section name: %s" % element_path)
|
||||
self.log.warn("configuration setting should be a value "
|
||||
+ "instead of a section name: %s" % element_path)
|
||||
else:
|
||||
if not isinstance(section_rules[e], configobj.Section):
|
||||
if not isinstance(section_rules[section], configobj.Section):
|
||||
pass # good - the setting is valid
|
||||
else:
|
||||
self.log.warn("configuration setting should be a section name instead of a value: %s" % element_path)
|
||||
self.log.warn("configuration setting should be a section "
|
||||
+ "name instead of a value: %s" % element_path)
|
||||
else:
|
||||
self.log.warn("unknown configuration setting: %s" % element_path)
|
||||
|
||||
|
||||
def __getPluginConfig(self):
|
||||
def __get_plugin_config(self):
|
||||
"""Load the plugin configuration file if it exists.
|
||||
"""
|
||||
import StringIO
|
||||
plugin_rules = StringIO.StringIO(self.pluginValidationSpec)
|
||||
try:
|
||||
try:
|
||||
pluginConf_file = os.path.join(self.prefs["Locations"]["SettingsDir"], self.PLUGINCONF_FILE)
|
||||
plugin_conf_file = os.path.join(
|
||||
self.prefs["Locations"]["SettingsDir"], self.PLUGINCONF_FILE)
|
||||
except KeyError:
|
||||
raise CBConfigUndefinedError("Locations", "SettingsDir")
|
||||
except SyntaxError:
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", pluginConf_file, "failed to interprete the filename of the plugin config file correctly (%s)" % pluginConf_file)
|
||||
## create pluginConf_file if necessary
|
||||
if os.path.exists(pluginConf_file):
|
||||
pluginConf = configobj.ConfigObj(pluginConf_file, configspec=plugin_rules)
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", plugin_conf_file,
|
||||
"failed to interprete the filename of the plugin config file "
|
||||
+ "correctly (%s)" % plugin_conf_file)
|
||||
## create plugin_conf_file if necessary
|
||||
if os.path.exists(plugin_conf_file):
|
||||
plugin_conf = configobj.ConfigObj(plugin_conf_file, configspec=plugin_rules)
|
||||
else:
|
||||
pluginConf = configobj.ConfigObj(pluginConf_file, configspec=plugin_rules, create_empty=True)
|
||||
plugin_conf = configobj.ConfigObj(plugin_conf_file, configspec=plugin_rules,
|
||||
create_empty=True)
|
||||
## validate and convert values according to the spec
|
||||
pluginConf.validate(validate.Validator())
|
||||
## check if pluginConf_file file was created successfully?
|
||||
if not os.path.exists(pluginConf_file):
|
||||
raise CBEnvironmentError("failed to create plugin configuration file (%s)" % pluginConf_file)
|
||||
return pluginConf
|
||||
plugin_conf.validate(validate.Validator())
|
||||
## check if plugin_conf_file file was created successfully?
|
||||
if not os.path.exists(plugin_conf_file):
|
||||
raise CBEnvironmentError(
|
||||
"failed to create plugin configuration file (%s)" % plugin_conf_file)
|
||||
return plugin_conf
|
||||
|
||||
|
||||
def __getVolumesDatabase(self):
|
||||
def __get_volumes_database(self):
|
||||
"""Load the volume database file if it exists.
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
conf_file = os.path.join(self.prefs["Locations"]["SettingsDir"], self.VOLUMESDB_FILE)
|
||||
conf_file = os.path.join(
|
||||
self.prefs["Locations"]["SettingsDir"], self.VOLUMESDB_FILE)
|
||||
except KeyError:
|
||||
raise CBConfigUndefinedError("Locations", "SettingsDir")
|
||||
except SyntaxError:
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", conf_file, "failed to interprete the filename of the volume database correctly (%s)" % conf_file)
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", conf_file,
|
||||
"failed to interprete the filename of the volume database "
|
||||
+ "correctly (%s)" % conf_file)
|
||||
## create conf_file if necessary
|
||||
if os.path.exists(conf_file):
|
||||
conf = configobj.ConfigObj(conf_file)
|
||||
|
@ -279,36 +318,48 @@ class CryptoBoxSettings:
|
|||
conf = configobj.ConfigObj(conf_file, create_empty=True)
|
||||
## check if conf_file file was created successfully?
|
||||
if not os.path.exists(conf_file):
|
||||
raise CBEnvironmentError("failed to create volume database file (%s)" % conf_file)
|
||||
raise CBEnvironmentError(
|
||||
"failed to create volume database file (%s)" % conf_file)
|
||||
return conf
|
||||
|
||||
|
||||
def __getUserDB(self):
|
||||
def __get_user_db(self):
|
||||
"""Load the user database file if it exists.
|
||||
"""
|
||||
import StringIO, sha
|
||||
userDB_rules = StringIO.StringIO(self.userDatabaseSpec)
|
||||
user_db_rules = StringIO.StringIO(self.userDatabaseSpec)
|
||||
try:
|
||||
try:
|
||||
userDB_file = os.path.join(self.prefs["Locations"]["SettingsDir"], self.USERDB_FILE)
|
||||
user_db_file = os.path.join(
|
||||
self.prefs["Locations"]["SettingsDir"], self.USERDB_FILE)
|
||||
except KeyError:
|
||||
raise CBConfigUndefinedError("Locations", "SettingsDir")
|
||||
except SyntaxError:
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", userDB_file, "failed to interprete the filename of the users database file correctly (%s)" % userDB_file)
|
||||
## create userDB_file if necessary
|
||||
if os.path.exists(userDB_file):
|
||||
userDB = configobj.ConfigObj(userDB_file, configspec=userDB_rules)
|
||||
raise CBConfigInvalidValueError("Locations", "SettingsDir", user_db_file,
|
||||
"failed to interprete the filename of the users database file "
|
||||
+ "correctly (%s)" % user_db_file)
|
||||
## create user_db_file if necessary
|
||||
if os.path.exists(user_db_file):
|
||||
user_db = configobj.ConfigObj(user_db_file, configspec=user_db_rules)
|
||||
else:
|
||||
userDB = configobj.ConfigObj(userDB_file, configspec=userDB_rules, create_empty=True)
|
||||
user_db = configobj.ConfigObj(user_db_file, configspec=user_db_rules,
|
||||
create_empty=True)
|
||||
## validate and set default value for "admin" user
|
||||
userDB.validate(validate.Validator())
|
||||
## check if userDB file was created successfully?
|
||||
if not os.path.exists(userDB_file):
|
||||
raise CBEnvironmentError("failed to create user database file (%s)" % userDB_file)
|
||||
user_db.validate(validate.Validator())
|
||||
## check if user_db file was created successfully?
|
||||
if not os.path.exists(user_db_file):
|
||||
raise CBEnvironmentError(
|
||||
"failed to create user database file (%s)" % user_db_file)
|
||||
## define password hash function - never use "sha" directly - SPOT
|
||||
userDB.getDigest = lambda password: sha.new(password).hexdigest()
|
||||
return userDB
|
||||
user_db.get_digest = lambda password: sha.new(password).hexdigest()
|
||||
return user_db
|
||||
|
||||
|
||||
def __getMiscFiles(self):
|
||||
def __get_misc_files(self):
|
||||
"""Load miscelleanous configuration files.
|
||||
|
||||
e.g.: an ssl certificate, ...
|
||||
"""
|
||||
misc_dir = os.path.join(self.prefs["Locations"]["SettingsDir"], "misc")
|
||||
if (not os.path.isdir(misc_dir)) or (not os.access(misc_dir, os.X_OK)):
|
||||
return []
|
||||
|
@ -317,8 +368,9 @@ class CryptoBoxSettings:
|
|||
if os.path.isfile(os.path.join(misc_dir, f))]
|
||||
|
||||
|
||||
def __getConfigFileName(self, config_file):
|
||||
# search for the configuration file
|
||||
def __get_config_filename(self, config_file):
|
||||
"""Search for the configuration file.
|
||||
"""
|
||||
import types
|
||||
if config_file is None:
|
||||
# no config file was specified - we will look for it in the ususal locations
|
||||
|
@ -332,13 +384,17 @@ class CryptoBoxSettings:
|
|||
else:
|
||||
# a config file was specified (e.g. via command line)
|
||||
if type(config_file) != types.StringType:
|
||||
raise CBConfigUnavailableError("invalid config file specified: %s" % config_file)
|
||||
raise CBConfigUnavailableError(
|
||||
"invalid config file specified: %s" % config_file)
|
||||
if not os.path.exists(config_file):
|
||||
raise CBConfigUnavailableError("could not find the specified configuration file (%s)" % config_file)
|
||||
raise CBConfigUnavailableError(
|
||||
"could not find the specified configuration file (%s)" % config_file)
|
||||
return config_file
|
||||
|
||||
|
||||
def __configureLogHandler(self):
|
||||
def __configure_log_handler(self):
|
||||
"""Configure the log handler of the CryptoBox according to the config.
|
||||
"""
|
||||
try:
|
||||
log_level = self.prefs["Log"]["Level"].upper()
|
||||
log_level_avail = ["DEBUG", "INFO", "WARN", "ERROR"]
|
||||
|
@ -347,15 +403,18 @@ class CryptoBoxSettings:
|
|||
except KeyError:
|
||||
raise CBConfigUndefinedError("Log", "Level")
|
||||
except TypeError:
|
||||
raise CBConfigInvalidValueError("Log", "Level", log_level, "invalid log level: only %s are allowed" % log_level_avail)
|
||||
raise CBConfigInvalidValueError("Log", "Level", log_level,
|
||||
"invalid log level: only %s are allowed" % log_level_avail)
|
||||
try:
|
||||
try:
|
||||
log_handler = logging.FileHandler(self.prefs["Log"]["Details"])
|
||||
except KeyError:
|
||||
raise CBConfigUndefinedError("Log", "Details")
|
||||
except IOError:
|
||||
raise CBEnvironmentError("could not create the log file (%s)" % self.prefs["Log"]["Details"])
|
||||
log_handler.setFormatter(logging.Formatter('%(asctime)s CryptoBox %(levelname)s: %(message)s'))
|
||||
raise CBEnvironmentError("could not create the log file (%s)" % \
|
||||
self.prefs["Log"]["Details"])
|
||||
log_handler.setFormatter(
|
||||
logging.Formatter('%(asctime)s CryptoBox %(levelname)s: %(message)s'))
|
||||
cbox_log = logging.getLogger("CryptoBox")
|
||||
## remove previous handlers
|
||||
cbox_log.handlers = []
|
||||
|
@ -364,7 +423,7 @@ class CryptoBoxSettings:
|
|||
## do not call parent's handlers
|
||||
cbox_log.propagate = False
|
||||
## 'log_level' is a string -> use 'getattr'
|
||||
cbox_log.setLevel(getattr(logging,log_level))
|
||||
cbox_log.setLevel(getattr(logging, log_level))
|
||||
## the logger named "CryptoBox" is configured now
|
||||
|
||||
|
||||
|
@ -420,16 +479,20 @@ admin = string(default=d033e22ae348aeb5660fc2140aec35850c4da997)
|
|||
|
||||
|
||||
class CryptoBoxSettingsValidator(validate.Validator):
|
||||
"""Some custom configuration check functions.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
validate.Validator.__init__(self)
|
||||
self.functions["directoryExists"] = self.check_directoryExists
|
||||
self.functions["fileExecutable"] = self.check_fileExecutable
|
||||
self.functions["fileWriteable"] = self.check_fileWriteable
|
||||
self.functions["listOfExistingDirectories"] = self.check_listOfExistingDirectories
|
||||
self.functions["directoryExists"] = self.check_directory_exists
|
||||
self.functions["fileExecutable"] = self.check_file_executable
|
||||
self.functions["fileWriteable"] = self.check_file_writeable
|
||||
self.functions["listOfExistingDirectories"] = self.check_existing_directories
|
||||
|
||||
|
||||
def check_directoryExists(self, value):
|
||||
def check_directory_exists(self, value):
|
||||
"""Is the directory accessible?
|
||||
"""
|
||||
dir_path = os.path.abspath(value)
|
||||
if not os.path.isdir(dir_path):
|
||||
raise validate.VdtValueError("%s (not found)" % value)
|
||||
|
@ -438,7 +501,9 @@ class CryptoBoxSettingsValidator(validate.Validator):
|
|||
return dir_path
|
||||
|
||||
|
||||
def check_fileExecutable(self, value):
|
||||
def check_file_executable(self, value):
|
||||
"""Is the file executable?
|
||||
"""
|
||||
file_path = os.path.abspath(value)
|
||||
if not os.path.isfile(file_path):
|
||||
raise validate.VdtValueError("%s (not found)" % value)
|
||||
|
@ -447,7 +512,9 @@ class CryptoBoxSettingsValidator(validate.Validator):
|
|||
return file_path
|
||||
|
||||
|
||||
def check_fileWriteable(self, value):
|
||||
def check_file_writeable(self, value):
|
||||
"""Is the file writeable?
|
||||
"""
|
||||
file_path = os.path.abspath(value)
|
||||
if os.path.isfile(file_path):
|
||||
if not os.access(file_path, os.W_OK):
|
||||
|
@ -460,18 +527,22 @@ class CryptoBoxSettingsValidator(validate.Validator):
|
|||
return file_path
|
||||
|
||||
|
||||
def check_listOfExistingDirectories(self, value):
|
||||
def check_existing_directories(self, value):
|
||||
"""Are these directories accessible?
|
||||
"""
|
||||
if not value:
|
||||
raise validate.VdtValueError("no plugin directory specified")
|
||||
if not isinstance(value,list):
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
result = []
|
||||
for d in value:
|
||||
dir_path = os.path.abspath(d)
|
||||
for one_dir in value:
|
||||
dir_path = os.path.abspath(one_dir)
|
||||
if not os.path.isdir(dir_path):
|
||||
raise validate.VdtValueError("%s (plugin directory not found)" % d)
|
||||
raise validate.VdtValueError(
|
||||
"%s (plugin directory not found)" % one_dir)
|
||||
if not os.access(dir_path, os.X_OK):
|
||||
raise validate.VdtValueError("%s (access denied for plugin directory)" % d)
|
||||
raise validate.VdtValueError(
|
||||
"%s (access denied for plugin directory)" % one_dir)
|
||||
result.append(dir_path)
|
||||
return result
|
||||
|
||||
|
@ -484,19 +555,25 @@ class MiscConfigFile:
|
|||
def __init__(self, filename, logger):
|
||||
self.filename = filename
|
||||
self.log = logger
|
||||
self.content = None
|
||||
self.load()
|
||||
|
||||
|
||||
def load(self):
|
||||
fd = open(self.filename, "rb")
|
||||
"""Load a configuration file into memory.
|
||||
"""
|
||||
fdesc = open(self.filename, "rb")
|
||||
## limit the maximum size
|
||||
self.content = fd.read(self.maxSize)
|
||||
if fd.tell() == self.maxSize:
|
||||
self.log.warn("file in misc settings directory (%s) is bigger than allowed (%s)" % (self.filename, self.maxSize))
|
||||
fd.close()
|
||||
self.content = fdesc.read(self.maxSize)
|
||||
if fdesc.tell() == self.maxSize:
|
||||
self.log.warn("file in misc settings directory (" + str(self.filename) \
|
||||
+ ") is bigger than allowed (" + str(self.maxSize) + ")")
|
||||
fdesc.close()
|
||||
|
||||
|
||||
def save(self):
|
||||
"""Save a configuration file to disk.
|
||||
"""
|
||||
save_dir = os.path.dirname(self.filename)
|
||||
## create the directory, if necessary
|
||||
if not os.path.isdir(save_dir):
|
||||
|
@ -506,14 +583,14 @@ class MiscConfigFile:
|
|||
return False
|
||||
## save the content of the file
|
||||
try:
|
||||
fd = open(self.filename, "wb")
|
||||
fdesc = open(self.filename, "wb")
|
||||
except IOError:
|
||||
return False
|
||||
try:
|
||||
fd.write(self.content)
|
||||
fd.close()
|
||||
fdesc.write(self.content)
|
||||
fdesc.close()
|
||||
return True
|
||||
except IOError:
|
||||
fd.close()
|
||||
fdesc.close()
|
||||
return False
|
||||
|
||||
|
|
|
@ -18,137 +18,169 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Some useful functions for the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
logger = logging.getLogger("CryptoBox")
|
||||
LOGGER = logging.getLogger("CryptoBox")
|
||||
|
||||
|
||||
def getAvailablePartitions():
|
||||
def get_available_partitions():
|
||||
"retrieve a list of all available containers"
|
||||
ret_list = []
|
||||
try:
|
||||
"the following reads all lines of /proc/partitions and adds the mentioned devices"
|
||||
## the following reads all lines of /proc/partitions and adds the mentioned devices
|
||||
fpart = open("/proc/partitions", "r")
|
||||
try:
|
||||
line = fpart.readline()
|
||||
while line:
|
||||
p_details = line.split()
|
||||
if (len(p_details) == 4):
|
||||
"the following code prevents double entries like /dev/hda and /dev/hda1"
|
||||
## the following code prevents double entries like /dev/hda and /dev/hda1
|
||||
(p_major, p_minor, p_size, p_device) = p_details
|
||||
## ignore lines with: invalid minor/major or extend partitions (size=1)
|
||||
if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor) and (p_size != "1"):
|
||||
if re.search('^[0-9]*$', p_major) and \
|
||||
re.search('^[0-9]*$', p_minor) and (p_size != "1"):
|
||||
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
|
||||
if p_parent == p_device:
|
||||
if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
|
||||
"major partition - its children are already in the list"
|
||||
if [e for e in ret_list
|
||||
if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
|
||||
## major partition - its children are already in the list
|
||||
pass
|
||||
else:
|
||||
"major partition - but there are no children for now"
|
||||
## major partition - but there are no children for now
|
||||
ret_list.append(p_device)
|
||||
else:
|
||||
"minor partition - remove parent if necessary"
|
||||
if p_parent in ret_list: ret_list.remove(p_parent)
|
||||
## minor partition - remove parent if necessary
|
||||
if p_parent in ret_list:
|
||||
ret_list.remove(p_parent)
|
||||
ret_list.append(p_device)
|
||||
line = fpart.readline()
|
||||
finally:
|
||||
fpart.close()
|
||||
return map(getAbsoluteDeviceName, ret_list)
|
||||
return [ get_absolute_devicename(e) for e in ret_list ]
|
||||
except IOError:
|
||||
logger.warning("Could not read /proc/partitions")
|
||||
LOGGER.warning("Could not read /proc/partitions")
|
||||
return []
|
||||
|
||||
|
||||
def getAbsoluteDeviceName(shortname):
|
||||
def get_absolute_devicename(shortname):
|
||||
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
|
||||
this does also work for device mapper devices
|
||||
if the result is non-unique, one arbitrary value is returned"""
|
||||
if re.search('^/', shortname): return shortname
|
||||
if the result is non-unique, one arbitrary value is returned
|
||||
"""
|
||||
if re.search('^/', shortname):
|
||||
return shortname
|
||||
default = os.path.join("/dev", shortname)
|
||||
if os.path.exists(default): return default
|
||||
result = findMajorMinorOfDevice(shortname)
|
||||
"if no valid major/minor was found -> exit"
|
||||
if not result: return default
|
||||
if os.path.exists(default):
|
||||
return default
|
||||
result = find_major_minor_of_device(shortname)
|
||||
## if no valid major/minor was found -> exit
|
||||
if not result:
|
||||
return default
|
||||
(major, minor) = result
|
||||
"for device-mapper devices (major == 254) ..."
|
||||
## for device-mapper devices (major == 254) ...
|
||||
if major == 254:
|
||||
result = findMajorMinorDeviceName("/dev/mapper", major, minor)
|
||||
if result: return result[0]
|
||||
"now check all files in /dev"
|
||||
result = findMajorMinorDeviceName("/dev", major, minor)
|
||||
if result: return result[0]
|
||||
result = find_major_minor_device("/dev/mapper", major, minor)
|
||||
if result:
|
||||
return result[0]
|
||||
## now check all files in /dev
|
||||
result = find_major_minor_device("/dev", major, minor)
|
||||
if result:
|
||||
return result[0]
|
||||
return default
|
||||
|
||||
|
||||
def findMajorMinorOfDevice(device):
|
||||
"return the major/minor numbers of a block device"
|
||||
if re.match("/", device) or not os.path.exists(os.path.join(os.path.sep,"sys","block",device)):
|
||||
def find_major_minor_of_device(device):
|
||||
"""Return the major/minor numbers of a block device.
|
||||
"""
|
||||
if re.match("/", device) or \
|
||||
not os.path.exists(os.path.join(os.path.sep, "sys", "block", device)):
|
||||
## maybe it is an absolute device name
|
||||
if not os.path.exists(device): return None
|
||||
if not os.path.exists(device):
|
||||
return None
|
||||
## okay - it seems to to a device node
|
||||
rdev = os.stat(device).st_rdev
|
||||
return (os.major(rdev), os.minor(rdev))
|
||||
blockdev_info_file = os.path.join(os.path.join(os.path.sep,"sys","block", device), "dev")
|
||||
blockdev_info_file = os.path.join(os.path.join(
|
||||
os.path.sep,"sys","block", device), "dev")
|
||||
try:
|
||||
f_blockdev_info = open(blockdev_info_file, "r")
|
||||
blockdev_info = f_blockdev_info.read()
|
||||
f_blockdev_info.close()
|
||||
(str_major, str_minor) = blockdev_info.split(":")
|
||||
"numeric conversion"
|
||||
## numeric conversion
|
||||
try:
|
||||
major = int(str_major)
|
||||
minor = int(str_minor)
|
||||
return (major, minor)
|
||||
except ValueError:
|
||||
"unknown device numbers -> stop guessing"
|
||||
## unknown device numbers -> stop guessing
|
||||
return None
|
||||
except IOError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def findMajorMinorDeviceName(dir, major, minor):
|
||||
"returns the names of devices with the specified major and minor number"
|
||||
def find_major_minor_device(dirpath, major, minor):
|
||||
"""Returns the names of devices with the specified major and minor number.
|
||||
"""
|
||||
collected = []
|
||||
try:
|
||||
subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))]
|
||||
"do a recursive call to parse the directory tree"
|
||||
subdirs = [os.path.join(dirpath, e) for e in os.listdir(dirpath)
|
||||
if (not os.path.islink(os.path.join(dirpath, e))) and \
|
||||
os.path.isdir(os.path.join(dirpath, e))]
|
||||
## do a recursive call to parse the directory tree
|
||||
for dirs in subdirs:
|
||||
collected.extend(findMajorMinorDeviceName(dirs, major, minor))
|
||||
"filter all device inodes in this directory"
|
||||
collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)])
|
||||
collected.extend(find_major_minor_device(dirs, major, minor))
|
||||
## filter all device inodes in this directory
|
||||
collected.extend([os.path.realpath(os.path.join(dirpath, e))
|
||||
for e in os.listdir(dirpath)
|
||||
if (os.major(os.stat(os.path.join(dirpath, e)).st_rdev) == major) \
|
||||
and (os.minor(os.stat(os.path.join(dirpath, e)).st_rdev) == minor)])
|
||||
## remove double entries
|
||||
result = []
|
||||
for e in collected:
|
||||
if e not in result: result.append(e)
|
||||
for item in collected:
|
||||
if item not in result:
|
||||
result.append(item)
|
||||
return result
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
|
||||
def getParentBlockDevices():
|
||||
def get_parent_blockdevices():
|
||||
"""Return a list of all block devices that contain other devices.
|
||||
"""
|
||||
devs = []
|
||||
for line in file("/proc/partitions"):
|
||||
p_details = line.split()
|
||||
## we expect four values - otherwise continue with next iteration
|
||||
if len(p_details) != 4: continue
|
||||
if len(p_details) != 4:
|
||||
continue
|
||||
(p_major, p_minor, p_size, p_device) = p_details
|
||||
## we expect numeric values in the first two columns
|
||||
if re.search(u'\D',p_major) or re.search(u'\D',p_minor): continue
|
||||
if re.search(u'\D', p_major) or re.search(u'\D', p_minor):
|
||||
continue
|
||||
## now let us check, if it is a (parent) block device or a partition
|
||||
if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)): continue
|
||||
if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)):
|
||||
continue
|
||||
devs.append(p_device)
|
||||
return map(getAbsoluteDeviceName, devs)
|
||||
return [ get_absolute_devicename(e) for e in devs ]
|
||||
|
||||
|
||||
def isPartOfBlockDevice(parent, subdevice):
|
||||
"""check if the given block device is a parent of 'subdevice'
|
||||
e.g. for checking if a partition belongs to a block device"""
|
||||
def is_part_of_blockdevice(parent, subdevice):
|
||||
"""Check if the given block device is a parent of 'subdevice'.
|
||||
|
||||
e.g. for checking if a partition belongs to a block device
|
||||
"""
|
||||
try:
|
||||
(par_major, par_minor) = findMajorMinorOfDevice(parent)
|
||||
(sub_major, sub_minor) = findMajorMinorOfDevice(subdevice)
|
||||
(par_major, par_minor) = find_major_minor_of_device(parent)
|
||||
(sub_major, sub_minor) = find_major_minor_of_device(subdevice)
|
||||
except TypeError:
|
||||
## at least one of these devices did not return a valid major/minor combination
|
||||
return False
|
||||
|
@ -158,7 +190,8 @@ def isPartOfBlockDevice(parent, subdevice):
|
|||
blpath = os.path.join(root, bldev, 'dev')
|
||||
if os.access(blpath, os.R_OK):
|
||||
try:
|
||||
if (str(par_major), str(par_minor)) == tuple([e for e in file(blpath)][0].strip().split(":",1)):
|
||||
if (str(par_major), str(par_minor)) == tuple([e
|
||||
for e in file(blpath)][0].strip().split(":",1)):
|
||||
parent_path = os.path.join(root, bldev)
|
||||
break
|
||||
except (IndexError, OSError):
|
||||
|
@ -170,7 +203,8 @@ def isPartOfBlockDevice(parent, subdevice):
|
|||
subblpath = os.path.join(parent_path, subbldev, "dev")
|
||||
if os.access(subblpath, os.R_OK):
|
||||
try:
|
||||
if (str(sub_major), str(sub_minor)) == tuple([e for e in file(subblpath)][0].strip().split(":",1)):
|
||||
if (str(sub_major), str(sub_minor)) == tuple([e
|
||||
for e in file(subblpath)][0].strip().split(":",1)):
|
||||
## the name of the subdevice node is not important - we found it!
|
||||
return True
|
||||
except (IndexError, OSError):
|
||||
|
@ -178,18 +212,22 @@ def isPartOfBlockDevice(parent, subdevice):
|
|||
return False
|
||||
|
||||
|
||||
def getBlockDeviceSize(device):
|
||||
if not device: return -1
|
||||
def get_blockdevice_size(device):
|
||||
"""Return the size of a blockdevice.
|
||||
"""
|
||||
if not device:
|
||||
return -1
|
||||
try:
|
||||
rdev = os.stat(device).st_rdev
|
||||
except OSError:
|
||||
return -1
|
||||
minor = os.minor(rdev)
|
||||
major = os.major(rdev)
|
||||
for f in file("/proc/partitions"):
|
||||
for line in file("/proc/partitions"):
|
||||
try:
|
||||
elements = f.split()
|
||||
if len(elements) != 4: continue
|
||||
elements = line.split()
|
||||
if len(elements) != 4:
|
||||
continue
|
||||
if (int(elements[0]) == major) and (int(elements[1]) == minor):
|
||||
return int(elements[2])/1024
|
||||
except ValueError:
|
||||
|
@ -197,8 +235,10 @@ def getBlockDeviceSize(device):
|
|||
return -1
|
||||
|
||||
|
||||
def getBlockDeviceSizeHumanly(device):
|
||||
size = getBlockDeviceSize(device)
|
||||
def get_blockdevice_size_humanly(device):
|
||||
"""Return a human readable size of a blockdevice.
|
||||
"""
|
||||
size = get_blockdevice_size(device)
|
||||
if size > 5120:
|
||||
return "%sGB" % size/1024
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"""Features may be easily added to the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
__all__ = [ 'base', 'manage' ]
|
||||
|
|
@ -21,161 +21,189 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""All features should inherit from this class.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import os
|
||||
import cherrypy
|
||||
|
||||
|
||||
class CryptoBoxPlugin:
|
||||
"""The base class of all features.
|
||||
"""
|
||||
|
||||
## default capability is "system" - the other supported capability is: "volume"
|
||||
pluginCapabilities = [ "system" ]
|
||||
plugin_capabilities = [ "system" ]
|
||||
|
||||
## where should the plugin be visible by default?
|
||||
pluginVisibility = [ "preferences" ]
|
||||
plugin_visibility = [ "preferences" ]
|
||||
|
||||
## does this plugin require admin authentification?
|
||||
requestAuth = False
|
||||
request_auth = False
|
||||
|
||||
## default rank (0..100) of the plugin in listings (lower value means higher priority)
|
||||
rank = 80
|
||||
|
||||
|
||||
## default icon of this plugin (relative path)
|
||||
defaultIconFileName = "plugin_icon.gif"
|
||||
default_icon_filename = "plugin_icon.gif"
|
||||
|
||||
## fallback icon file (in the common plugin directory)
|
||||
fallbackIconFileName = "plugin_icon_unknown.gif"
|
||||
fallback_icon_filename = "plugin_icon_unknown.gif"
|
||||
|
||||
|
||||
def __init__(self, cbox, pluginDir, siteClass=None):
|
||||
def __init__(self, cbox, plugin_dir, site_class=None):
|
||||
self.cbox = cbox
|
||||
self.hdf = {}
|
||||
self.pluginDir = pluginDir
|
||||
self.hdf_prefix = "Data.Plugins.%s." % self.getName()
|
||||
self.site = siteClass
|
||||
self.plugin_dir = plugin_dir
|
||||
self.hdf_prefix = "Data.Plugins.%s." % self.get_name()
|
||||
self.site = site_class
|
||||
|
||||
|
||||
|
||||
def doAction(self, **args):
|
||||
"""override doAction with your plugin code"""
|
||||
raise Exception, "undefined action handler ('doAction') in plugin '%'" % self.getName()
|
||||
def do_action(self, **args):
|
||||
"""Override do_action with your plugin code
|
||||
"""
|
||||
raise Exception, \
|
||||
"undefined action handler ('do_action') in plugin '%s'" % self.get_name()
|
||||
|
||||
|
||||
def getStatus(self):
|
||||
"""you should override this, to supply useful state information"""
|
||||
raise Exception, "undefined state handler ('getStatus') in plugin '%'" % self.getName()
|
||||
def get_status(self):
|
||||
"""you should override this, to supply useful state information
|
||||
"""
|
||||
raise Exception, \
|
||||
"undefined state handler ('get_status') in plugin '%s'" % self.get_name()
|
||||
|
||||
|
||||
def getName(self):
|
||||
"""the name of the python file (module) should be the name of the plugin"""
|
||||
def get_name(self):
|
||||
"""the name of the python file (module) should be the name of the plugin
|
||||
"""
|
||||
return self.__module__
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def getIcon(self, image=None, **kargs):
|
||||
def get_icon(self, image=None, **kargs):
|
||||
"""return the image data of the icon of the plugin
|
||||
|
||||
the parameter 'image' may be used for alternative image locations (relative
|
||||
to the directory of the plugin)
|
||||
'**kargs' is necessary, as a 'weblang' attribute may be specified (and ignored)"""
|
||||
import cherrypy, re
|
||||
if (image is None): # or (re.search(u'[\w-\.]', image)):
|
||||
plugin_icon_file = os.path.join(self.pluginDir, self.defaultIconFileName)
|
||||
'**kargs' is necessary, as a 'weblang' attribute may be specified (and ignored)
|
||||
"""
|
||||
import re
|
||||
if (image is None) or (not re.match(u'[\w\-\.]*$', image)):
|
||||
plugin_icon_file = os.path.join(self.plugin_dir, self.default_icon_filename)
|
||||
else:
|
||||
plugin_icon_file = os.path.join(self.pluginDir, image)
|
||||
plugin_icon_file = os.path.join(self.plugin_dir, image)
|
||||
if not os.access(plugin_icon_file, os.R_OK):
|
||||
plugin_icon_file = os.path.join(self.cbox.prefs["Locations"]["PluginDir"], self.fallbackIconFileName)
|
||||
plugin_icon_file = os.path.join(
|
||||
self.cbox.prefs["Locations"]["PluginDir"], self.fallback_icon_filename)
|
||||
return cherrypy.lib.cptools.serveFile(plugin_icon_file)
|
||||
|
||||
|
||||
def getTemplateFileName(self, template_name):
|
||||
def get_template_filename(self, template_name):
|
||||
"""return the filename of the template, if it is part of this plugin
|
||||
|
||||
use this function to check, if the plugin provides the specified template
|
||||
"""
|
||||
result_file = os.path.join(self.pluginDir, template_name + ".cs")
|
||||
result_file = os.path.join(self.plugin_dir, template_name + ".cs")
|
||||
if os.access(result_file, os.R_OK) and os.path.isfile(result_file):
|
||||
return result_file
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def getLanguageData(self):
|
||||
def get_language_data(self):
|
||||
"""Retrieve the language data of the feature.
|
||||
|
||||
Typically this is the content of the language.hdf file as a HDF object.
|
||||
"""
|
||||
import neo_cgi, neo_util
|
||||
lang_hdf = neo_util.HDF()
|
||||
langFile = os.path.join(self.pluginDir, 'language.hdf')
|
||||
lang_file = os.path.join(self.plugin_dir, 'language.hdf')
|
||||
try:
|
||||
lang_hdf.readFile(langFile)
|
||||
except (neo_util.Error, neo_util.ParseError), errMsg:
|
||||
self.cbox.log.error("failed to load language file (%s) of plugin (%s):" % (langFile,self.getName()))
|
||||
lang_hdf.readFile(lang_file)
|
||||
except (neo_util.Error, neo_util.ParseError):
|
||||
self.cbox.log.error("failed to load language file (%s) of plugin (%s):" % \
|
||||
(lang_file, self.get_name()))
|
||||
return lang_hdf
|
||||
|
||||
|
||||
def loadDataSet(self, hdf):
|
||||
def load_dataset(self, hdf):
|
||||
"""Add the local values of the feature to the hdf dataset.
|
||||
"""
|
||||
for (key, value) in self.hdf.items():
|
||||
hdf.setValue(key, str(value))
|
||||
|
||||
|
||||
def isAuthRequired(self):
|
||||
def is_auth_required(self):
|
||||
"""check if this plugin requires authentication
|
||||
first step: check plugin configuration
|
||||
second step: check default value of plugin"""
|
||||
second step: check default value of plugin
|
||||
"""
|
||||
try:
|
||||
if self.cbox.prefs.pluginConf[self.getName()]["requestAuth"] is None:
|
||||
return self.requestAuth
|
||||
if self.cbox.prefs.pluginConf[self.getName()]["requestAuth"]:
|
||||
if self.cbox.prefs.plugin_conf[self.get_name()]["requestAuth"] is None:
|
||||
return self.request_auth
|
||||
if self.cbox.prefs.plugin_conf[self.get_name()]["requestAuth"]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except KeyError:
|
||||
return self.requestAuth
|
||||
return self.request_auth
|
||||
|
||||
|
||||
def isEnabled(self):
|
||||
def is_enabled(self):
|
||||
"""check if this plugin is enabled
|
||||
first step: check plugin configuration
|
||||
second step: check default value of plugin"""
|
||||
fallback = bool(self.pluginVisibility)
|
||||
second step: check default value of plugin
|
||||
"""
|
||||
fallback = bool(self.plugin_visibility)
|
||||
try:
|
||||
if self.cbox.prefs.pluginConf[self.getName()]["visibility"] is None:
|
||||
if self.cbox.prefs.plugin_conf[self.get_name()]["visibility"] is None:
|
||||
return fallback
|
||||
return bool(self.cbox.prefs.pluginConf[self.getName()]["visibility"])
|
||||
return bool(self.cbox.prefs.plugin_conf[self.get_name()]["visibility"])
|
||||
except KeyError:
|
||||
return fallback
|
||||
|
||||
|
||||
def getRank(self):
|
||||
def get_rank(self):
|
||||
"""check the rank of this plugin
|
||||
first step: check plugin configuration
|
||||
second step: check default value of plugin"""
|
||||
second step: check default value of plugin
|
||||
"""
|
||||
try:
|
||||
if self.cbox.prefs.pluginConf[self.getName()]["rank"] is None:
|
||||
if self.cbox.prefs.plugin_conf[self.get_name()]["rank"] is None:
|
||||
return self.rank
|
||||
return int(self.cbox.prefs.pluginConf[self.getName()]["rank"])
|
||||
return int(self.cbox.prefs.plugin_conf[self.get_name()]["rank"])
|
||||
except (KeyError, TypeError):
|
||||
return self.rank
|
||||
|
||||
|
||||
def getVisibility(self):
|
||||
def get_visibility(self):
|
||||
"""Check which visibility flags of the feature are set.
|
||||
"""
|
||||
try:
|
||||
if self.cbox.prefs.pluginConf[self.getName()]["visibility"] is None:
|
||||
return self.pluginVisibility[:]
|
||||
return self.cbox.prefs.pluginConf[self.getName()]["visibility"]
|
||||
if self.cbox.prefs.plugin_conf[self.get_name()]["visibility"] is None:
|
||||
return self.plugin_visibility[:]
|
||||
return self.cbox.prefs.plugin_conf[self.get_name()]["visibility"]
|
||||
except KeyError:
|
||||
return self.pluginVisibility
|
||||
return self.plugin_visibility
|
||||
|
||||
|
||||
def getTestClass(self):
|
||||
def get_test_class(self):
|
||||
"""Return the unittest class of the feature.
|
||||
"""
|
||||
import imp
|
||||
pl_file = os.path.join(self.pluginDir, "unittests.py")
|
||||
pl_file = os.path.join(self.plugin_dir, "unittests.py")
|
||||
if os.access(pl_file, os.R_OK) and os.path.isfile(pl_file):
|
||||
try:
|
||||
return getattr(imp.load_source("unittests_%s" % self.getName(), pl_file), "unittests")
|
||||
return imp.load_source("unittests_%s" % self.get_name(), pl_file).unittests
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
self.cbox.log.info("could not load unittests for plugin: %s" % self.getName())
|
||||
self.cbox.log.info("could not load unittests for plugin: %s" % \
|
||||
self.get_name())
|
||||
except AttributeError:
|
||||
pass
|
||||
return None
|
||||
|
|
|
@ -19,46 +19,56 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Manages the pluggable features of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import imp
|
||||
import os
|
||||
import logging
|
||||
|
||||
|
||||
class PluginManager:
|
||||
"""manage available plugins"""
|
||||
|
||||
def __init__(self, cbox, plugin_dirs=".", siteClass=None):
|
||||
def __init__(self, cbox, plugin_dirs=".", site_class=None):
|
||||
self.cbox = cbox
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
self.site = siteClass
|
||||
self.site = site_class
|
||||
if hasattr(plugin_dirs, "__iter__"):
|
||||
self.plugin_dirs = [os.path.abspath(dir) for dir in plugin_dirs]
|
||||
self.plugin_dirs = [os.path.abspath(d) for d in plugin_dirs]
|
||||
else:
|
||||
self.plugin_dirs = [os.path.abspath(plugin_dirs)]
|
||||
self.pluginList = self.__getAllPlugins()
|
||||
self.plugin_list = self.__get_all_plugins()
|
||||
|
||||
|
||||
def getPlugins(self):
|
||||
return self.pluginList[:]
|
||||
def get_plugins(self):
|
||||
"""Return a list of all feature instances.
|
||||
"""
|
||||
return self.plugin_list[:]
|
||||
|
||||
|
||||
def getPlugin(self, name):
|
||||
for p in self.pluginList[:]:
|
||||
if p.getName() == name:
|
||||
return p
|
||||
def get_plugin(self, name):
|
||||
"""Return the specified feature as an instance.
|
||||
"""
|
||||
for plugin in self.plugin_list[:]:
|
||||
if plugin.get_name() == name:
|
||||
return plugin
|
||||
return None
|
||||
|
||||
|
||||
def __getAllPlugins(self):
|
||||
list = []
|
||||
for plfile in self.__getPluginFiles():
|
||||
list.append(self.__getPluginClass(os.path.basename(plfile)[:-3]))
|
||||
return list
|
||||
def __get_all_plugins(self):
|
||||
"""Return all available features as instances.
|
||||
"""
|
||||
plist = []
|
||||
for plfile in self.__get_plugin_files():
|
||||
plist.append(self.__get_plugin_class(os.path.basename(plfile)[:-3]))
|
||||
return plist
|
||||
|
||||
|
||||
def __getPluginClass(self, name):
|
||||
for plfile in self.__getPluginFiles():
|
||||
def __get_plugin_class(self, name):
|
||||
"""Return a instance object of the give feature.
|
||||
"""
|
||||
import imp
|
||||
for plfile in self.__get_plugin_files():
|
||||
if name == os.path.basename(plfile)[:-3]:
|
||||
try:
|
||||
pl_class = getattr(imp.load_source(name, plfile), name)
|
||||
|
@ -69,18 +79,23 @@ class PluginManager:
|
|||
return None
|
||||
|
||||
|
||||
def __getPluginFiles(self):
|
||||
def __get_plugin_files(self):
|
||||
"""Retrieve all python files that may potentially be a feature.
|
||||
"""
|
||||
result = []
|
||||
if self.cbox and self.cbox.prefs["Main"]["DisabledPlugins"]:
|
||||
disabled = self.cbox.prefs["Main"]["DisabledPlugins"]
|
||||
else:
|
||||
disabled = []
|
||||
for dir in [os.path.abspath(e) for e in self.plugin_dirs if os.access(e, os.R_OK) and os.path.isdir(e)]:
|
||||
for plname in [f for f in os.listdir(dir)]:
|
||||
for pdir in [os.path.abspath(e) for e in self.plugin_dirs
|
||||
if os.access(e, os.R_OK) and os.path.isdir(e)]:
|
||||
for plname in [f for f in os.listdir(pdir)]:
|
||||
if plname in disabled:
|
||||
if self.cbox: self.cbox.log.info("skipped plugin '%s' (disabled via config)" % plname)
|
||||
if self.cbox:
|
||||
self.cbox.log.info(
|
||||
"skipped plugin '%s' (disabled via config)" % plname)
|
||||
continue
|
||||
pldir = os.path.join(dir, plname)
|
||||
pldir = os.path.join(pdir, plname)
|
||||
plfile = os.path.join(pldir, plname + ".py")
|
||||
if os.path.isfile(plfile) and os.access(plfile, os.R_OK):
|
||||
result.append(plfile)
|
||||
|
@ -88,8 +103,8 @@ class PluginManager:
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
x = PluginManager(None, "../plugins")
|
||||
for a in x.getPlugins():
|
||||
if not a is None:
|
||||
print "Plugin: %s" % a.getName()
|
||||
MANAGER = PluginManager(None, "../plugins")
|
||||
for one_plugin in MANAGER.get_plugins():
|
||||
if not one_plugin is None:
|
||||
print "Plugin: %s" % one_plugin.get_name()
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"""Some unittests for the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
__all__ = [ 'test.cryptobox', 'test.cryptoboxtools', 'test.plugins', 'test.websites' ]
|
||||
|
|
@ -19,33 +19,41 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Some unittests for the core CryptoBox modules.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
import cryptobox.core.main
|
||||
from cryptobox.core.exceptions import *
|
||||
import cryptobox.core.settings
|
||||
import os
|
||||
|
||||
class CryptoBoxPropsDeviceTests(unittest.TestCase):
|
||||
cb = cryptobox.core.main.CryptoBoxProps()
|
||||
class CryptoBoxDeviceTests(unittest.TestCase):
|
||||
"""Some unittests for the CryptoBox
|
||||
"""
|
||||
|
||||
cb = cryptobox.core.main.CryptoBox()
|
||||
|
||||
def testAllowedDevices(self):
|
||||
'''isDeviceAllowed should accept permitted devices'''
|
||||
self.assertTrue(self.cb.isDeviceAllowed("/dev/loop"))
|
||||
self.assertTrue(self.cb.isDeviceAllowed("/dev/loop1"))
|
||||
self.assertTrue(self.cb.isDeviceAllowed("/dev/loop/urgd"))
|
||||
self.assertTrue(self.cb.isDeviceAllowed("/dev/usb/../loop1"))
|
||||
def test_allowed_devices(self):
|
||||
'''is_device_allowed should accept permitted devices'''
|
||||
self.assertTrue(self.cb.is_device_allowed("/dev/loop"))
|
||||
self.assertTrue(self.cb.is_device_allowed("/dev/loop1"))
|
||||
self.assertTrue(self.cb.is_device_allowed("/dev/loop/urgd"))
|
||||
self.assertTrue(self.cb.is_device_allowed("/dev/usb/../loop1"))
|
||||
|
||||
def testDeniedDevices(self):
|
||||
'''isDeviceAllowed should fail with not explicitly allowed devices'''
|
||||
self.assertFalse(self.cb.isDeviceAllowed("/dev/hda"))
|
||||
self.assertFalse(self.cb.isDeviceAllowed("/dev/loopa/../hda"))
|
||||
self.assertFalse(self.cb.isDeviceAllowed("/"))
|
||||
def test_denied_devices(self):
|
||||
'''is_device_allowed should fail with not explicitly allowed devices'''
|
||||
self.assertFalse(self.cb.is_device_allowed("/dev/hda"))
|
||||
self.assertFalse(self.cb.is_device_allowed("/dev/loopa/../hda"))
|
||||
self.assertFalse(self.cb.is_device_allowed("/"))
|
||||
|
||||
|
||||
class CryptoBoxPropsConfigTests(unittest.TestCase):
|
||||
class CryptoBoxConfigTests(unittest.TestCase):
|
||||
'''test here if everything with the config turns right'''
|
||||
import os
|
||||
files = {
|
||||
"configFileOK" : "cbox-test_ok.conf",
|
||||
"configFileBroken" : "cbox-test_broken.conf",
|
||||
|
@ -86,71 +94,89 @@ CryptoBoxRootActions = CryptoBoxRootActions
|
|||
def setUp(self):
|
||||
'''generate all files in tmp and remember the names'''
|
||||
import tempfile
|
||||
os = self.os
|
||||
self.tmpdirname = tempfile.mkdtemp(prefix="cbox-")
|
||||
for file in self.files.keys():
|
||||
self.filenames[file] = os.path.join(self.tmpdirname, self.files[file])
|
||||
self.writeConfig()
|
||||
for tfile in self.files.keys():
|
||||
self.filenames[tfile] = os.path.join(self.tmpdirname, self.files[tfile])
|
||||
self.write_config()
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
'''remove the created tmpfiles'''
|
||||
os = self.os
|
||||
# remove temp files
|
||||
for file in self.filenames.values():
|
||||
compl_name = os.path.join(self.tmpdirname, file)
|
||||
for tfile in self.filenames.values():
|
||||
compl_name = os.path.join(self.tmpdirname, tfile)
|
||||
if os.path.exists(compl_name):
|
||||
os.remove(compl_name)
|
||||
# remove temp dir
|
||||
os.rmdir(self.tmpdirname)
|
||||
|
||||
|
||||
def testConfigInit(self):
|
||||
def test_config_init(self):
|
||||
'''Check various branches of config file loading'''
|
||||
import os
|
||||
self.assertRaises(CBConfigUnavailableError, cryptobox.core.main.CryptoBoxProps,"/invalid/path/to/config/file")
|
||||
self.assertRaises(CBConfigUnavailableError, cryptobox.core.main.CryptoBoxProps,"/etc/shadow")
|
||||
""" check one of the following things:
|
||||
1) are we successfully using an existing config file?
|
||||
2) do we break, if no config file is there?
|
||||
depending on the existence of a config file, only one of these conditions
|
||||
can be checked - hints for more comprehensive tests are appreciated :) """
|
||||
for a in ['cryptobox.conf']:
|
||||
if os.path.exists(a):
|
||||
cryptobox.core.main.CryptoBoxProps()
|
||||
self.assertRaises(CBConfigUnavailableError,
|
||||
cryptobox.core.main.CryptoBox,"/invalid/path/to/config/file")
|
||||
self.assertRaises(CBConfigUnavailableError,
|
||||
cryptobox.core.main.CryptoBox,"/etc/shadow")
|
||||
## check one of the following things:
|
||||
## 1) are we successfully using an existing config file?
|
||||
## 2) do we break, if no config file is there?
|
||||
## depending on the existence of a config file, only one of these conditions
|
||||
## can be checked - hints for more comprehensive tests are appreciated :)
|
||||
for cfile in ['cryptobox.conf']:
|
||||
if os.path.exists(cfile):
|
||||
cryptobox.core.main.CryptoBox()
|
||||
break # this skips the 'else' clause
|
||||
else: self.assertRaises(CBConfigUnavailableError, cryptobox.core.main.CryptoBoxProps)
|
||||
self.assertRaises(CBConfigUnavailableError, cryptobox.core.main.CryptoBoxProps,[])
|
||||
else:
|
||||
self.assertRaises(CBConfigUnavailableError,
|
||||
cryptobox.core.main.CryptoBox)
|
||||
self.assertRaises(CBConfigUnavailableError,
|
||||
cryptobox.core.main.CryptoBox,[])
|
||||
|
||||
|
||||
def testBrokenConfigs(self):
|
||||
"""Check various broken configurations"""
|
||||
self.writeConfig("SettingsDir", "SettingsDir=/foo/bar", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
self.writeConfig("Level", "Level = ho", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
self.writeConfig("Details", "#out", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
self.writeConfig("super", "super=/bin/invalid/no", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
self.writeConfig("CryptoBoxRootActions", "#not here", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
self.writeConfig("CryptoBoxRootActions", "CryptoBoxRootActions = /bin/false", filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBEnvironmentError, cryptobox.core.main.CryptoBoxProps,self.filenames["configFileBroken"])
|
||||
def test_broken_configs(self):
|
||||
"""Check various broken configurations
|
||||
"""
|
||||
self.write_config("SettingsDir", "SettingsDir=/foo/bar",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
self.write_config("Level", "Level = ho",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
self.write_config("Details", "#out",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
self.write_config("super", "super=/bin/invalid/no",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
self.write_config("CryptoBoxRootActions", "#not here",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
self.write_config("CryptoBoxRootActions", "CryptoBoxRootActions = /bin/false",
|
||||
filename=self.filenames["configFileBroken"])
|
||||
self.assertRaises(CBEnvironmentError, cryptobox.core.main.CryptoBox,
|
||||
self.filenames["configFileBroken"])
|
||||
|
||||
|
||||
def writeConfig(self, replace=None, newline=None, filename=None):
|
||||
def write_config(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 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()
|
||||
cfile = open(filename, "w")
|
||||
cfile.write(content)
|
||||
cfile.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
|
|
@ -19,9 +19,14 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Unittests for cryptobox.core.tools
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
|
||||
import unittest
|
||||
import cryptobox.core.tools as cbxTools
|
||||
import cryptobox.core.tools as cbx_tools
|
||||
import os
|
||||
|
||||
## use /dev/ubd? if possible - otherwise /dev/hd?
|
||||
|
@ -36,30 +41,40 @@ else:
|
|||
|
||||
|
||||
class CryptoBoxToolsTests(unittest.TestCase):
|
||||
"""All unittests for cryptoboxtools
|
||||
"""
|
||||
|
||||
def testGetAbsoluteDeviceName(self):
|
||||
func = cbxTools.getAbsoluteDeviceName
|
||||
def test_get_absolute_devicename(self):
|
||||
"""check the get_absolute_devicename function
|
||||
"""
|
||||
func = cbx_tools.get_absolute_devicename
|
||||
self.assertTrue(func(device) == "/dev/%s" % device)
|
||||
self.assertTrue(func("loop0") == "/dev/loop0")
|
||||
self.assertTrue(func(os.path.devnull) == os.path.devnull)
|
||||
|
||||
|
||||
def testFindMajorMinorOfDevice(self):
|
||||
func = cbxTools.findMajorMinorOfDevice
|
||||
self.assertTrue(func(os.path.devnull) == (1,3))
|
||||
def test_find_major_minor_of_device(self):
|
||||
"""check the find_major_minor_of_device function
|
||||
"""
|
||||
func = cbx_tools.find_major_minor_of_device
|
||||
self.assertTrue(func(os.path.devnull) == (1, 3))
|
||||
self.assertTrue(func("/dev/nothere") is None)
|
||||
|
||||
|
||||
def testFindMajorMinorDeviceName(self):
|
||||
func = cbxTools.findMajorMinorDeviceName
|
||||
dir = os.path.join(os.path.sep, "dev")
|
||||
self.assertTrue(os.path.devnull in func(dir,1,3))
|
||||
self.assertFalse(os.path.devnull in func(dir,2,3))
|
||||
self.assertFalse(None in func(dir,17,23))
|
||||
def test_find_major_minor_device(self):
|
||||
"""check the find_major_minor_device function
|
||||
"""
|
||||
func = cbx_tools.find_major_minor_device
|
||||
path = os.path.join(os.path.sep, "dev")
|
||||
self.assertTrue(os.path.devnull in func(path, 1, 3))
|
||||
self.assertFalse(os.path.devnull in func(path, 2, 3))
|
||||
self.assertFalse(None in func(path, 17, 23))
|
||||
|
||||
|
||||
def testIsPartOfBlockDevice(self):
|
||||
func = cbxTools.isPartOfBlockDevice
|
||||
def test_is_part_of_blockdevice(self):
|
||||
"""check the is_part_of_blockdevice function
|
||||
"""
|
||||
func = cbx_tools.is_part_of_blockdevice
|
||||
self.assertTrue(func("/dev/%s" % device, "/dev/%s1" % device))
|
||||
self.assertFalse(func("/dev/%s" % device, "/dev/%s" % device))
|
||||
self.assertFalse(func("/dev/%s1" % device, "/dev/%s" % device))
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""This module handles the unittests of all features.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import unittest
|
||||
import cryptobox.plugins.manage
|
||||
|
@ -28,20 +32,21 @@ class CheckForUndefinedTestCases(unittest.TestCase):
|
|||
|
||||
|
||||
def create_testcases():
|
||||
|
||||
plugins = cryptobox.plugins.manage.PluginManager(None, "../plugins").getPlugins()
|
||||
"""Create functions that execute unittests for all features.
|
||||
"""
|
||||
plugins = cryptobox.plugins.manage.PluginManager(None, "../plugins").get_plugins()
|
||||
glob_dict = globals()
|
||||
loc_dict = locals()
|
||||
for pl in plugins:
|
||||
test_class = pl.getTestClass()
|
||||
for plugin in plugins:
|
||||
test_class = plugin.get_test_class()
|
||||
if test_class:
|
||||
## add the testclass to the global dictionary
|
||||
glob_dict["unittest" + pl.getName()] = test_class
|
||||
glob_dict["unittest" + plugin.get_name()] = test_class
|
||||
else:
|
||||
subname = "test_existence_%s" % pl.getName()
|
||||
subname = "test_existence_%s" % plugin.get_name()
|
||||
def test_existence(self):
|
||||
"""check if the plugin (%s) contains tests""" % pl.getName()
|
||||
self.fail("no tests defined for plugin: %s" % pl.getName())
|
||||
"""check if the plugin (%s) contains tests""" % plugin.get_name()
|
||||
self.fail("no tests defined for plugin: %s" % plugin.get_name())
|
||||
## add this function to the class above
|
||||
setattr(CheckForUndefinedTestCases, subname, test_existence)
|
||||
#FIXME: the failure output always contains the same name for all plugins
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Base class for all unittests involving the webserver.
|
||||
|
||||
This class uses twill.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import unittest
|
||||
|
||||
|
@ -32,28 +38,32 @@ import cryptobox.web.testclass
|
|||
|
||||
|
||||
class WebServer(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
"""Basic tests for the webserver.
|
||||
"""
|
||||
|
||||
def test_is_server_running(self):
|
||||
'''the server should run under given name and port'''
|
||||
self.register_auth(self.URL)
|
||||
self.cmd.go(self.URL)
|
||||
self.register_auth(self.url)
|
||||
self.cmd.go(self.url)
|
||||
self.cmd.find("CBOX-STATUS")
|
||||
## other URLs must not be checked, as we do not know, if they are valid
|
||||
|
||||
|
||||
class BuiltinPages(cryptobox.web.testclass.WebInterfaceTestClass):
|
||||
"""Basic test of builtin pages (no features).
|
||||
"""
|
||||
|
||||
|
||||
def test_goto_index(self):
|
||||
'''display all devices'''
|
||||
self.register_auth(self.URL)
|
||||
self.cmd.go(self.URL)
|
||||
self.register_auth(self.url)
|
||||
self.cmd.go(self.url)
|
||||
self.cmd.find("The CryptoBox")
|
||||
self.cmd.go(self.URL + "?weblang=de")
|
||||
self.cmd.go(self.url + "?weblang=de")
|
||||
self.cmd.find("Die CryptoBox")
|
||||
self.cmd.go(self.URL + "?weblang=sl")
|
||||
self.cmd.go(self.url + "?weblang=sl")
|
||||
self.cmd.find("Privatnost v vsako vas")
|
||||
self.cmd.go(self.URL + "?weblang=fr")
|
||||
self.cmd.go(self.url + "?weblang=fr")
|
||||
self.cmd.find("La CryptoBox")
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"""The webinterface of the CryptoBox.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
__all__ = [ 'dataset', 'languages', 'sites', 'testclass' ]
|
||||
|
|
@ -18,8 +18,12 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""Manage the hdf dataset of the cryptobox web sites.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import os
|
||||
from cryptobox.core.exceptions import *
|
||||
import cryptobox.core.container as cbxContainer
|
||||
import cryptobox.core.tools as cbxTools
|
||||
|
||||
|
@ -30,20 +34,24 @@ class WebInterfaceDataset(dict):
|
|||
"""
|
||||
|
||||
def __init__(self, cbox, prefs, plugins):
|
||||
super(WebInterfaceDataset, self).__init__()
|
||||
self.prefs = prefs
|
||||
self.cbox = cbox
|
||||
self.__setConfigValues()
|
||||
self.__set_config_values()
|
||||
self.plugins = plugins
|
||||
self.setCryptoBoxState()
|
||||
self.setPluginData()
|
||||
self.setContainersState()
|
||||
self.set_crypto_box_state()
|
||||
self.set_plugin_data()
|
||||
self.set_containers_state()
|
||||
|
||||
|
||||
def setCryptoBoxState(self):
|
||||
def set_crypto_box_state(self):
|
||||
"""Set some hdf values according to the cryptobox as a whole.
|
||||
"""
|
||||
import cherrypy
|
||||
import cryptobox.core.main
|
||||
import cryptobox.web.languages
|
||||
self["Data.Version"] = cryptobox.core.main.VERSION
|
||||
import cryptobox
|
||||
self["Data.Version"] = cryptobox.__version__
|
||||
langs = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||
langs.sort()
|
||||
for (index, lang) in enumerate(langs):
|
||||
|
@ -58,10 +66,11 @@ class WebInterfaceDataset(dict):
|
|||
try:
|
||||
self["Data.ScriptURL.Prot"] = cherrypy.request.scheme
|
||||
host = cherrypy.request.headers["Host"]
|
||||
self["Data.ScriptURL.Host"] = host.split(":",1)[0]
|
||||
complete_url = "%s://%s" % (self["Data.ScriptURL.Prot"], self["Data.ScriptURL.Host"])
|
||||
self["Data.ScriptURL.Host"] = host.split(":", 1)[0]
|
||||
complete_url = "%s://%s" % \
|
||||
(self["Data.ScriptURL.Prot"], self["Data.ScriptURL.Host"])
|
||||
try:
|
||||
port = int(host.split(":",1)[1])
|
||||
port = int(host.split(":", 1)[1])
|
||||
complete_url += ":%s" % port
|
||||
except (IndexError, ValueError):
|
||||
if cherrypy.request.scheme == "http":
|
||||
|
@ -70,7 +79,8 @@ class WebInterfaceDataset(dict):
|
|||
port = 443
|
||||
else:
|
||||
## unknown scheme -> port 0
|
||||
self.cbox.log.info("unknown protocol scheme used: %s" % (cherrypy.request.scheme,))
|
||||
self.cbox.log.info(
|
||||
"unknown protocol scheme used: %s" % (cherrypy.request.scheme,))
|
||||
port = 0
|
||||
self["Data.ScriptURL.Port"] = port
|
||||
## retrieve the relative address of the CGI (or the cherrypy base address)
|
||||
|
@ -83,20 +93,25 @@ class WebInterfaceDataset(dict):
|
|||
self["Data.ScriptURL"] = ""
|
||||
|
||||
|
||||
def setCurrentDiskState(self, device):
|
||||
for container in self.cbox.getContainerList():
|
||||
if container.getDevice() == device:
|
||||
isEncrypted = (container.getType() == cbxContainer.ContainerTypes["luks"]) and 1 or 0
|
||||
isPlain = (container.getType() == cbxContainer.ContainerTypes["plain"]) and 1 or 0
|
||||
isMounted = container.isMounted() and 1 or 0
|
||||
self["Data.CurrentDisk.device"] = container.getDevice()
|
||||
self["Data.CurrentDisk.name"] = container.getName()
|
||||
self["Data.CurrentDisk.encryption"] = isEncrypted
|
||||
self["Data.CurrentDisk.plaintext"] = isPlain
|
||||
self["Data.CurrentDisk.active"] = isMounted
|
||||
self["Data.CurrentDisk.size"] = cbxTools.getBlockDeviceSizeHumanly(container.getDevice())
|
||||
if isMounted:
|
||||
(size, avail, used) = container.getCapacity()
|
||||
def set_current_disk_state(self, device):
|
||||
"""Set some hdf values according to the currently active disk.
|
||||
"""
|
||||
for container in self.cbox.get_container_list():
|
||||
if container.get_device() == device:
|
||||
is_encrypted = (container.get_type() == \
|
||||
cbxContainer.CONTAINERTYPES["luks"]) and 1 or 0
|
||||
is_plain = (container.get_type() == \
|
||||
cbxContainer.CONTAINERTYPES["plain"]) and 1 or 0
|
||||
is_mounted = container.is_mounted() and 1 or 0
|
||||
self["Data.CurrentDisk.device"] = container.get_device()
|
||||
self["Data.CurrentDisk.name"] = container.get_name()
|
||||
self["Data.CurrentDisk.encryption"] = is_encrypted
|
||||
self["Data.CurrentDisk.plaintext"] = is_plain
|
||||
self["Data.CurrentDisk.active"] = is_mounted
|
||||
self["Data.CurrentDisk.size"] = cbxTools.get_blockdevice_size_humanly(
|
||||
container.get_device())
|
||||
if is_mounted:
|
||||
(size, avail, used) = container.get_capacity()
|
||||
percent = used / size
|
||||
self["Data.CurrentDisk.capacity.used"] = used
|
||||
self["Data.CurrentDisk.capacity.free"] = avail
|
||||
|
@ -105,51 +120,63 @@ class WebInterfaceDataset(dict):
|
|||
self["Settings.LinkAttrs.device"] = device
|
||||
|
||||
|
||||
def setContainersState(self):
|
||||
def set_containers_state(self):
|
||||
"""Set some hdf values according to the list of available containers.
|
||||
"""
|
||||
avail_counter = 0
|
||||
active_counter = 0
|
||||
for container in self.cbox.getContainerList():
|
||||
for container in self.cbox.get_container_list():
|
||||
## useful if the container was changed during an action
|
||||
container.resetObject()
|
||||
isEncrypted = (container.getType() == cbxContainer.ContainerTypes["luks"]) and 1 or 0
|
||||
isPlain = (container.getType() == cbxContainer.ContainerTypes["plain"]) and 1 or 0
|
||||
isMounted = container.isMounted() and 1 or 0
|
||||
self["Data.Disks.%d.device" % avail_counter] = container.getDevice()
|
||||
self["Data.Disks.%d.name" % avail_counter] = container.getName()
|
||||
self["Data.Disks.%d.encryption" % avail_counter] = isEncrypted
|
||||
self["Data.Disks.%d.plaintext" % avail_counter] = isPlain
|
||||
self["Data.Disks.%d.active" % avail_counter] = isMounted
|
||||
self["Data.Disks.%d.size" % avail_counter] = cbxTools.getBlockDeviceSizeHumanly(container.getDevice())
|
||||
if isMounted: active_counter += 1
|
||||
container.reset_object()
|
||||
is_encrypted = (container.get_type() == \
|
||||
cbxContainer.CONTAINERTYPES["luks"]) and 1 or 0
|
||||
is_plain = (container.get_type() == \
|
||||
cbxContainer.CONTAINERTYPES["plain"]) and 1 or 0
|
||||
is_mounted = container.is_mounted() and 1 or 0
|
||||
self["Data.Disks.%d.device" % avail_counter] = container.get_device()
|
||||
self["Data.Disks.%d.name" % avail_counter] = container.get_name()
|
||||
self["Data.Disks.%d.encryption" % avail_counter] = is_encrypted
|
||||
self["Data.Disks.%d.plaintext" % avail_counter] = is_plain
|
||||
self["Data.Disks.%d.active" % avail_counter] = is_mounted
|
||||
self["Data.Disks.%d.size" % avail_counter] = \
|
||||
cbxTools.get_blockdevice_size_humanly(container.get_device())
|
||||
if is_mounted:
|
||||
active_counter += 1
|
||||
avail_counter += 1
|
||||
self["Data.activeDisksCount"] = active_counter
|
||||
|
||||
|
||||
def setPluginData(self):
|
||||
for p in self.plugins:
|
||||
entryName = "Settings.PluginList." + p.getName()
|
||||
def set_plugin_data(self):
|
||||
"""Set some hdf values according to the available features.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
entry_name = "Settings.PluginList." + plugin.get_name()
|
||||
## first: remove all existing settings of this plugin
|
||||
for key in self.keys():
|
||||
if key.startswith(entryName): del self[key]
|
||||
lang_data = p.getLanguageData()
|
||||
self[entryName] = p.getName()
|
||||
self[entryName + ".Name"] = lang_data.getValue("Name", p.getName())
|
||||
self[entryName + ".Link"] = lang_data.getValue("Link", p.getName())
|
||||
self[entryName + ".Rank"] = p.getRank()
|
||||
self[entryName + ".RequestAuth"] = p.isAuthRequired() and "1" or "0"
|
||||
for a in p.pluginCapabilities:
|
||||
self[entryName + ".Types." + a] = "1"
|
||||
for a in p.getVisibility():
|
||||
self[entryName + ".Visible." + a] = "1"
|
||||
if key.startswith(entry_name):
|
||||
del self[key]
|
||||
lang_data = plugin.get_language_data()
|
||||
self[entry_name] = plugin.get_name()
|
||||
self[entry_name + ".Name"] = lang_data.getValue("Name", plugin.get_name())
|
||||
self[entry_name + ".Link"] = lang_data.getValue("Link", plugin.get_name())
|
||||
self[entry_name + ".Rank"] = plugin.get_rank()
|
||||
self[entry_name + ".RequestAuth"] = plugin.is_auth_required() and "1" or "0"
|
||||
for capy in plugin.plugin_capabilities:
|
||||
self[entry_name + ".Types." + capy] = "1"
|
||||
for visi in plugin.get_visibility():
|
||||
self[entry_name + ".Visible." + visi] = "1"
|
||||
|
||||
|
||||
def __setConfigValues(self):
|
||||
self["Settings.TemplateDir"] = os.path.abspath(self.prefs["Locations"]["TemplateDir"])
|
||||
def __set_config_values(self):
|
||||
"""Set some hdf values according to configuration settings.
|
||||
"""
|
||||
self["Settings.TemplateDir"] = os.path.abspath(
|
||||
self.prefs["Locations"]["TemplateDir"])
|
||||
self["Settings.DocDir"] = os.path.abspath(self.prefs["Locations"]["DocDir"])
|
||||
self["Settings.Stylesheet"] = self.prefs["WebSettings"]["Stylesheet"]
|
||||
self["Settings.Language"] = self.prefs["WebSettings"]["Languages"][0]
|
||||
for num,d in enumerate(self.prefs["Locations"]["PluginDir"]):
|
||||
self["Settings.PluginDir.%d" % num] = d
|
||||
for (num, dpath) in enumerate(self.prefs["Locations"]["PluginDir"]):
|
||||
self["Settings.PluginDir.%d" % num] = dpath
|
||||
## store the first directory in this settings variable - backward compatibility
|
||||
self["Settings.PluginDir"] = self.prefs["Locations"]["PluginDir"][0]
|
||||
self["Settings.SettingsDir"] = self.prefs["Locations"]["SettingsDir"]
|
||||
|
|
|
@ -22,23 +22,28 @@
|
|||
"""supply information about existing languages
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
## every language information should contain (name, pluralformat)
|
||||
LANGUAGE_INFO = {
|
||||
"cs": ('Český', ('3', '(n==1) ? 0 : (n>=2 && n< =4) ? 1 : 2')),
|
||||
"da": ('Dansk', ('2', '(n != 1)')),
|
||||
"de": ('Deutsch', ('2', '(n != 1)')),
|
||||
"en": ('English', ('2', '(n != 1)')),
|
||||
"es": ('Español', ('2', '(n != 1)')),
|
||||
"fi": ('Suomi', ('2', '(n != 1)')),
|
||||
"fr": ('Français', ('2', '(n != 1)')),
|
||||
"hu": ('Magyar', ('1', '0')),
|
||||
"it": ('Italiano', ('2', '(n != 1)')),
|
||||
"ja": ('日本語', ('1', '0')),
|
||||
"nl": ('Nederlands', ('2', '(n != 1)')),
|
||||
"pl": ('Polski', ('3', '(n==1 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 || n%100>=20) ? 1 : 2)')),
|
||||
"pt": ('Português', ('2', '(n != 1)')),
|
||||
"ru": ('Русский', ('3', '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 || n%100>=20) ? 1 : 2)')),
|
||||
"sl": ('Slovensko', ('4', '(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)')),
|
||||
"sv": ('Svenska', ('2', '(n != 1)')),
|
||||
}
|
||||
"cs": ('Český', ('3', '(n==1) ? 0 : (n>=2 && n< =4) ? 1 : 2')),
|
||||
"da": ('Dansk', ('2', '(n != 1)')),
|
||||
"de": ('Deutsch', ('2', '(n != 1)')),
|
||||
"en": ('English', ('2', '(n != 1)')),
|
||||
"es": ('Español', ('2', '(n != 1)')),
|
||||
"fi": ('Suomi', ('2', '(n != 1)')),
|
||||
"fr": ('Français', ('2', '(n != 1)')),
|
||||
"hu": ('Magyar', ('1', '0')),
|
||||
"it": ('Italiano', ('2', '(n != 1)')),
|
||||
"ja": ('日本語', ('1', '0')),
|
||||
"nl": ('Nederlands', ('2', '(n != 1)')),
|
||||
"pl": ('Polski', ('3', '(n==1 ? 0 : n%10>=2 && n%10< =4 '
|
||||
+ '&& (n%100<10 || n%100>=20) ? 1 : 2)')),
|
||||
"pt": ('Português', ('2', '(n != 1)')),
|
||||
"ru": ('Русский', ('3', '(n%10==1 && n%100!=11 ? 0 : '
|
||||
+ 'n%10>=2 && n%10< =4 && (n%100<10 || n%100>=20) ? 1 : 2)')),
|
||||
"sl": ('Slovensko', ('4', '(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || '
|
||||
+ 'n%100==4 ? 2 : 3)')),
|
||||
"sv": ('Svenska', ('2', '(n != 1)')),
|
||||
}
|
||||
|
||||
|
|
|
@ -17,103 +17,150 @@
|
|||
# along with the CryptoBox; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
""" this module handles all http requests and renders a website """
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import cryptobox.core.main
|
||||
import cryptobox.web.dataset
|
||||
import cryptobox.plugins.manage
|
||||
from cryptobox.core.exceptions import *
|
||||
import cryptobox.core.exceptions
|
||||
import re
|
||||
import cherrypy
|
||||
import types
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import neo_cgi, neo_util, neo_cs
|
||||
except ImportError:
|
||||
errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'."
|
||||
self.log.error(errorMsg)
|
||||
sys.stderr.write(errorMsg)
|
||||
raise ImportError, errorMsg
|
||||
_ERRMSG = "Could not import clearsilver module. \
|
||||
Try 'apt-get install python-clearsilver'."
|
||||
sys.stderr.write(_ERRMSG)
|
||||
raise ImportError, _ERRMSG
|
||||
|
||||
|
||||
GETTEXT_DOMAIN = 'cryptobox-server'
|
||||
|
||||
|
||||
class PluginIconHandler:
|
||||
"""deliver the icons of available plugins via cherrypy"""
|
||||
|
||||
def __init__(self, plugins):
|
||||
for plugin in plugins.getPlugins():
|
||||
if not plugin: continue
|
||||
plname = plugin.getName()
|
||||
## expose the getIcon function of this plugin
|
||||
setattr(self, plname, plugin.getIcon)
|
||||
for plugin in plugins.get_plugins():
|
||||
if not plugin:
|
||||
continue
|
||||
plname = plugin.get_name()
|
||||
## expose the get_icon function of this plugin
|
||||
setattr(self, plname, plugin.get_icon)
|
||||
|
||||
|
||||
|
||||
class WebInterfaceSites:
|
||||
'''
|
||||
'''
|
||||
"""handle all http requests and render pages
|
||||
|
||||
this includes:
|
||||
- filtering common arguments
|
||||
- calling feature actions
|
||||
- translating content
|
||||
|
||||
all available features are dynamically exposed
|
||||
"""
|
||||
|
||||
## this template is used under strange circumstances
|
||||
defaultTemplate = "empty"
|
||||
|
||||
|
||||
def __init__(self, conf_file=None):
|
||||
import logging,sys
|
||||
self.cbox = cryptobox.core.main.CryptoBoxProps(conf_file)
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
self.prefs = self.cbox.prefs
|
||||
self.__resetDataset()
|
||||
## we should only use variables preceded by "__" to avoid name conflicts
|
||||
## when loading features
|
||||
self.cbox = cryptobox.core.main.CryptoBox(conf_file)
|
||||
self.__cached_language_data = None
|
||||
self.__dataset = None
|
||||
self.icons = None
|
||||
self.__plugin_manager = None
|
||||
self.__reset_dataset()
|
||||
## store the original http error handler
|
||||
self._cp_on_http_error = self.newHTTPErrorHandler
|
||||
self._cp_on_http_error = self.new_http_error_handler
|
||||
## set initial language order
|
||||
self.langOrder = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||
self.lang_order = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||
|
||||
|
||||
def __resetDataset(self):
|
||||
def __reset_dataset(self):
|
||||
"""this method has to be called at the beginning of every "site" action
|
||||
important: only at the beginning of an action (to not loose information)
|
||||
important: for _every_ "site" action (cherrypy is stateful)
|
||||
also take care for the plugins, as they also contain datasets
|
||||
"""
|
||||
self.__loadPlugins()
|
||||
self.dataset = cryptobox.web.dataset.WebInterfaceDataset(self.cbox, self.prefs, self.pluginList.getPlugins())
|
||||
self.__load_plugins()
|
||||
self.__dataset = cryptobox.web.dataset.WebInterfaceDataset(
|
||||
self.cbox, self.cbox.prefs, self.__plugin_manager.get_plugins())
|
||||
## publish plugin icons
|
||||
self.icons = PluginIconHandler(self.pluginList)
|
||||
self.icons = PluginIconHandler(self.__plugin_manager)
|
||||
self.icons.exposed = True
|
||||
## check, if a configuration partition has become available
|
||||
self.cbox.prefs.preparePartition()
|
||||
self.cbox.prefs.prepare_partition()
|
||||
|
||||
|
||||
def __loadPlugins(self):
|
||||
self.pluginList = cryptobox.plugins.manage.PluginManager(self.cbox, self.prefs["Locations"]["PluginDir"], self)
|
||||
for plugin in self.pluginList.getPlugins():
|
||||
if not plugin: continue
|
||||
plname = plugin.getName()
|
||||
if plugin.isEnabled():
|
||||
self.cbox.log.info("Plugin '%s' loaded" % plname)
|
||||
## this should be the "easiest" way to expose all plugins as URLs
|
||||
setattr(self, plname, self.return_plugin_action(plugin))
|
||||
setattr(getattr(self, plname), "exposed", True)
|
||||
# TODO: check, if this really works - for now the "stream_response" feature seems to be broken
|
||||
#setattr(getattr(self, plname), "stream_respones", True)
|
||||
else:
|
||||
self.cbox.log.info("Plugin '%s' is disabled" % plname)
|
||||
## remove the plugin, if it was active before
|
||||
setattr(self, plname, None)
|
||||
def __load_plugins(self):
|
||||
"""reinitialize the list of available plugins
|
||||
|
||||
this includes the following:
|
||||
- reload all plugins and check their state (disabled or not)
|
||||
- reinitilize the datasets of all plugins
|
||||
"""
|
||||
self.__plugin_manager = cryptobox.plugins.manage.PluginManager(
|
||||
self.cbox, self.cbox.prefs["Locations"]["PluginDir"], self)
|
||||
for plugin in self.__plugin_manager.get_plugins():
|
||||
if not plugin:
|
||||
continue
|
||||
plname = plugin.get_name()
|
||||
## check if there are name conflicts: e.g. a local variable has the
|
||||
## same name as a plugin to be loaded -> skip these plugins
|
||||
## if we do not check this here, nasty side effects may occour ...
|
||||
try:
|
||||
prev_obj = getattr(self, plname)
|
||||
if not callable(prev_obj) \
|
||||
or not prev_obj.exposed:
|
||||
self.cbox.log.error("Skipped feature (%s) as its name"
|
||||
+ " conflicts with a local variable - see"
|
||||
+ " module cryptobox.web.sites" % plname)
|
||||
## skip this plugin
|
||||
continue
|
||||
except (NameError, AttributeError):
|
||||
## an attribute with the same name does not exist -> ok
|
||||
if plugin.is_enabled():
|
||||
self.cbox.log.info("Plugin '%s' loaded" % plname)
|
||||
## expose all features as URLs
|
||||
setattr(self, plname, self.return_plugin_action(plugin))
|
||||
getattr(self, plname).exposed = True
|
||||
#TODO: check, if this really works
|
||||
#for now the "stream_response" feature seems to be broken
|
||||
#setattr(getattr(self, plname), "stream_respones", True)
|
||||
else:
|
||||
self.cbox.log.info("Plugin '%s' is disabled" % plname)
|
||||
## remove the plugin, if it was active before
|
||||
setattr(self, plname, None)
|
||||
|
||||
|
||||
## this is a function decorator to check authentication
|
||||
## it has to be defined before any page definition requiring authentification
|
||||
def __requestAuth(self=None):
|
||||
## sub pages requiring authentication may not be defined above
|
||||
def __request_auth(self=None):
|
||||
""" this is a function decorator to check authentication
|
||||
"""
|
||||
def check_credentials(site):
|
||||
""" see description of _inner_wrapper - please simplify this!
|
||||
"""
|
||||
def _inner_wrapper(self, *args, **kargs):
|
||||
"""this function was necessary while trying around with the
|
||||
function decorator - if someone can implement the decorator
|
||||
with less effort, then any suggestions are welcome!
|
||||
"""
|
||||
import base64
|
||||
## define a "non-allowed" function
|
||||
user, password = None, None
|
||||
try:
|
||||
resp = cherrypy.request.headers["Authorization"][6:] # ignore "Basic "
|
||||
(user, password) = base64.b64decode(resp).split(":",1)
|
||||
## ignore the "Basic " (first six letters) part
|
||||
resp = cherrypy.request.headers["Authorization"][6:]
|
||||
(user, password) = base64.b64decode(resp).split(":", 1)
|
||||
except KeyError:
|
||||
## no "authorization" header was sent
|
||||
pass
|
||||
|
@ -123,18 +170,20 @@ class WebInterfaceSites:
|
|||
except AttributeError:
|
||||
## no cherrypy response header defined
|
||||
pass
|
||||
authDict = self.cbox.prefs.userDB["admins"]
|
||||
if user in authDict.keys():
|
||||
if self.cbox.prefs.userDB.getDigest(password) == authDict[user]:
|
||||
auth_dict = self.cbox.prefs.user_db["admins"]
|
||||
if user in auth_dict.keys():
|
||||
if self.cbox.prefs.user_db.get_digest(password) == auth_dict[user]:
|
||||
## ok: return the choosen page
|
||||
self.cbox.log.info("access granted for: %s" % user)
|
||||
return site(self, *args, **kargs)
|
||||
else:
|
||||
self.cbox.log.info("wrong password supplied for: %s" % user)
|
||||
self.cbox.log.info(
|
||||
"wrong password supplied for: %s" % user)
|
||||
else:
|
||||
self.cbox.log.info("unknown user: %s" % str(user))
|
||||
## wrong credentials: return "access denied"
|
||||
cherrypy.response.headers["WWW-Authenticate"] = '''Basic realm="CryptoBox"'''
|
||||
cherrypy.response.headers["WWW-Authenticate"] = \
|
||||
'''Basic realm="CryptoBox"'''
|
||||
cherrypy.response.status = 401
|
||||
return self.__render("access_denied")
|
||||
return _inner_wrapper
|
||||
|
@ -147,15 +196,18 @@ class WebInterfaceSites:
|
|||
|
||||
@cherrypy.expose
|
||||
def index(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
self.__checkEnvironment()
|
||||
"""the default page on startup - we show the list of available disks
|
||||
"""
|
||||
self.__reset_dataset()
|
||||
self.__set_web_lang(weblang)
|
||||
self.__check_environment()
|
||||
## do not forget the language!
|
||||
param_dict = {"weblang":weblang}
|
||||
## render "disks" plugin by default
|
||||
return self.return_plugin_action(self.pluginList.getPlugin("disks"))(**param_dict)
|
||||
return self.return_plugin_action(
|
||||
self.__plugin_manager.get_plugin("disks"))(**param_dict)
|
||||
|
||||
def newHTTPErrorHandler(self, errorCode, message):
|
||||
def new_http_error_handler(self, error_code, message):
|
||||
"""handle http errors gracefully
|
||||
|
||||
404 - not found errors: ignored if url is below /cryptobox-misc/
|
||||
|
@ -163,148 +215,164 @@ class WebInterfaceSites:
|
|||
500 - runtime errors: return "ok" exit code and show a polite excuse
|
||||
others: are there any other possible http errors?
|
||||
"""
|
||||
import traceback, sys
|
||||
import traceback
|
||||
## we ignore uninteresting not-found errors
|
||||
if (errorCode == 404) and \
|
||||
if (error_code == 404) and \
|
||||
(cherrypy.request.path.startswith("/cryptobox-misc/") or \
|
||||
cherrypy.request.path in ['/robots.txt','/favicon.ico']):
|
||||
cherrypy.response.status = errorCode
|
||||
cherrypy.response.status = error_code
|
||||
return
|
||||
## an invalid action was requested
|
||||
if errorCode == 404:
|
||||
if error_code == 404:
|
||||
## we send a not-found error (with the usual interface)
|
||||
cherrypy.response.status = errorCode
|
||||
self.dataset["Data.Warning"] = "InvalidAction"
|
||||
cherrypy.response.status = error_code
|
||||
self.__dataset["Data.Warning"] = "InvalidAction"
|
||||
cherrypy.response.body = self.__render("empty")
|
||||
return
|
||||
## are there still bugs in the code?
|
||||
if errorCode == 500:
|
||||
if error_code == 500:
|
||||
## we fix the error code (200 is "OK")
|
||||
cherrypy.response.status = 200
|
||||
self.cbox.log.error("HTTP-ERROR[500] - a runtime error occoured: %s" % str(message))
|
||||
self.cbox.log.error(
|
||||
"HTTP-ERROR[500] - runtime error: %s" % str(message))
|
||||
## add a traceback and exception information to the lo
|
||||
for a in traceback.format_exception(*sys.exc_info()):
|
||||
self.cbox.log.error("\t%s" % a)
|
||||
self.dataset["Data.Warning"] = "RuntimeError"
|
||||
for log_line in traceback.format_exception(*sys.exc_info()):
|
||||
self.cbox.log.error("\t%s" % log_line)
|
||||
self.__dataset["Data.Warning"] = "RuntimeError"
|
||||
cherrypy.response.body = self.__render("empty")
|
||||
return
|
||||
## unknown error type
|
||||
cherrypy.response.status = errorCode
|
||||
self.cbox.log.warn("HTTP-ERROR[%d] - an unknown error occoured: %s" % (errorCode, message))
|
||||
cherrypy.response.status = error_code
|
||||
self.cbox.log.warn("HTTP-ERROR[%d] - an unknown error occoured: %s" \
|
||||
% (error_code, message))
|
||||
cherrypy.response.body = self.__render("empty")
|
||||
|
||||
|
||||
def return_plugin_action(self, plugin):
|
||||
""" returns a function that is suitable for handling a cherrypy
|
||||
page request
|
||||
"""
|
||||
def handler(self, **args):
|
||||
self.__resetDataset()
|
||||
self.__checkEnvironment()
|
||||
args_orig = dict(args)
|
||||
"""this function handles a cherrypy page request
|
||||
"""
|
||||
self.__reset_dataset()
|
||||
self.__check_environment()
|
||||
## set web interface language
|
||||
try:
|
||||
self.__setWebLang(args["weblang"])
|
||||
self.__set_web_lang(args["weblang"])
|
||||
del args["weblang"]
|
||||
except KeyError:
|
||||
self.__setWebLang("")
|
||||
## we always read the "device" setting - otherwise volume-plugin links
|
||||
## would not work easily (see "volume_props" linking to "volume_format_fs")
|
||||
self.__set_web_lang("")
|
||||
## we always read the "device" setting - otherwise volume-plugin
|
||||
## links would not work easily
|
||||
## (see "volume_props" linking to "volume_format_fs")
|
||||
## it will get ignored for non-volume plugins
|
||||
try:
|
||||
plugin.device = None
|
||||
if self.__setDevice(args["device"]):
|
||||
if self.__set_device(args["device"]):
|
||||
plugin.device = args["device"]
|
||||
del args["device"]
|
||||
except KeyError:
|
||||
pass
|
||||
plugin.device = None
|
||||
## check the device argument of volume plugins
|
||||
if "volume" in plugin.pluginCapabilities:
|
||||
if "volume" in plugin.plugin_capabilities:
|
||||
## initialize the dataset of the selected device if necessary
|
||||
if plugin.device:
|
||||
self.dataset.setCurrentDiskState(plugin.device)
|
||||
self.__dataset.set_current_disk_state(plugin.device)
|
||||
else:
|
||||
## invalid (or missing) device setting
|
||||
return self.__render(self.defaultTemplate)
|
||||
## check if there is a "redirect" setting - this will override the return
|
||||
## value of the doAction function (e.g. useful for umount-before-format)
|
||||
## check if there is a "redirect" setting - this will override
|
||||
## the return value of the do_action function
|
||||
## (e.g. useful for umount-before-format)
|
||||
try:
|
||||
if args["redirect"]:
|
||||
override_nextTemplate = { "plugin":args["redirect"] }
|
||||
if "volume" in plugin.pluginCapabilities:
|
||||
override_nextTemplate["values"] = {"device":plugin.device}
|
||||
override_next_template = { "plugin":args["redirect"] }
|
||||
if "volume" in plugin.plugin_capabilities:
|
||||
override_next_template["values"] = {"device":plugin.device}
|
||||
del args["redirect"]
|
||||
except KeyError:
|
||||
override_nextTemplate = None
|
||||
override_next_template = None
|
||||
## check for information to be kept after the last call
|
||||
try:
|
||||
keep_values = args["message_keep"]
|
||||
del args["message_keep"]
|
||||
for key, value in keep_values["dataset"].items():
|
||||
self.dataset[key] = value
|
||||
self.__dataset[key] = value
|
||||
except KeyError:
|
||||
keep_values = None
|
||||
## call the plugin handler
|
||||
nextTemplate = plugin.doAction(**args)
|
||||
next_template = plugin.do_action(**args)
|
||||
## for 'volume' plugins: reread the dataset of the current disk
|
||||
## additionally: set the default template for plugins
|
||||
if "volume" in plugin.pluginCapabilities:
|
||||
if "volume" in plugin.plugin_capabilities:
|
||||
## maybe the state of the current volume was changed?
|
||||
self.dataset.setCurrentDiskState(plugin.device)
|
||||
if not nextTemplate: nextTemplate = { "plugin":"volume_mount", "values":{"device":plugin.device}}
|
||||
self.__dataset.set_current_disk_state(plugin.device)
|
||||
if not next_template:
|
||||
next_template = { "plugin":"volume_mount",
|
||||
"values":{"device":plugin.device}}
|
||||
else:
|
||||
## maybe a non-volume plugin changed some plugin settings (e.g. plugin_manager)
|
||||
self.dataset.setPluginData()
|
||||
## update the container hdf-dataset (maybe a plugin changed the state of a container)
|
||||
self.dataset.setContainersState()
|
||||
## some non-volume plugins change the internal state of other
|
||||
## plugins - e.g.: plugin_manager
|
||||
self.__dataset.set_plugin_data()
|
||||
## some non-volume plugins may change the state of containers
|
||||
self.__dataset.set_containers_state()
|
||||
## default page for non-volume plugins is the disk selection
|
||||
if not nextTemplate: nextTemplate = { "plugin":"disks", "values":{} }
|
||||
if not next_template:
|
||||
next_template = { "plugin":"disks", "values":{} }
|
||||
## was a redirect requested?
|
||||
if override_nextTemplate:
|
||||
nextTemplate = override_nextTemplate
|
||||
## if another plugins was choosen for 'nextTemplate', then do it!
|
||||
if isinstance(nextTemplate, types.DictType) \
|
||||
and "plugin" in nextTemplate.keys() \
|
||||
and "values" in nextTemplate.keys() \
|
||||
and self.pluginList.getPlugin(nextTemplate["plugin"]):
|
||||
valueDict = dict(nextTemplate["values"])
|
||||
if override_next_template:
|
||||
next_template = override_next_template
|
||||
## if another plugins was choosen for 'next_template', then do it!
|
||||
if isinstance(next_template, dict) \
|
||||
and "plugin" in next_template.keys() \
|
||||
and "values" in next_template.keys() \
|
||||
and self.__plugin_manager.get_plugin(next_template["plugin"]):
|
||||
value_dict = dict(next_template["values"])
|
||||
## force the current weblang attribute - otherwise it gets lost
|
||||
valueDict["weblang"] = self.dataset["Settings.Language"]
|
||||
value_dict["weblang"] = self.__dataset["Settings.Language"]
|
||||
## check for warnings/success messages, that should be kept
|
||||
if "Data.Warning" in plugin.hdf.keys() \
|
||||
or "Data.Success" in plugin.hdf.keys():
|
||||
self.cbox.log.info("keep warning message")
|
||||
valueDict["message_keep"] = { "plugin":plugin, "dataset":{}}
|
||||
if "Data.Success" in plugin.hdf.keys() \
|
||||
or "Data.Warning" in plugin.hdf.keys():
|
||||
value_dict["message_keep"] = {"plugin":plugin, "dataset":{}}
|
||||
for keep_key in ("Data.Warning", "Data.Success"):
|
||||
if keep_key in plugin.hdf.keys():
|
||||
valueDict["message_keep"]["dataset"][keep_key] = plugin.hdf[keep_key]
|
||||
new_plugin = self.pluginList.getPlugin(nextTemplate["plugin"])
|
||||
return self.return_plugin_action(new_plugin)(**valueDict)
|
||||
self.cbox.log.info("keeping message: %s" % \
|
||||
plugin.hdf[keep_key])
|
||||
value_dict["message_keep"]["dataset"][keep_key] = \
|
||||
plugin.hdf[keep_key]
|
||||
new_plugin = self.__plugin_manager.get_plugin(next_template["plugin"])
|
||||
return self.return_plugin_action(new_plugin)(**value_dict)
|
||||
## save the currently active plugin name
|
||||
self.dataset["Data.ActivePlugin"] = plugin.getName()
|
||||
return self.__render(nextTemplate, plugin)
|
||||
self.__dataset["Data.ActivePlugin"] = plugin.get_name()
|
||||
return self.__render(next_template, plugin)
|
||||
## apply authentication?
|
||||
if plugin.isAuthRequired():
|
||||
return lambda **args: self.__requestAuth()(handler)(self, **args)
|
||||
if plugin.is_auth_required():
|
||||
return lambda **args: self.__request_auth()(handler)(self, **args)
|
||||
else:
|
||||
return lambda **args: handler(self, **args)
|
||||
|
||||
|
||||
## test authentication
|
||||
@cherrypy.expose
|
||||
@__requestAuth
|
||||
@__request_auth
|
||||
def test(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
self.__checkEnvironment()
|
||||
"""test authentication - this function may be safely removed
|
||||
"""
|
||||
self.__reset_dataset()
|
||||
self.__set_web_lang(weblang)
|
||||
self.__check_environment()
|
||||
return "test passed"
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def test_stream(self):
|
||||
"""just for testing purposes - to check if the "stream_response" feature
|
||||
actually works - for now (September 02006) it does not seem to be ok"""
|
||||
actually works - for now (September 02006) it does not seem to be ok
|
||||
"""
|
||||
import time
|
||||
yield "<html><head><title>neu</title></head><body><p><ul>"
|
||||
for a in range(10):
|
||||
yield "<li>yes: %d - %s</li>" % (a, str(time.time()))
|
||||
for num in range(10):
|
||||
yield "<li>yes: %d - %s</li>" % (num, str(time.time()))
|
||||
time.sleep(1)
|
||||
yield "</ul></p></html>"
|
||||
|
||||
|
@ -312,69 +380,77 @@ class WebInterfaceSites:
|
|||
|
||||
##################### input checker ##########################
|
||||
|
||||
def __checkEnvironment(self):
|
||||
"""here we should place all interesting checks to inform the user of problems
|
||||
def __check_environment(self):
|
||||
"""inform the user of suspicious environmental problems
|
||||
|
||||
examples are: non-https, readonly-config, ...
|
||||
"""
|
||||
## this check is done _after_ "resetDataSet" -> a possible config partition was
|
||||
## loaded before
|
||||
if self.cbox.prefs.requiresPartition() and not self.cbox.prefs.getActivePartition():
|
||||
self.dataset["Data.EnvironmentWarning"] = "ReadOnlyConfig"
|
||||
# TODO: turn this on soon (add "not") - for now it is annoying
|
||||
if self.__checkHTTPS():
|
||||
self.dataset["Data.EnvironmentWarning"] = "NoSSL"
|
||||
## this check is done _after_ "reset_dataset" -> if there is
|
||||
## a config partition, then it was loaded before
|
||||
if self.cbox.prefs.requires_partition() \
|
||||
and not self.cbox.prefs.get_active_partition():
|
||||
self.__dataset["Data.EnvironmentWarning"] = "ReadOnlyConfig"
|
||||
#TODO: turn this on soon (add "not") - for now it is annoying
|
||||
if self.__check_https():
|
||||
self.__dataset["Data.EnvironmentWarning"] = "NoSSL"
|
||||
|
||||
|
||||
def __checkHTTPS(self):
|
||||
## check the request scheme
|
||||
if cherrypy.request.scheme == "https": return True
|
||||
def __check_https(self):
|
||||
"""check the request scheme
|
||||
"""
|
||||
if cherrypy.request.scheme == "https":
|
||||
return True
|
||||
## check an environment setting - this is quite common behind proxies
|
||||
try:
|
||||
if os.environ["HTTPS"]: return True
|
||||
if os.environ["HTTPS"]:
|
||||
return True
|
||||
except KeyError:
|
||||
pass
|
||||
## check http header TODO (check pound for the name)
|
||||
try:
|
||||
if cherrypy.request.headers["TODO"]: return True
|
||||
except KeyError:
|
||||
pass
|
||||
## the connection seems to be unencrypted
|
||||
return False
|
||||
## check http header for ssl information
|
||||
#TODO: (check pound for the name)
|
||||
try:
|
||||
if cherrypy.request.headers["XXX"]:
|
||||
return True
|
||||
except KeyError:
|
||||
## the connection seems to be unencrypted
|
||||
return False
|
||||
|
||||
|
||||
def __setWebLang(self, value):
|
||||
"""set the preferred priority of languages according to the following order:
|
||||
def __set_web_lang(self, value):
|
||||
"""set the preferred priority of languages according to this order:
|
||||
1. language selected via web interface
|
||||
2. preferred browser language setting
|
||||
3. languages defined in the config file
|
||||
"""
|
||||
## start with the configured language order
|
||||
langOrder = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||
self.cbox.log.debug("updating language preferences (default: %s)" % str(langOrder))
|
||||
lang_order = self.cbox.prefs["WebSettings"]["Languages"][:]
|
||||
self.cbox.log.debug(
|
||||
"updating language preferences (default: %s)" % str(lang_order))
|
||||
## put the preferred browser language in front
|
||||
guess = self.__getPreferredBrowserLanguage(langOrder)
|
||||
guess = self.__get_browser_language(lang_order)
|
||||
if guess:
|
||||
langOrder.remove(guess)
|
||||
langOrder.insert(0,guess)
|
||||
self.cbox.log.debug("raised priority of preferred browser language: %s" % guess)
|
||||
lang_order.remove(guess)
|
||||
lang_order.insert(0, guess)
|
||||
self.cbox.log.debug(
|
||||
"raised priority of preferred browser language: %s" % guess)
|
||||
## is the chosen language (via web interface) valid? - put it in front
|
||||
if value and (value in langOrder) and (not re.search(u'\W',value)):
|
||||
langOrder.remove(value)
|
||||
langOrder.insert(0,value)
|
||||
self.cbox.log.debug("raised priority of selected language: %s" % value)
|
||||
if value and (value in lang_order) and (not re.search(u'\W', value)):
|
||||
lang_order.remove(value)
|
||||
lang_order.insert(0, value)
|
||||
self.cbox.log.debug(
|
||||
"raised priority of selected language: %s" % value)
|
||||
elif value:
|
||||
self.cbox.log.info("invalid language selected: %s" % value)
|
||||
## store current language setting
|
||||
self.cbox.log.debug("current language preference: %s" % str(langOrder))
|
||||
self.langOrder = langOrder
|
||||
self.dataset["Settings.Language"] = langOrder[0]
|
||||
self.dataset["Settings.LinkAttrs.weblang"] = langOrder[0]
|
||||
self.cbox.log.debug(
|
||||
"current language preference: %s" % str(lang_order))
|
||||
self.lang_order = lang_order
|
||||
self.__dataset["Settings.Language"] = lang_order[0]
|
||||
self.__dataset["Settings.LinkAttrs.weblang"] = lang_order[0]
|
||||
|
||||
|
||||
def __getPreferredBrowserLanguage(self, availLangs):
|
||||
def __get_browser_language(self, avail_langs):
|
||||
"""guess the preferred language of the user (as sent by the browser)
|
||||
take the first language, that is part of 'availLangs'
|
||||
take the first language, that is part of 'avail_langs'
|
||||
"""
|
||||
try:
|
||||
pref_lang_header = cherrypy.request.headers["Accept-Language"]
|
||||
|
@ -382,56 +458,64 @@ class WebInterfaceSites:
|
|||
## no language header was specified
|
||||
return None
|
||||
## this could be a typical 'Accept-Language' header:
|
||||
## de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
|
||||
## de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
|
||||
regex = re.compile(u"\w+(-\w+)?(;q=[\d\.]+)?$")
|
||||
pref_langs = [e.split(";",1)[0]
|
||||
pref_langs = [e.split(";", 1)[0]
|
||||
for e in pref_lang_header.split(",")
|
||||
if regex.match(e)]
|
||||
## is one of these preferred languages available?
|
||||
for lang in pref_langs:
|
||||
if lang in availLangs: return lang
|
||||
if lang in avail_langs:
|
||||
return lang
|
||||
## we try to be nice: also look for "de" if "de-de" was specified ...
|
||||
for lang in pref_langs:
|
||||
## use only the first part of the language
|
||||
short_lang = lang.split("-",1)[0]
|
||||
if short_lang in availLangs: return short_lang
|
||||
short_lang = lang.split("-", 1)[0]
|
||||
if short_lang in avail_langs:
|
||||
return short_lang
|
||||
## we give up
|
||||
return None
|
||||
|
||||
|
||||
def __setDevice(self, device):
|
||||
def __set_device(self, device):
|
||||
"""check a device name that was chosen via the web interface
|
||||
issue a warning if the device is invalid"""
|
||||
if device and re.match(u'[\w /\-]+$', device) and self.cbox.getContainer(device):
|
||||
self.log.debug("select device: %s" % device)
|
||||
if device and re.match(u'[\w /\-]+$', device) \
|
||||
and self.cbox.get_container(device):
|
||||
self.cbox.log.debug("select device: %s" % device)
|
||||
return True
|
||||
else:
|
||||
self.log.warn("invalid device: %s" % device)
|
||||
self.dataset["Data.Warning"] = "InvalidDevice"
|
||||
self.cbox.log.warn("invalid device: %s" % device)
|
||||
self.__dataset["Data.Warning"] = "InvalidDevice"
|
||||
return False
|
||||
|
||||
|
||||
def __substituteGettext(self, languages, textDomain, hdf):
|
||||
def __substitute_gettext(self, languages, text_domain, hdf):
|
||||
"""substitute all texts in the hdf dataset with their translated
|
||||
counterparts as returned by gettext
|
||||
"""
|
||||
import gettext
|
||||
try:
|
||||
translator = gettext.translation(textDomain, languages=languages)
|
||||
except IOError, errMsg:
|
||||
translator = gettext.translation(text_domain, languages=languages)
|
||||
except IOError, err_msg:
|
||||
## no translation found
|
||||
self.cbox.log.warn("unable to load language file: %s" % errMsg)
|
||||
self.cbox.log.warn("unable to load language file: %s" % err_msg)
|
||||
return hdf
|
||||
def walk_tree(hdf_node):
|
||||
"""iterate through all nodes"""
|
||||
def translate_node(node):
|
||||
for (key,value) in node.attrs():
|
||||
if key == 'LINK': return
|
||||
"""turn one single string into unicode"""
|
||||
for (key, value) in node.attrs():
|
||||
if key == "LINK":
|
||||
return
|
||||
try:
|
||||
node.setValue("",translator.ugettext(node.value()))
|
||||
except UnicodeEncodeError, errMsg:
|
||||
self.cbox.log.info("Failed unicode encoding for gettext: %s - %s" % (node.value(),errMsg))
|
||||
node.setValue("", translator.ugettext(node.value()))
|
||||
except UnicodeEncodeError, err_msg:
|
||||
self.cbox.log.info(
|
||||
"Failed unicode encoding for gettext: %s - %s" \
|
||||
% (node.value(),err_msg))
|
||||
## fallback to default encoding
|
||||
node.setValue("",translator.gettext(node.value()))
|
||||
node.setValue("", translator.gettext(node.value()))
|
||||
while hdf_node:
|
||||
translate_node(hdf_node)
|
||||
walk_tree(hdf_node.child())
|
||||
|
@ -439,86 +523,95 @@ class WebInterfaceSites:
|
|||
walk_tree(hdf)
|
||||
|
||||
|
||||
def __getLanguageData(self):
|
||||
def __get_language_data(self):
|
||||
"""return the hdf dataset of the main interface and all plugins
|
||||
translations are done according to self.langOrder
|
||||
translations are done according to self.lang_order
|
||||
"""
|
||||
## check if the language setting was changed - use cached data if possible
|
||||
try:
|
||||
if self.cachedLanguageData["langOrder"] == self.langOrder:
|
||||
self.cbox.log.debug("using cached language data: %s" % str(self.langOrder))
|
||||
return self.cachedLanguageData["hdf"]
|
||||
except AttributeError:
|
||||
pass
|
||||
## check if the language setting has changed - use cache if possible
|
||||
if self.__cached_language_data and \
|
||||
self.__cached_language_data["lang_order"] == self.lang_order:
|
||||
self.cbox.log.debug(
|
||||
"using cached language data: %s" % str(self.lang_order))
|
||||
return self.__cached_language_data["hdf"]
|
||||
self.cbox.log.debug("generating language data")
|
||||
hdf = neo_util.HDF()
|
||||
hdf.readFile(os.path.join(self.prefs["Locations"]["TemplateDir"],"language.hdf"))
|
||||
self.__substituteGettext(self.langOrder, GETTEXT_DOMAIN, hdf)
|
||||
hdf.readFile(os.path.join(
|
||||
self.cbox.prefs["Locations"]["TemplateDir"],"language.hdf"))
|
||||
self.__substitute_gettext(self.lang_order, GETTEXT_DOMAIN, hdf)
|
||||
## load the language data of all plugins
|
||||
for p in self.pluginList.getPlugins():
|
||||
pl_lang = p.getLanguageData()
|
||||
self.__substituteGettext(self.langOrder, "%s-feature-%s" % (GETTEXT_DOMAIN, p.getName()), pl_lang)
|
||||
hdf.copy("Plugins.%s" % p.getName(), pl_lang)
|
||||
self.cbox.log.debug("language data for plugin loaded: %s" % p.getName())
|
||||
for plugin in self.__plugin_manager.get_plugins():
|
||||
pl_lang = plugin.get_language_data()
|
||||
self.__substitute_gettext(self.lang_order, "%s-feature-%s" % \
|
||||
(GETTEXT_DOMAIN, plugin.get_name()), pl_lang)
|
||||
hdf.copy("Plugins.%s" % plugin.get_name(), pl_lang)
|
||||
self.cbox.log.debug(
|
||||
"language data for plugin loaded: %s" % plugin.get_name())
|
||||
## cache result for later retrieval
|
||||
self.cachedLanguageData = {"langOrder": self.langOrder, "hdf": hdf}
|
||||
self.__cached_language_data = \
|
||||
{"lang_order": self.lang_order, "hdf": hdf}
|
||||
return hdf
|
||||
|
||||
|
||||
def __render(self, renderInfo, plugin=None):
|
||||
def __render(self, render_info, plugin=None):
|
||||
'''renders from clearsilver templates and returns the resulting html
|
||||
'''
|
||||
## is renderInfo a string (filename of the template) or a dictionary?
|
||||
if type(renderInfo) == types.DictType:
|
||||
template = renderInfo["template"]
|
||||
if renderInfo.has_key("generator"):
|
||||
generator = renderInfo["generator"]
|
||||
## is render_info a string (filename of the template) or a dictionary?
|
||||
if isinstance(render_info, dict):
|
||||
template = render_info["template"]
|
||||
if render_info.has_key("generator"):
|
||||
generator = render_info["generator"]
|
||||
else:
|
||||
generator = None
|
||||
else:
|
||||
(template, generator) = (renderInfo, None)
|
||||
(template, generator) = (render_info, None)
|
||||
|
||||
## load the language data
|
||||
hdf = neo_util.HDF()
|
||||
hdf.copy("Lang", self.__getLanguageData())
|
||||
hdf.copy("Lang", self.__get_language_data())
|
||||
|
||||
## first: assume, that the template file is in the global template directory
|
||||
self.dataset["Settings.TemplateFile"] = os.path.abspath(os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs"))
|
||||
## first: assume, that the template file is in the global
|
||||
## template directory
|
||||
self.__dataset["Settings.TemplateFile"] = os.path.abspath(os.path.join(
|
||||
self.cbox.prefs["Locations"]["TemplateDir"],
|
||||
template + ".cs"))
|
||||
|
||||
if plugin:
|
||||
## check, if the plugin provides the template file -> overriding
|
||||
plugin_cs_file = plugin.getTemplateFileName(template)
|
||||
plugin_cs_file = plugin.get_template_filename(template)
|
||||
if plugin_cs_file:
|
||||
self.dataset["Settings.TemplateFile"] = plugin_cs_file
|
||||
self.__dataset["Settings.TemplateFile"] = plugin_cs_file
|
||||
|
||||
## add the current state of the plugins to the hdf dataset
|
||||
self.dataset["Data.Status.Plugins.%s" % plugin.getName()] = plugin.getStatus()
|
||||
self.__dataset["Data.Status.Plugins.%s" % plugin.get_name()] = \
|
||||
plugin.get_status()
|
||||
## load the dataset of the plugin
|
||||
plugin.loadDataSet(hdf)
|
||||
plugin.load_dataset(hdf)
|
||||
|
||||
self.log.info("rendering site: " + template)
|
||||
self.cbox.log.info("rendering site: " + template)
|
||||
|
||||
cs_path = os.path.abspath(os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs"))
|
||||
cs_path = os.path.abspath(os.path.join(
|
||||
self.cbox.prefs["Locations"]["TemplateDir"], "main.cs"))
|
||||
if not os.access(cs_path, os.R_OK):
|
||||
log.error("Couldn't read clearsilver file: %s" % cs_path)
|
||||
self.cbox.log.error(
|
||||
"Couldn't read clearsilver file: %s" % cs_path)
|
||||
yield "Couldn't read clearsilver file: %s" % cs_path
|
||||
return
|
||||
|
||||
self.log.debug(self.dataset)
|
||||
for key in self.dataset.keys():
|
||||
hdf.setValue(key,str(self.dataset[key]))
|
||||
cs = neo_cs.CS(hdf)
|
||||
cs.parseFile(cs_path)
|
||||
self.cbox.log.debug(self.__dataset)
|
||||
for key in self.__dataset.keys():
|
||||
hdf.setValue(key, str(self.__dataset[key]))
|
||||
cs_data = neo_cs.CS(hdf)
|
||||
cs_data.parseFile(cs_path)
|
||||
|
||||
## is there a generator containing additional information?
|
||||
if not generator:
|
||||
## all content in one flush
|
||||
yield cs.render()
|
||||
yield cs_data.render()
|
||||
else:
|
||||
content_generate = generator()
|
||||
dummy_line = """<!-- CONTENT_DUMMY -->"""
|
||||
## now we do it linewise - checking for the content marker
|
||||
for line in cs.render().splitlines():
|
||||
for line in cs_data.render().splitlines():
|
||||
if line.find(dummy_line) != -1:
|
||||
yield line.replace(dummy_line, content_generate.next())
|
||||
else:
|
||||
|
|
|
@ -24,6 +24,8 @@ super class of all web interface unittests for the cryptobox
|
|||
just inherit this class and add some test functions
|
||||
"""
|
||||
|
||||
__revision__ = "$Id"
|
||||
|
||||
import unittest
|
||||
import twill
|
||||
import cherrypy
|
||||
|
@ -34,10 +36,12 @@ import os
|
|||
## we do the following, for easy surfing
|
||||
## e.g. use: cbx.go(your_url)
|
||||
## commands api: http://twill.idyll.org/commands.html
|
||||
CBXHOST="localhost"
|
||||
CBXPORT=8081
|
||||
CBX_URL="http://%s:%d/" % (CBXHOST, CBXPORT)
|
||||
LOG_FILE="/tmp/twill.log"
|
||||
CBXHOST = "localhost"
|
||||
CBXPORT = 8081
|
||||
CBX_URL = "http://%s:%d/" % (CBXHOST, CBXPORT)
|
||||
LOG_FILE = "/tmp/cryptobox-twill.log"
|
||||
WEBLOG_FILE = "/tmp/cryptobox-cherrypy.log"
|
||||
|
||||
|
||||
class WebInterfaceTestClass(unittest.TestCase):
|
||||
'''this class checks the webserver, using "twill"
|
||||
|
@ -62,9 +66,12 @@ class WebInterfaceTestClass(unittest.TestCase):
|
|||
'server.logToScreen' : False,
|
||||
'autoreload.on': False,
|
||||
'server.threadPool': 1,
|
||||
'server.environment': 'production',
|
||||
'server.environment': 'development',
|
||||
'server.log_tracebacks': True,
|
||||
'server.log_file': WEBLOG_FILE,
|
||||
})
|
||||
cherrypy.root = cryptobox.web.sites.WebInterfaceSites("cryptobox-unittests.conf")
|
||||
cherrypy.root = cryptobox.web.sites.WebInterfaceSites(
|
||||
"cryptobox-unittests.conf")
|
||||
cherrypy.server.start(initOnly=True, serverClass=None)
|
||||
|
||||
from cherrypy._cpwsgi import wsgiApp
|
||||
|
@ -74,19 +81,13 @@ class WebInterfaceTestClass(unittest.TestCase):
|
|||
self.output = open(LOG_FILE,"a")
|
||||
twill.set_output(self.output)
|
||||
self.cmd = twill.commands
|
||||
self.URL = CBX_URL
|
||||
self.url = CBX_URL
|
||||
self.cbox = cherrypy.root.cbox
|
||||
self.globals, self.locals = twill.namespaces.get_twill_glocals()
|
||||
## search for a usable block device
|
||||
## use /dev/ubd? if possible - otherwise /dev/hd?
|
||||
## so it will be possible to use these tests inside of an uml
|
||||
for d in ["ubdb", "loop", "ubda", "udbc", "ubdd", "hdb", "hda", "hdc", "hdd"]:
|
||||
if os.path.exists("/dev/%s1" % d):
|
||||
device = d
|
||||
break
|
||||
else:
|
||||
device = "hda"
|
||||
self.device = device
|
||||
self.blockdevice, self.device = self.__find_test_device()
|
||||
|
||||
|
||||
|
||||
|
@ -103,6 +104,34 @@ class WebInterfaceTestClass(unittest.TestCase):
|
|||
browser = twill.commands.get_browser()
|
||||
soup = BeautifulSoup(browser.get_html())
|
||||
return soup
|
||||
|
||||
|
||||
def __find_test_device(self):
|
||||
"""Search for a valid test device - the data will get lost ...
|
||||
"""
|
||||
for dev in ["ubdb", "loop", "ubda", "udbc", "ubdd"]:
|
||||
if os.path.exists("/dev/%s1" % dev) \
|
||||
and not self.__is_config_partition("/dev/%s1" % dev):
|
||||
return (dev, dev + "1")
|
||||
if os.path.exists("/dev/%s2" % dev) \
|
||||
and not self.__is_config_partition("/dev/%s2" % dev):
|
||||
return (dev, dev + "2")
|
||||
else:
|
||||
raise Exception, "no valid device for testing found"
|
||||
|
||||
|
||||
def __is_config_partition(self, device):
|
||||
"""Check if the device is a configuration partition.
|
||||
"""
|
||||
import subprocess
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [ '/sbin/e2label',
|
||||
device ])
|
||||
(stdout, stderr) = proc.communicate()
|
||||
return stdout.strip() == "cbox_config"
|
||||
|
||||
|
||||
def register_auth(self, url, user="admin", password="admin"):
|
||||
|
|
44
src/pylintrc
Normal file
44
src/pylintrc
Normal file
|
@ -0,0 +1,44 @@
|
|||
# this is a local configuration file for pylint to be used for checking the
|
||||
# quality of the CryptoBox code
|
||||
#
|
||||
# just run:
|
||||
# bin/do_pylint.sh cryptobox.core.main
|
||||
# to check the module cryptobox.core.main
|
||||
|
||||
|
||||
[MASTER]
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=CVS
|
||||
ignore=.svn
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
required-attributes=__revision__
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=88
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string='\t'
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
Loading…
Reference in a new issue