diff --git a/README.samba b/README.samba index 7c926f8..7921200 100644 --- a/README.samba +++ b/README.samba @@ -19,7 +19,6 @@ Reload the new samba configuration by calling: invoke-rc.d samba reload - B) one share for each volume Copy the example event script /usr/share/doc/cryptobox-server/event-script/samba @@ -27,14 +26,5 @@ to /etc/cryptobox-server/events.d/samba. This event handler will add and remove shares whenever a volume is mounted or unmounted via the CryptoBox webinterface. Add the following line to your /etc/samba/smb.conf: - include = /var/cache/cryptobox-server/samba-include.conf - -Create this file: - touch /var/cache/cryptobox-server/samba-include.conf - -Chown it to the cryptobox user: - chown cryptobox /var/cache/cryptobox-server/samba-include.conf - -Reload the new samba configuration by calling: - invoke-rc.d samba reload + include = /var/cache/cryptobox-server/settings/misc/samba-include.conf diff --git a/bin/CryptoBoxWebserver b/bin/CryptoBoxWebserver index 71aa763..ef53f35 100755 --- a/bin/CryptoBoxWebserver +++ b/bin/CryptoBoxWebserver @@ -106,10 +106,24 @@ class CryptoBoxWebserver: "staticFilter.file": os.path.realpath(os.path.join(opts.datadir, 'favicon.ico'))} }) - + self.define_exit_handlers(cherrypy.root) + + + def define_exit_handlers(self, cbw): + import atexit + import signal + atexit.register(cbw.cleanup) + def kill_signal_handler(signum, frame): + cbw.cbox.log.info("Kill signal handler called: %d" % signum) + sys.exit(1) + signal.signal(signal.SIGTERM, kill_signal_handler) + + def start(self): cherrypy.server.start() + + def fork_to_background(): ## this is just copy'n'pasted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731 @@ -221,6 +235,8 @@ def parseOptions(): if __name__ == "__main__": ## process arguments options = parseOptions() + ## set umask to 022 (aka 755) - octal value + os.umask(022) ## run the webserver as a daemon process if options.background: fork_to_background() ## write pid file diff --git a/bin/cryptobox-unittests.conf b/bin/cryptobox-unittests.conf index 12f7da3..5fb60de 100644 --- a/bin/cryptobox-unittests.conf +++ b/bin/cryptobox-unittests.conf @@ -76,7 +76,8 @@ Languages = en, de, sl, fr [Programs] cryptsetup = /sbin/cryptsetup -mkfs-data = /sbin/mkfs.ext3 +mkfs = /sbin/mkfs +nice = /usr/bin/nice blkid = /sbin/blkid blockdev = /sbin/blockdev mount = /bin/mount diff --git a/bin/cryptobox.conf b/bin/cryptobox.conf index 1ec5435..092cb2e 100644 --- a/bin/cryptobox.conf +++ b/bin/cryptobox.conf @@ -64,6 +64,7 @@ Destination = file # syslog: $LOG_FACILITY #Details = /var/log/cryptobox.log Details = ./cryptobox.log +#Details = SYSLOG [WebSettings] diff --git a/bin/uml-setup.sh b/bin/uml-setup.sh index 77c150f..c011d72 100755 --- a/bin/uml-setup.sh +++ b/bin/uml-setup.sh @@ -27,5 +27,6 @@ if [ ! -e "$TEST_IMG" ] dd if=/dev/zero of="$TEST_IMG" bs=1M count=$TEST_SIZE fi -linux ubd0="$ROOT_IMG" ubd1="$TEST_IMG" con=xterm hostfs=$PROJ_DIR fakehd eth0=daemon mem=$MEM_SIZE +# "aio=2.4" is necessary, as otherwise sfdiks hangs at "nanosleep({3,0})" +linux ubd0="$ROOT_IMG" ubd1="$TEST_IMG" con=xterm hostfs=$PROJ_DIR fakehd eth0=daemon mem=$MEM_SIZE aio=2.4 diff --git a/conf-examples/apache2_dav.conf b/conf-examples/apache2_dav.conf index d2309b4..e1572ef 100644 --- a/conf-examples/apache2_dav.conf +++ b/conf-examples/apache2_dav.conf @@ -5,7 +5,7 @@ # include the dynamically managed configuration directory - IT MUST EXIST - Include /var/cache/cryptobox-server/settings/apache2_dav.conf.d/ + Include /var/cache/cryptobox-server/settings/misc/apache2_dav.conf.d/ # lock database - should be writeable for www-data DavLockDB /tmp/dav_lock.db # a longer value than the default (120) help for high-latency networks diff --git a/conf-examples/cryptobox.conf b/conf-examples/cryptobox.conf index a3d4872..6840ed4 100644 --- a/conf-examples/cryptobox.conf +++ b/conf-examples/cryptobox.conf @@ -49,14 +49,14 @@ EventDir = /etc/cryptobox-server/events.d Level = debug # where to write the log messages to? -# possible values are: file -# syslog support will be added later +# possible values are 'file' and 'syslog' Destination = file # depending on the choosen destination (see above) you may select # details. Possible values for the different destinations are: # file: $FILENAME -# syslog: $LOG_FACILITY +# syslog: KERN | USER | MAIL | DAEMON | AUTH | SYSLOG | LPR | NEWS | UUCP +# | CRON | AUTHPRIV | LOCAL0 .. LOCAL7 Details = /var/log/cryptobox-server/cryptobox.log @@ -71,7 +71,7 @@ Stylesheet = /cryptobox-misc/cryptobox.css # see /usr/share/locale for a list of possible language codes # if a translated string is not available, then the english original is displayed # available languages: cs, da, de, en, es, fi, fr, hu, it, ja, nl, pl, pt, ru, sl, sv -Languages = de, en, fr +Languages = de, en, fr, es, sl [Programs] diff --git a/conf-examples/samba-include.conf b/conf-examples/samba-include.conf deleted file mode 100644 index 9a1274c..0000000 --- a/conf-examples/samba-include.conf +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT REMOVE OR EDIT THIS FILE -# the file was automatically generated by the cryptobox package diff --git a/debian/changelog b/debian/changelog index 92c97e8..c694488 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +cryptobox (0.2.54-1) unstable; urgency=low + + * log plugin improved + * samba plugin fixed + * syslog support added + * improved output of 'logs' plugin + * finished 'volume_automount' plugin + + -- Lars Kruse Mon, 11 Dec 2006 11:52:38 +0100 + cryptobox (0.2.53-1) unstable; urgency=low * constant screen width diff --git a/debian/control b/debian/control index 558c52e..697a7b3 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Standards-Version: 3.7.2 Package: cryptobox-server Architecture: any Depends: ${python:Depends}, cryptsetup (>=20050111), e2fsprogs (>= 1.27), adduser, python (>=2.4), python-clearsilver, super, dosfstools, python-cherrypy, python-configobj -Suggests: samba, apache, stunnel +Suggests: samba, apache2, stunnel Replaces: cryptobox XB-Python-Version: ${python:Versions} Description: Web interface for an encrypting fileserver diff --git a/debian/cryptobox-server.postrm b/debian/cryptobox-server.postrm index fc2d7aa..b52cf3a 100644 --- a/debian/cryptobox-server.postrm +++ b/debian/cryptobox-server.postrm @@ -15,7 +15,7 @@ remove_super_lines() ## do nothing, if there is no CryptoBox line grep -q "CRYPTOBOX_MARKER" "$SUPER_FILE" || return 0 sed -i /CRYPTOBOX_MARKER/d "$SUPER_FILE" - sed -i /CryptoBoxRootActions/d "$SUPER_FILE" + sed -i /^CryptoBoxRootActions/d "$SUPER_FILE" } diff --git a/event-scripts/README b/event-scripts/README index 78737fe..c6f82ba 100644 --- a/event-scripts/README +++ b/event-scripts/README @@ -2,12 +2,13 @@ Event scripts for CryptoBox events If you want to execute specific actions according to changes of the cryptobox, then you can just add your own scripts to this directory. -For every supported event of the CryptoBox, all scripts are called with root user -permissions. +These scripts are called with root user permissions. The common synopsis for all event scripts is: SCRIPTNAME EVENT [[EVENT_INFOS]...] + +1) Possible events Supported events: premount|postmount|preumount|postumount: called before and after (u)mounting of a volume @@ -18,9 +19,17 @@ Supported events: - mount_dir: mountpoint of the volume +2) Preperation of event scripts Every event script has to fulfill the following conditions: - be executable (for the cryptobox user and for root) - be writeable for root only - its parent directories must be writeable for root only - the directory of the script must contain a file called '_event_scripts_' (to prevent abuse) + +3) Storing settings +If your custom event script needs to write information to a file, then it +should create this file below /var/cache/cryptobox-server/settings/misc/. +(adapt this directory to your setup, if you changed the default settings of +[Locations]->SettingsDir) + diff --git a/event-scripts/apache2_dav b/event-scripts/apache2_dav index 57118c1..2e8dd19 100755 --- a/event-scripts/apache2_dav +++ b/event-scripts/apache2_dav @@ -9,7 +9,7 @@ # (e.g. /etc/apache2/conf.d) # # -# Params: $event $volume_name $volume_type $mount_dir +# Params: $event $device $volume_name $volume_type $mount_dir # # event: premount | postmount | preumount | postumount # device: name of the device @@ -24,7 +24,7 @@ set -eu # adapt this part of the file to your setup APACHE_SCRIPT=/etc/init.d/apache2 -APACHE_CONF_DIR=/var/cache/cryptobox/apache2_dav.conf.d +APACHE_CONF_DIR=/var/cache/cryptobox/settings/misc/apache2_dav.conf.d # this apache config snippet is used for every published volume # _VOLUME_NAME_ and _SHARE_DIR_ are replaced by their actual values diff --git a/event-scripts/samba b/event-scripts/samba index 2b7aabd..9fe1612 100755 --- a/event-scripts/samba +++ b/event-scripts/samba @@ -7,10 +7,10 @@ # The following line _must_ be added to your /etc/samba/smb.conf: # include = /var/cache/cryptobox-server/samba-include.conf # and you should create this file and chown it to the cryptobox user: -# touch /var/cache/cryptobox-server/samba-include.conf +# touch /var/cache/cryptobox-server/settings/misc/samba-include.conf # # -# Params: $event $volume_name $volume_type $mount_dir +# Params: $event $device $volume_name $volume_type $mount_dir # # event: premount | postmount | preumount | postumount # device: name of the device @@ -25,17 +25,15 @@ set -eu # adapt this part of the file to your needs SAMBA_CONTROL=smbcontrol -SAMBA_CONF_DIR=/var/cache/cryptobox-server/samba.conf.d -MAIN_SAMBA_CONF_FILE=/var/cache/cryptobox-server/samba-include.conf +SAMBA_CONF_DIR=/var/cache/cryptobox-server/settings/misc/samba.conf.d +MAIN_SAMBA_CONF_FILE=/var/cache/cryptobox-server/settings/misc/samba-include.conf # this smb.conf snippet will get used for every published share # _VOLUME_NAME and _SHARE_DIR_ are replaced by their actual values -# TODO: improve the later parsing of _SHARE_DIR_ in update_include_conf_file -# for now it depends on non existing whitespaces around the dirname SAMBA_SHARE_TEMPLATE=$(cat - <<-"EOF" [_VOLUME_NAME_] comment = CryptoBox share - path =_SHARE_DIR_ + path = _SHARE_DIR_ read only = no guest ok = yes EOF @@ -71,7 +69,7 @@ update_include_conf_file() ( echo "# this file was automatically generated by the CryptoBox" echo "# DO NOT EDIT - all changes will get lost!" find "$SAMBA_CONF_DIR" -type f -name "*.conf" | while read fname - do mdir=$(cat "$fname" | grep "path.*=" | cut -f 2 -d "=") + do mdir=$(grep "path.*=" "$fname" | cut -f 2 -d "=" | sed 's/^[ \t]*//') # check if the mount directory still exists if test -d "$mdir" then echo "include = $fname" diff --git a/intl/sl/cryptobox-server.po b/intl/sl/cryptobox-server.po index 1696144..1113372 100644 --- a/intl/sl/cryptobox-server.po +++ b/intl/sl/cryptobox-server.po @@ -3,14 +3,14 @@ msgstr "" "Project-Id-Version: CryptoBox-Server 0.3\n" "Report-Msgid-Bugs-To: translate@cryptobox.org\n" "POT-Creation-Date: 2006-11-28 05:03+0100\n" -"PO-Revision-Date: 2006-11-30 08:49+0100\n" +"PO-Revision-Date: 2006-12-11 01:40+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" -"X-Generator: Translate Toolkit 0.10.1\n" +"X-Generator: Pootle 0.10.1\n" #: Name msgid "English" @@ -18,11 +18,11 @@ msgstr "" #: Title.Top msgid "The CryptoBox" -msgstr "Privatnost v vsako vas" +msgstr "" #: Title.Slogan msgid "Privacy for the rest of us." -msgstr "" +msgstr "Privatnost v vsako vas" #: Title.Volume msgid "Volume" diff --git a/plugins/date/date.py b/plugins/date/date.py index 789bcef..58eee83 100644 --- a/plugins/date/date.py +++ b/plugins/date/date.py @@ -47,22 +47,17 @@ class date(cryptobox.plugins.base.CryptoBoxPlugin): datetime.datetime(year, month, day, hour, minute) except ValueError: self.hdf["Data.Warning"] = "Plugins.date.InvalidDate" - self.__prepare_form_data() - return "form_date" - date = "%02d%02d%02d%02d%d" % (month, day, hour, minute, year) - if self.__set_date(date): - self.cbox.log.info("changed date to: %s" % date) - self.hdf["Data.Success"] = "Plugins.date.DateChanged" - return "form_date" else: - ## 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.__prepare_form_data() - return "form_date" - else: - self.__prepare_form_data() - return "form_date" + date = "%02d%02d%02d%02d%d" % (month, day, hour, minute, year) + if self.__set_date(date): + self.cbox.log.info("changed date to: %s" % date) + self.hdf["Data.Success"] = "Plugins.date.DateChanged" + else: + ## 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.__prepare_form_data() + return "form_date" def get_status(self): diff --git a/plugins/date/intl/sl/cryptobox-server-feature-date.po b/plugins/date/intl/sl/cryptobox-server-feature-date.po index ba38ae4..e00a01d 100644 --- a/plugins/date/intl/sl/cryptobox-server-feature-date.po +++ b/plugins/date/intl/sl/cryptobox-server-feature-date.po @@ -1,102 +1,101 @@ -#, fuzzy msgid "" msgstr "" "Project-Id-Version: CryptoBox-Server 0.3\n" "Report-Msgid-Bugs-To: translate@cryptobox.org\n" "POT-Creation-Date: 2006-11-28 05:04+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2006-12-09 17:00+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Translate Toolkit 0.10.1\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" +"X-Generator: Pootle 0.10.1\n" #: Name msgid "Change date and time" -msgstr "" +msgstr "Spremeni datum in čas" #: Link msgid "Set date/time" -msgstr "" +msgstr "Nastavi datum in čas" #: Title.ConfigDate msgid "Date and time setting" -msgstr "" +msgstr "Nastavitve datum/čas" #: Button.ConfigDate msgid "Set date and time" -msgstr "" +msgstr "Nastavi datum/čas" #: Text.Date msgid "Date" -msgstr "" +msgstr "Datum" #: Text.Time msgid "Time" -msgstr "" +msgstr "Čas" #: Text.Months.1 msgid "January" -msgstr "" +msgstr "Januar" #: Text.Months.2 msgid "February" -msgstr "" +msgstr "Februar" #: Text.Months.3 msgid "March" -msgstr "" +msgstr "Marec" #: Text.Months.4 msgid "April" -msgstr "" +msgstr "April" #: Text.Months.5 msgid "May" -msgstr "" +msgstr "Maj" #: Text.Months.6 msgid "June" -msgstr "" +msgstr "Junij" #: Text.Months.7 msgid "July" -msgstr "" +msgstr "Julij" #: Text.Months.8 msgid "August" -msgstr "" +msgstr "Avgust" #: Text.Months.9 msgid "September" -msgstr "" +msgstr "September" #: Text.Months.10 msgid "October" -msgstr "" +msgstr "Oktober" #: Text.Months.11 msgid "November" -msgstr "" +msgstr "November" #: Text.Months.12 msgid "December" -msgstr "" +msgstr "December" #: SuccessMessage.DateChanged.Title msgid "Date changed" -msgstr "" +msgstr "Datum je spremenjen" #: SuccessMessage.DateChanged.Text msgid "The date was changed successfully." -msgstr "" +msgstr "Datum je bil uspešno spremenjen" #: WarningMessage.InvalidDate.Title msgid "Invalid value" -msgstr "" +msgstr "Neveljavna vrednost" #: WarningMessage.InvalidDate.Text msgid "An invalid value for date or time was supplied. Please try again." -msgstr "" +msgstr "Nepravilen vnos datuma ali časa. Prosimo poskusite ponovno." diff --git a/plugins/date/root_action.py b/plugins/date/root_action.py index a0c2846..94592f9 100755 --- a/plugins/date/root_action.py +++ b/plugins/date/root_action.py @@ -45,7 +45,7 @@ if __name__ == "__main__": sys.stderr.write("%s: no argument supplied\n" % self_bin) sys.exit(1) - if re.search(u'\D', args[0]): + if re.search(r'\D', args[0]): sys.stderr.write("%s: illegal argument (%s)\n" % (self_bin, args[0])) sys.exit(1) diff --git a/plugins/disks/unittests.py b/plugins/disks/unittests.py index d8aa0d9..15149aa 100644 --- a/plugins/disks/unittests.py +++ b/plugins/disks/unittests.py @@ -36,7 +36,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): 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") + self.cmd.find(r'Data.Status.Plugins.disks=(.*)$', "m") devices = self.locals["__match__"].split(":") self.assertTrue(len(devices)>0) self.assertTrue("/dev/%s" % self.device in devices) diff --git a/plugins/help/help.py b/plugins/help/help.py index 6b4ce9b..fedd067 100644 --- a/plugins/help/help.py +++ b/plugins/help/help.py @@ -43,7 +43,7 @@ class help(cryptobox.plugins.base.CryptoBoxPlugin): 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 \ + not re.search(r'\W', page) and \ os.path.isfile(os.path.join(self.cbox.prefs["Locations"]["DocDir"], self.default_lang, page + '.html')): ## everything is ok diff --git a/plugins/help/intl/sl/cryptobox-server-feature-help.po b/plugins/help/intl/sl/cryptobox-server-feature-help.po index 591e6ea..363a534 100644 --- a/plugins/help/intl/sl/cryptobox-server-feature-help.po +++ b/plugins/help/intl/sl/cryptobox-server-feature-help.po @@ -1,22 +1,21 @@ -#, fuzzy msgid "" msgstr "" "Project-Id-Version: CryptoBox-Server 0.3\n" "Report-Msgid-Bugs-To: translate@cryptobox.org\n" "POT-Creation-Date: 2006-11-28 05:03+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2006-12-09 16:28+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Translate Toolkit 0.10.1\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" +"X-Generator: Pootle 0.10.1\n" #: Name msgid "User manual" -msgstr "" +msgstr "Uporabniški priročnik" #: Link msgid "Help" -msgstr "" +msgstr "Pomoč" diff --git a/plugins/help/unittests.py b/plugins/help/unittests.py index 0d9b46c..b876deb 100644 --- a/plugins/help/unittests.py +++ b/plugins/help/unittests.py @@ -89,6 +89,6 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): def _getHelpStatus(self): - self.cmd.find(u'Data.Status.Plugins.help=(.*)$', "m") + self.cmd.find(r'Data.Status.Plugins.help=(.*)$', "m") return tuple(self.locals["__match__"].split(":")) diff --git a/plugins/language_selection/intl/sl/cryptobox-server-feature-language_selection.po b/plugins/language_selection/intl/sl/cryptobox-server-feature-language_selection.po index fcbd19a..b766f7e 100644 --- a/plugins/language_selection/intl/sl/cryptobox-server-feature-language_selection.po +++ b/plugins/language_selection/intl/sl/cryptobox-server-feature-language_selection.po @@ -1,26 +1,25 @@ -#, fuzzy msgid "" msgstr "" "Project-Id-Version: CryptoBox-Server 0.3\n" "Report-Msgid-Bugs-To: translate@cryptobox.org\n" "POT-Creation-Date: 2006-11-28 05:03+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2006-12-09 16:33+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Translate Toolkit 0.10.1\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" +"X-Generator: Pootle 0.10.1\n" #: Name msgid "Choose interface language" -msgstr "" +msgstr "Izberite jezik" #: Link msgid "Languages" -msgstr "" +msgstr "Jezik" #: Title.Language msgid "Choose an interface language" -msgstr "" +msgstr "Izberite Jezik" diff --git a/plugins/language_selection/unittests.py b/plugins/language_selection/unittests.py index 1f06609..af63747 100644 --- a/plugins/language_selection/unittests.py +++ b/plugins/language_selection/unittests.py @@ -35,7 +35,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): url = self.url + "language_selection" self.register_auth(url) self.cmd.go(url) - self.cmd.find(u'Data.Status.Plugins.language_selection=(.*)$', "m") + self.cmd.find(r'Data.Status.Plugins.language_selection=(.*)$', "m") langs = self.locals["__match__"].split(":") self.assertTrue(len(langs)>1) self.assertTrue(langs[0] == "en") diff --git a/plugins/logs/language.hdf b/plugins/logs/language.hdf index d186a82..b186acf 100644 --- a/plugins/logs/language.hdf +++ b/plugins/logs/language.hdf @@ -1,10 +1,23 @@ -Name = Show the content of the log file -Link = Show log file +Name = Show event log +Link = Event log -Title.Log = CryptoBox logfiles +Title.Log = CryptoBox event log Text { - EmptyLog = The logfile of the CryptoBox is empty. - Refresh = Refresh + ShowAll = Show all messages + AtLeastWarnings = Show warnings and errors + OnlyErrors = Show errors only + AgeOfEvent = Time passed + EventText = Description + TimeUnits { + Days = days + Hours = hours + Minutes = minutes + Seconds = seconds + } +} + +AdviceMessage { + EmptyLog.Text = There are no messages available. } diff --git a/plugins/logs/logs.css b/plugins/logs/logs.css index 41335ed..68173c7 100644 --- a/plugins/logs/logs.css +++ b/plugins/logs/logs.css @@ -1,6 +1,15 @@ -#log p.console { - margin-left: 10%; - margin-right: 10%; - font-family: monospace; - text-align: left; +#log table.log td.level img { + width: 24px; + height: 24px; + vertical-align: middle; } + +#log table.log td.time { + padding: 0 5px 0 3px; +} + +#log table.log td.text { + font-size: 0.8em; + font-family: monospace; +} + diff --git a/plugins/logs/logs.py b/plugins/logs/logs.py index e4ddd18..2ac294e 100644 --- a/plugins/logs/logs.py +++ b/plugins/logs/logs.py @@ -26,6 +26,14 @@ __revision__ = "$Id" import cryptobox.plugins.base import os +import re +import datetime + +LOG_LEVELS = [ 'DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERROR' ] + +LINE_REGEX = re.compile(r"(?P\d{4})-(?P\d{2})-(?P\d{2}) " \ + + r"(?P\d{2}):(?P\d{2}):\d{2},\d{3} (?P" \ + + "|".join([ "(?:%s)" % e for e in LOG_LEVELS]) + r"): (?P.*)$") class logs(cryptobox.plugins.base.CryptoBoxPlugin): """The logs feature of the CryptoBox. @@ -36,29 +44,31 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): request_auth = False rank = 90 - def do_action(self, lines=50, size=3000, pattern=None): + def do_action(self, lines=50, size=3000, level=None): """Show the latest part of the log file. """ - import re ## filter input try: lines = int(lines) if lines <= 0: raise(ValueError) except ValueError: + self.cbox.log.info("[logs] invalid line number: %s" % str(lines)) lines = 50 try: size = int(size) if size <= 0: raise(ValueError) except ValueError: + self.cbox.log.info("[logs] invalid log size: %s" % str(size)) 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.__get_log_content( - lines, size, pattern) + if not level is None: + level = str(level) + if not level in LOG_LEVELS: + self.cbox.log.info("[logs] invalid log level: %s" % str(level)) + level = None + for (index, line) in enumerate(self.__get_log_content(lines, size, level)): + self.__set_line_hdf_data(self.hdf_prefix + "Content.%d" % index, line) self.hdf[self.hdf_prefix + "StyleSheetFile"] = os.path.abspath(os.path.join( self.plugin_dir, "logs.css")) return "show_log" @@ -73,21 +83,79 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): self.cbox.prefs["Log"]["Details"]) - def __get_log_content(self, lines, max_size, pattern): + def __get_log_content(self, lines, max_size, level): """Filter, sort and shorten the log content. """ - if pattern: + if level and level in LOG_LEVELS: + filtered_levels = LOG_LEVELS[:] + ## only the given and higher levels are accepted + while filtered_levels[0] != level: + del filtered_levels[0] content = [] current_length = 0 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 max_size and current_length >= max_size: + for one_level in filtered_levels: + if line.find(one_level) != -1: break + else: + ## the line does not contain an appropriate level name + continue + ## we found a line that fits + content.append(line) + current_length += len(line) + if lines and len(content) >= lines: + break + if max_size and current_length >= max_size: + break else: content = self.cbox.get_log_data(lines, max_size) - return "
".join(content) + return content + + def __set_line_hdf_data(self, hdf_prefix, line): + """Parse the log line for time and log level. + + If parsing fails, then the output line is simply displayed without + meta information. + """ + self.hdf[hdf_prefix + ".Text"] = line.strip() + match = LINE_REGEX.match(line) + if not match: + ## we could not parse the line - just return the text without meta info + return + ## matching was successfully - we can parse the line for details + ## calculate time difference of log line (aka: age of event) + try: + (year, month, day, hour, minute) = match.group( + 'year', 'month', 'day', 'hour', 'minute') + (year, month, day, hour, minute) = \ + (int(year), int(month), int(day), int(hour), int(minute)) + ## timediff is a timedelta object + timediff = datetime.datetime.today() - \ + datetime.datetime(year, month, day, hour, minute) + ## the time units (see below) correspond to the names within the language + ## file: Text.TimeUnits.Days ... + if timediff.days >= 1: + self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Days' + self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.days + elif timediff.seconds >= 3600: + self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Hours' + self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds / 3600 + elif timediff.seconds >= 60: + self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Minutes' + self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds / 60 + else: + self.hdf[hdf_prefix + ".TimeDiff.Unit"] = 'Seconds' + self.hdf[hdf_prefix + ".TimeDiff.Value"] = timediff.seconds + except (OverflowError, TypeError, ValueError, IndexError), err_msg: + pass + ## retrieve the level + try: + self.hdf[hdf_prefix + ".Level"] = match.group('level') + except IndexError: + pass + try: + self.hdf[hdf_prefix + ".Text"] = match.group('text').strip() + except IndexError: + pass + diff --git a/plugins/logs/show_log.cs b/plugins/logs/show_log.cs index 8abc9c9..6c245ab 100644 --- a/plugins/logs/show_log.cs +++ b/plugins/logs/show_log.cs @@ -6,21 +6,63 @@

-
- + + + + +
- - + var:html_escape(Lang.Plugins.logs.Text.ShowAll) ?> + + + + + + +
- -

+ 0 ?> + + + + + + + + + + +
" + alt="symbol: " /> 
-

+
diff --git a/plugins/logs/unittests.py b/plugins/logs/unittests.py index c51b04f..3faa88d 100644 --- a/plugins/logs/unittests.py +++ b/plugins/logs/unittests.py @@ -28,32 +28,32 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): log_url = self.url + "logs" self.register_auth(log_url) self.cmd.go(log_url) - self.cmd.find('class="console"') + self.cmd.find('') def test_write_logs(self): log_text = "unittest - just a marker - please ignore" self.cbox.log.error(log_text) log_url = self.url + "logs" self.register_auth(log_url) - self.cmd.go(log_url + "?pattern=ERROR") + self.cmd.go(log_url + "?level=ERROR") self.cmd.find(log_text) def test_invalid_args(self): log_url = self.url + "logs" self.cmd.go(log_url + "?lines=10") - self.cmd.find('class="console"') + self.cmd.find('
') self.cmd.go(log_url + "?lines=0") - self.cmd.find('class="console"') + self.cmd.find('
') self.cmd.go(log_url + "?lines=x") - self.cmd.find('class="console"') + self.cmd.find('
') self.cmd.go(log_url + "?size=1000") - self.cmd.find('class="console"') + self.cmd.find('
') self.cmd.go(log_url + "?size=0") - self.cmd.find('class="console"') + self.cmd.find('
') self.cmd.go(log_url + "?size=x") - self.cmd.find('class="console"') - self.cmd.go(log_url + "?pattern=foobar") - self.cmd.find('class="console"') - self.cmd.go(log_url + u"?pattern=kfj!^(]") - self.cmd.find('class="console"') + self.cmd.find('
') + self.cmd.go(log_url + "?level=foobar") + self.cmd.find('
') + self.cmd.go(log_url + r"?level=kfj!^(]") + self.cmd.find('
') diff --git a/plugins/network/network.py b/plugins/network/network.py index 6992bce..63aa189 100644 --- a/plugins/network/network.py +++ b/plugins/network/network.py @@ -128,7 +128,7 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin): 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) + match = re.search(r'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()]) diff --git a/plugins/network/root_action.py b/plugins/network/root_action.py index 83edb12..3b52aca 100755 --- a/plugins/network/root_action.py +++ b/plugins/network/root_action.py @@ -50,7 +50,7 @@ if __name__ == "__main__": sys.stderr.write("%s: no argument supplied\n" % self_bin) sys.exit(1) - match = re.search(u'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$', args[0]) + match = re.search(r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$', args[0]) ## did we match? If yes, then: are there wrong values inside? if not match or [e for e in match.groups() if int(e) > 255]: sys.stderr.write("%s: illegal argument (%s)\n" % (self_bin, args[0])) diff --git a/plugins/network/unittests.py b/plugins/network/unittests.py index f49a5d4..c371c2a 100644 --- a/plugins/network/unittests.py +++ b/plugins/network/unittests.py @@ -38,7 +38,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): 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") + self.cmd.find(r'Data.Status.Plugins.network=([0-9\.]*)$', "m") return self.locals["__match__"] orig_ip_text = get_current_ip() orig_ip_octs = orig_ip_text.split(".") diff --git a/plugins/partition/language.hdf b/plugins/partition/language.hdf index a00ab29..5379d5e 100644 --- a/plugins/partition/language.hdf +++ b/plugins/partition/language.hdf @@ -57,16 +57,18 @@ WarningMessage { PartitioningFailed { Title = Partitioning failed Text = The partitioning of the device failed for some reason - sorry! - Link.Text = Show log messages - Link.Attr1.name = pattern + Link.Text = Show log messages + Link.Rel = logs + Link.Attr1.name = level Link.Attr1.value = ERROR } FormattingFailed { Title = Formatting failed - Text = The formatting of the filesystems of the device failed - sorry! + Text = Formatting of at least one volume failed - sorry! Link.Text = Show log messages - Link.Attr1.name = pattern + Link.Rel = logs + Link.Attr1.name = level Link.Attr1.value = ERROR } diff --git a/plugins/partition/partition.py b/plugins/partition/partition.py index 262ff2d..d843b4a 100644 --- a/plugins/partition/partition.py +++ b/plugins/partition/partition.py @@ -209,37 +209,34 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin): ## 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 - format_part_gen = self.__format_partitions(parts) - while counter < len(parts): - ## first part: get the device name - yield format_part_gen.next() - counter += 1 - ## second part: do the real formatting of a partition - 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.mount_partition() - self.cbox.prefs.write() - self.cbox.log.info("settings stored on config partition") - ## return the result - if result: - yield "OK" - else: - yield "Error" - return { - "template": "show_format_progress", - "generator": result_generator} + #self.cbox.reread_container_list() + format_ok = True + counter = 0 + ## initialize the generator + format_part_gen = self.__format_partitions(parts) + while counter < len(parts): + ## first part: get the device name + counter += 1 + ## second part: do the real formatting of a partition + 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.mount_partition() + self.cbox.prefs.write() + self.cbox.log.info("settings stored on config partition") + ## return the result + if not result: + format_ok = False + if format_ok: + self.hdf["Data.Success"] = "Plugins.partition.Partitioned" + else: + self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed" + return "empty" else: return self.__action_add_partition(args) @@ -382,6 +379,9 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin): self.device]) for line in self.__get_sfdisk_layout(parts, is_filled): proc.stdin.write(line + "\n") + #TODO: if running inside of an uml, then sfdisk hangs at "nanosleep({3,0})" + # very ugly - maybe a uml bug? + # it seems, like this can be avoided by running uml with the param "aio=2.4" (output, error) = proc.communicate() if proc.returncode != 0: self.cbox.log.debug("partitioning failed: %s" % error) @@ -439,7 +439,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin): dev_name = self.device + str(part_num) 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.__format_one_partition(dev_name, part_type) del parts[0] ## other data partitions @@ -449,7 +448,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin): 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.__format_one_partition(dev_name, part_type) part_num += 1 del parts[0] @@ -476,34 +474,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin): return True - def __old_format_one_partition(self, dev_name, fs_type): - """Format a single partition - """ - ## first: retrieve UUID - it can be removed from the database afterwards - 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, - args = [ - self.cbox.prefs["Programs"]["super"], - self.cbox.prefs["Programs"]["CryptoBoxRootActions"], - "plugin", - os.path.join(self.plugin_dir, "root_action.py"), - "format", - dev_name, - fs_type]) - (output, error) = proc.communicate() - if proc.returncode != 0: - self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error)) - return False - else: - ## remove unused volume entry - if prev_name: - del self.cbox.prefs.volumes_db[prev_name[0]] - return True - - def __set_label_of_partition(self, dev_name, label): """Set the label of a partition - useful for the config partition. """ diff --git a/plugins/plugin-interface.txt b/plugins/plugin-interface.txt index 321415c..4a029df 100644 --- a/plugins/plugin-interface.txt +++ b/plugins/plugin-interface.txt @@ -30,6 +30,10 @@ Python code interface: - 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)) + - function "setup": + - may be overridden to specify bootup behaviour + - function "cleanup": + - may be overridden to specify shutdown behaviour - the class variable "plugin_capabilities" must be an array of strings (supported: "system" and "volume") - the class variable "plugin_visibility" may contain one or more of the following items: diff --git a/plugins/plugin_manager/plugin_manager.py b/plugins/plugin_manager/plugin_manager.py index f40a3eb..1c75e52 100644 --- a/plugins/plugin_manager/plugin_manager.py +++ b/plugins/plugin_manager/plugin_manager.py @@ -35,7 +35,7 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin): import re if plugin_name: ## check for invalid characters - if re.search(u'\W', plugin_name): return "plugin_list" + if re.search(r'\W', plugin_name): return "plugin_list" plugin_manager = cryptobox.plugins.manage.PluginManager( self.cbox, self.cbox.prefs["Locations"]["PluginDir"]) plugin = plugin_manager.get_plugin(plugin_name) @@ -51,7 +51,7 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin): elif store: for key in args.keys(): if key.endswith("_listed"): - if not re.search(u'\W',key): + if not re.search(r'\W',key): self.__setConfig(key[:-7], args) else: self.cbox.log.info("plugin_manager: invalid plugin name (%s)" % \ @@ -129,7 +129,7 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin): setting = {} setting["visibility"] = [] ## look for "_visible_" values and apply them - pattern = re.compile(u'%s_visible_([\w]+)$' % name) + pattern = re.compile(r'%s_visible_([\w]+)$' % name) for key in args.keys(): if key.startswith(name + "_visible_"): (vis_type, ) = pattern.match(key).groups() diff --git a/plugins/plugin_manager/unittests.py b/plugins/plugin_manager/unittests.py index 4738fa5..48163db 100644 --- a/plugins/plugin_manager/unittests.py +++ b/plugins/plugin_manager/unittests.py @@ -34,25 +34,25 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): def test_set_options(self): url = self.url + "plugin_manager" self.register_auth(url) - self.cmd.go(url + u"?plugin_name=t/-!") + self.cmd.go(url + r"?plugin_name=t/-!") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?plugin_name=foobar") + self.cmd.go(url + r"?plugin_name=foobar") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?plugin_name=disks&action=up") + self.cmd.go(url + r"?plugin_name=disks&action=up") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?plugin_name=disks&action=down") + self.cmd.go(url + r"?plugin_name=disks&action=down") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&dis/ks_listed") + self.cmd.go(url + r"?store=1&dis/ks_listed") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_rank=50") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_rank=50") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_rank=x") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_rank=x") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_auth=1") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_auth=1") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_rank=50&disks_auth=1") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_rank=50&disks_auth=1") self.cmd.find('Plugin Manager') @@ -60,11 +60,11 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): #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.go(url + r"?plugin_name=disks&action=up") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_rank=0") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_rank=0") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?plugin_name=disks&action=up") + self.cmd.go(url + r"?plugin_name=disks&action=up") self.cmd.find('Plugin Manager') @@ -72,11 +72,11 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): ## 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=down") + self.cmd.go(url + r"?plugin_name=disks&action=down") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?store=1&disks_listed&disks_visible_menu=1&disks_rank=100") + self.cmd.go(url + r"?store=1&disks_listed&disks_visible_menu=1&disks_rank=100") self.cmd.find('Plugin Manager') - self.cmd.go(url + u"?plugin_name=disks&action=down") + self.cmd.go(url + r"?plugin_name=disks&action=down") self.cmd.find('Plugin Manager') diff --git a/plugins/system_preferences/unittests.py b/plugins/system_preferences/unittests.py index 716975c..6342551 100644 --- a/plugins/system_preferences/unittests.py +++ b/plugins/system_preferences/unittests.py @@ -31,7 +31,7 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): def test_check_plugins(self): self.cmd.go(self.url + "system_preferences") - self.cmd.find(u'Data.Status.Plugins.system_preferences=(.*)$', "m") + self.cmd.find(r'Data.Status.Plugins.system_preferences=(.*)$', "m") plugins = self.locals["__match__"].split(":") self.assertTrue(len(plugins) > 1) self.assertTrue("disks" in plugins) diff --git a/plugins/user_manager/user_manager.py b/plugins/user_manager/user_manager.py index f4c2420..b0a51e2 100644 --- a/plugins/user_manager/user_manager.py +++ b/plugins/user_manager/user_manager.py @@ -38,7 +38,7 @@ class user_manager(cryptobox.plugins.base.CryptoBoxPlugin): if store is None: pass elif store == "add_user": - if (user is None) or (re.search(u'\W', user)): + if (user is None) or (re.search(r'\W', user)): self.hdf["Data.Warning"] = "Plugins.user_manager.InvalidUserName" elif not new_pw: self.hdf["Data.Warning"] = "EmptyNewPassword" diff --git a/plugins/volume_automount/unittests.py b/plugins/volume_automount/unittests.py index 0852414..db0c6a8 100644 --- a/plugins/volume_automount/unittests.py +++ b/plugins/volume_automount/unittests.py @@ -28,8 +28,10 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): """try to read automount form""" url = self.url + "volume_automount?weblang=en&device=%2Fdev%2F" + self.device self.register_auth(url) + ## first: turn it off + self.cmd.go(url + "&action=disable") self.cmd.go(url) - self.cmd.find('Opening during startup') + self.cmd.find('is disabled') def test_toggle(self): @@ -37,11 +39,11 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): url = self.url + "volume_automount" self.register_auth(url) self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=disable" % self.device) - self.cmd.find("Automatic opening disabled") + self.cmd.find("Automatic activation disabled") self.cmd.find("is disabled") self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=enable" % self.device) - self.cmd.find("Automatic opening enabled") - self.cmd.notfind("is disabled") + self.cmd.find("Automatic activation enabled") + self.cmd.find("is enabled") def test_invalid_input(self): @@ -49,6 +51,6 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): url = self.url + "volume_automount" self.register_auth(url) self.cmd.go(url + "?device=%%2Fdev%%2F%s&action=foobar" % self.device) - self.cmd.notfind("Automatic opening disabled") - self.cmd.notfind("Automatic opening enabled") + self.cmd.notfind("Automatic activation disabled") + self.cmd.notfind("Automatic activation enabled") diff --git a/plugins/volume_automount/volume_automount.py b/plugins/volume_automount/volume_automount.py index 6a87c14..64205df 100644 --- a/plugins/volume_automount/volume_automount.py +++ b/plugins/volume_automount/volume_automount.py @@ -21,6 +21,7 @@ __revision__ = "$Id" import cryptobox.plugins.base +import cryptobox.core.container from cryptobox.core.exceptions import * @@ -55,21 +56,34 @@ class volume_automount(cryptobox.plugins.base.CryptoBoxPlugin): return "volume_automount" + def setup(self): + """Override bootup behaviour. + + Mount all volumes marked as 'automount'. + """ + cryptobox.plugins.base.CryptoBoxPlugin.setup(self) + for cont in self.cbox.get_container_list(): + if self.__is_auto_mount(cont) and not cont.is_mounted(): + cont.mount() + + def get_status(self): - return str(self.__is_auto_mount()) + return str(self.__is_auto_mount(self.cbox.get_container(self.device))) def __prepare_hdf(self): - if self.__is_auto_mount(): + if self.__is_auto_mount(self.cbox.get_container(self.device)): self.hdf[self.hdf_prefix + "automount_setting"] = "1" else: self.hdf[self.hdf_prefix + "automount_setting"] = "0" - def __is_auto_mount(self): - container = self.cbox.get_container(self.device) + def __is_auto_mount(self, container): if not container: return False + ## only valid for plain volumes + if container.get_type() != cryptobox.core.container.CONTAINERTYPES["plain"]: + return False if container.attributes.has_key("automount"): return container.attributes["automount"] == self.true_string else: diff --git a/plugins/volume_format_fs/language.hdf b/plugins/volume_format_fs/language.hdf index 1ce6e73..ef3c2c6 100644 --- a/plugins/volume_format_fs/language.hdf +++ b/plugins/volume_format_fs/language.hdf @@ -47,7 +47,7 @@ WarningMessage { Text = Formatting of the selected filesystem failed for unknown reasons - sorry! Link.Text = View log messages Link.Rel = logs - Link.Attr1.name = pattern + Link.Attr1.name = level Link.Attr1.value = ERROR } } diff --git a/plugins/volume_mount/language.hdf b/plugins/volume_mount/language.hdf index 70c3f20..57ff300 100644 --- a/plugins/volume_mount/language.hdf +++ b/plugins/volume_mount/language.hdf @@ -3,8 +3,8 @@ Link = Activation Title { - Mount = Open volume - Umount = Turn on the volume + Mount = Opening a volume + Umount = Closing a volume } @@ -29,12 +29,12 @@ SuccessMessage { WarningMessage { MountFailed { - Title = Activation failed + Title = Opening failed Text = The volume could not be activated for some reason. Sorry! } MountCryptoFailed { - Title = Activation failed + Title = Opening failed Text = Maybe you entered the wrong password? } diff --git a/plugins/volume_mount/unittests.py b/plugins/volume_mount/unittests.py index a531e13..8fdd1b8 100644 --- a/plugins/volume_mount/unittests.py +++ b/plugins/volume_mount/unittests.py @@ -27,6 +27,10 @@ class unittests(cryptobox.web.testclass.WebInterfaceTestClass): def test_read_form(self): url = self.url + "volume_mount?weblang=en&device=%2Fdev%2F" + self.device self.register_auth(url) + ## first: umount if necessary + self.cmd.go(url + "&action=umount") + ## now we can start self.cmd.go(url) + #TODO: make sure, that device is closed before self.cmd.find('Open volume') diff --git a/scripts/fetch_po_files.sh b/scripts/fetch_po_files.sh index 83d0fa1..d151ce5 100755 --- a/scripts/fetch_po_files.sh +++ b/scripts/fetch_po_files.sh @@ -1,36 +1,88 @@ #!/bin/sh # -# this script symlinks all cbx po files to thorax' pootle dir -# it is useful to be root for this - otherwise chown and the pootle restart will fail +# this script symlinks all cbx po files to a language directory structure, as +# it is used by the pootle translation server # +# all language files are chgrp'ed to the 'pootle' group and group write +# permissions are added +# +# call this script whenever you add _new_ languages to your translation server +# +# it is useful to be root while calling it - otherwise chgrp will fail +# +# +# Copyright 2006 sense.lab e.V. +# +# This file is part of the CryptoBox. +# +# The CryptoBox is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The CryptoBox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the CryptoBox; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + + +set -eu test $# -ne 1 && echo "Usage: $(basename $0) TARGET_DIR" && exit 1 test ! -d "$1" && echo "target directory does not exist: '$1'" && exit 1 -TARGETPATH=$1 +if test "$(id -u)" == 0 + then is_root=1 + else is_root=0 + echo "$(basename $0) not running as root: the language files will not be writeable for pootle" >&2 + echo " run this script as root to change the permissions of the language files appropriately" >&2 + fi + +DEST_GROUP=pootle +TARGETPATH=${1%/} BASEPATH=$(cd $(dirname "$0")/..; pwd) -mkdir -p ${TARGETPATH}/templates +############# functions ############### -for language in `ls ${BASEPATH}/intl/` ; do +# symlink a language file and chgrp if possible +# Paramters: LANG_FILE LANGUAGE +process_language_file() +{ + test ! -d "${TARGETPATH}/$2" && mkdir -p "${TARGETPATH}/$2" + ln -sfn "$1" "${TARGETPATH}/$2/" + if test "$is_root" == 1 + then chgrp "$DEST_GROUP" "$1" "$TARGETPATH/$2" + chmod g+w "$1" "$TARGETPATH/$2" + fi +} + + +############# main ################# + + +for language in $(ls ${BASEPATH}/intl/) ; do test ! -d "${BASEPATH}/intl/${language}" && continue echo "Processing $language ..." [ ! -d ${TARGETPATH}/${language} ] && mkdir -p ${TARGETPATH}/${language} ## base translation - find ${BASEPATH}/intl/${language} -name \*.po -exec ln -sfn '{}' ${TARGETPATH}/${language}/ \; + find "${BASEPATH}/intl/${language}" -name \*.po | while read fname + do process_language_file "$fname" "$language" + done ## plugin translations - for plugin in $(ls ${BASEPATH}/plugins/); do - test ! -d "${BASEPATH}/plugins/${plugin}" && continue - find ${BASEPATH}/plugins/${plugin}/intl/${language} -name \*.po -exec ln -sfn '{}' ${TARGETPATH}/${language}/ \; - done + find "${BASEPATH}/plugins/" -name \*.po | \ + grep "/intl/$language/" | while read fname + do process_language_file "$fname" "$language" + done done echo "Processing template files ..." find ${BASEPATH}/intl ${BASEPATH}/plugins -type f -name \*.pot | while read fname - do ln -sfn $fname ${TARGETPATH}/templates/ + do process_language_file "$fname" "template" done -chown -R pootle. ${TARGETPATH} -/etc/init.d/pootle restart - diff --git a/src/cryptobox/__init__.py b/src/cryptobox/__init__.py index a476b56..0e09e4e 100644 --- a/src/cryptobox/__init__.py +++ b/src/cryptobox/__init__.py @@ -10,5 +10,5 @@ __all__ = ['core', 'web', 'plugins', 'tests'] __revision__ = "$Id$" -__version__ = "0.2.53" +__version__ = "0.2.54" diff --git a/src/cryptobox/core/container.py b/src/cryptobox/core/container.py index 58cb8d8..012e519 100644 --- a/src/cryptobox/core/container.py +++ b/src/cryptobox/core/container.py @@ -208,41 +208,6 @@ class CryptoBoxContainer: pass - def set_busy(self, new_state, time_limit=300): - """Set the current busy state. - - The timelimit is specified in seconds. - """ - if new_state: - self.cbox.busy_devices[self.device] = int(time.time() + time_limit) - else: - try: - if self.cbox.busy_devices[self.device]: - del self.cbox.busy_devices[self.device] - except KeyError: - pass - - - def is_busy(self): - """Check the busy state of the container. - """ - if not self.cbox.busy_devices.has_key(self.device): - self.cbox.log.debug("no 'busy' attribute for '%s'" % self.get_name()) - return False - ## invalid value - can happen after saving and loading the database - if not isinstance(self.cbox.busy_devices[self.device], int): - self.cbox.log.debug("invalid 'busy' attribute for '%s'" % self.get_name()) - del db_entry["busy"] - return False - if time.time() >= self.cbox.busy_devices[self.device]: - self.cbox.log.debug("expired 'busy' attribute for '%s'" % self.get_name()) - del db_entry["busy"] - return False - ## lock is still active - self.cbox.log.debug("active 'busy' attribute for '%s'" % self.get_name()) - return True - - def change_password(self, oldpw, newpw): """Change the password of an encrypted container. @@ -311,6 +276,23 @@ class CryptoBoxContainer: raise CBChangePasswordError(error_msg) + def is_busy(self): + """Return the current state of the busy flag of this device. + + The busy flag is mainly used to indicate that the device may not be used + while it is being formatted or similar. + """ + return self.cbox.get_device_busy_state(self.device) + + + def set_busy(self, new_state, timeout=300): + """Set the busy state of this device. + + Either set or remove this flag. + The timeout is optional and defaults to five minutes. + """ + self.cbox.set_device_busy_state(self.device, new_state, timeout) + ## ****************** internal stuff ********************* @@ -424,7 +406,7 @@ class CryptoBoxContainer: "-c", os.devnull, "-w", os.devnull, self.device ]) - (stdout, stder) = proc.communicate() + (stdout, stderr) = proc.communicate() if proc.returncode == 0: ## we found a uuid return stdout.strip() @@ -644,14 +626,20 @@ class CryptoBoxContainer: raise CBVolumeIsActive( "deactivate the partition before filesystem initialization") def format(): - import os - old_name = self.get_name() + """This function will get called as a seperate thread. + + To avoid the non-sharing cpu distribution between the formatting thread + and the main interface, we fork and let the parent wait for the child. + This should be handled using the kernel's threading features. + """ + ## create a local object - to store different values for each thread + loc_data = threading.local() + loc_data.old_name = self.get_name() self.set_busy(True, 600) - self.cbox.log.debug("Turn the busy flag on: %s" % self.device) ## give the main thread a chance to continue - child_pid = os.fork() - if child_pid == 0: - proc = subprocess.Popen( + loc_data.child_pid = os.fork() + if loc_data.child_pid == 0: + loc_data.proc = subprocess.Popen( shell = False, stdin = None, stdout = subprocess.PIPE, @@ -660,17 +648,19 @@ class CryptoBoxContainer: self.cbox.prefs["Programs"]["nice"], self.cbox.prefs["Programs"]["mkfs"], "-t", fs_type, self.device]) - (stdout, sterr) = proc.communicate() + loc_data.proc.wait() ## for to allow error detection - if proc.returncode == 0: + if loc_data.proc.returncode == 0: time.sleep(5) ## skip cleanup stuff (as common for sys.exit) os._exit(0) else: - os.waitpid(child_pid, 0) - self.set_name(old_name) + os.waitpid(loc_data.child_pid, 0) + try: + self.set_name(loc_data.old_name) + except CBNameIsInUse: + pass self.set_busy(False) - self.cbox.log.debug("Turn the busy flag off: %s" % self.device) bg_task = threading.Thread(target=format) bg_task.start() time.sleep(3) @@ -731,14 +721,20 @@ class CryptoBoxContainer: self.cbox.log.error(err_msg) raise CBCreateError(err_msg) def format_luks(): - import os - old_name = self.get_name() + """This function will get called as a seperate thread. + + To avoid the non-sharing cpu distribution between the formatting thread + and the main interface, we fork and let the parent wait for the child. + This should be handled using the kernel's threading features. + """ + ## create a local object - to store different values for each thread + loc_data = threading.local() + loc_data.old_name = self.get_name() self.set_busy(True, 600) - self.cbox.log.debug("Turn the busy flag on: %s" % self.device) - child_pid = os.fork() - if child_pid == 0: + loc_data.child_pid = os.fork() + if loc_data.child_pid == 0: ## make the filesystem - proc = subprocess.Popen( + loc_data.proc = subprocess.Popen( shell = False, stdin = None, stdout = subprocess.PIPE, @@ -748,17 +744,16 @@ class CryptoBoxContainer: self.cbox.prefs["Programs"]["mkfs"], "-t", fs_type, os.path.join(self.__dmDir, self.name)]) - (stdou, stderr) = proc.communicate() + loc_data.proc.wait() ## wait to allow error detection - if proc.returncode == 0: + if loc_data.proc.returncode == 0: time.sleep(5) ## skip cleanup stuff (as common for sys.exit) os._exit(0) else: - os.waitpid(child_pid, 0) - self.set_name(old_name) + os.waitpid(loc_data.child_pid, 0) + self.set_name(loc_data.old_name) self.set_busy(False) - self.cbox.log.debug("Turn the busy flag off: %s" % self.device) ## remove the mapping - for every exit status self.__umount_luks() bg_task = threading.Thread(target=format_luks) diff --git a/src/cryptobox/core/main.py b/src/cryptobox/core/main.py index c4f5b52..3440bbc 100644 --- a/src/cryptobox/core/main.py +++ b/src/cryptobox/core/main.py @@ -31,6 +31,7 @@ import re import os import cryptobox.core.tools as cbxTools import subprocess +import threading class CryptoBox: @@ -46,10 +47,40 @@ class CryptoBox: self.prefs = cbxSettings.CryptoBoxSettings(config_file) self.__run_tests() self.__containers = [] - self.busy_devices = {} + self.__busy_devices = {} + self.__busy_devices_sema = threading.BoundedSemaphore() self.reread_container_list() + def setup(self): + """Initialize the cryptobox. + """ + self.log.info("Starting up the CryptoBox ...") + + + def cleanup(self): + """Umount all containers and shutdown everything safely. + """ + self.log.info("Shutting down the CryptoBox ...") + ## umount all containers + self.log.info("Umounting all volumes ...") + self.reread_container_list() + for cont in self.get_container_list(): + cont.umount() + ## save all settings + self.log.info("Storing local settings ...") + self.prefs.write() + if self.prefs.get_active_partition: + self.prefs.umount_partition() + ## shutdown logging as the last step + try: + self.log.info("Turning off logging ...") + self.log.close() + except AttributeError: + ## there should be 'close' action - but it may fail silently + pass + + def __get_startup_logger(self): """Initialize the configured logging facility of the CryptoBox. @@ -128,6 +159,44 @@ class CryptoBox: self.__containers.sort(cmp = lambda x, y: x.get_name() < y.get_name() and -1 or 1) + def get_device_busy_state(self, device): + """Return whether a device is currently marked as busy or not. + + The busy flag can be turned off manually (recommended) or the timeout + can expire. + """ + import time + self.__busy_devices_sema.acquire() + ## not marked as busy + if not self.__busy_devices.has_key(device): + self.__busy_devices_sema.release() + return False + ## timer is expired + if time.time() > self.__busy_devices[device]: + del self.__busy_devices[device] + self.__busy_devices_sema.release() + return False + self.__busy_devices_sema.release() + return True + + + def set_device_busy_state(self, device, new_state, timeout=300): + """Mark a device as busy. + + This is especially useful during formatting, as this may take a long time. + """ + import time + self.__busy_devices_sema.acquire() + self.log.debug("Turn busy flag %s: %s" % (new_state and "on" or "off", device)) + if new_state: + self.__busy_devices[device] = time.time() + timeout + else: + if self.__busy_devices.has_key(device): + del self.__busy_devices[device] + self.log.debug("Current busy flags: %s" % str(self.__busy_devices)) + self.__busy_devices_sema.release() + + def is_config_partition(self, device): """Check if a given partition contains configuration informations. diff --git a/src/cryptobox/core/settings.py b/src/cryptobox/core/settings.py index a939c90..7794829 100644 --- a/src/cryptobox/core/settings.py +++ b/src/cryptobox/core/settings.py @@ -28,6 +28,7 @@ import logging import subprocess import os import configobj, validate +import syslog class CryptoBoxSettings: @@ -56,6 +57,11 @@ class CryptoBoxSettings: 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.__read_misc_files() + + + def __read_misc_files(self): self.misc_files = self.__get_misc_files() @@ -150,6 +156,7 @@ class CryptoBoxSettings: if not self.get_active_partition(): self.log.warn("umountConfigPartition: no configuration partition mounted") return False + self.__read_misc_files() proc = subprocess.Popen( shell = False, stdout = subprocess.PIPE, @@ -363,9 +370,10 @@ class CryptoBoxSettings: 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 [] - return [MiscConfigFile(os.path.join(misc_dir, f), self.log) - for f in os.listdir(misc_dir) - if os.path.isfile(os.path.join(misc_dir, f))] + misc_files = [] + for root, dirs, files in os.walk(misc_dir): + misc_files.extend([os.path.join(root, e) for e in files]) + return [MiscConfigFile(os.path.join(misc_dir, f), self.log) for f in misc_files] def __get_config_filename(self, config_file): @@ -395,28 +403,46 @@ class CryptoBoxSettings: 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"] - if not log_level in log_level_avail: - raise TypeError - except KeyError: - raise CBConfigUndefinedError("Log", "Level") - except TypeError: + log_level = self.prefs["Log"]["Level"].upper() + log_level_avail = ["DEBUG", "INFO", "WARN", "ERROR"] + if not log_level in log_level_avail: raise CBConfigInvalidValueError("Log", "Level", log_level, - "invalid log level: only %s are allowed" % log_level_avail) - try: + "invalid log level: only %s are allowed" % str(log_level_avail)) + log_destination = self.prefs["Log"]["Destination"].lower() + ## keep this in sync with the spec and the log_destination branches below + log_dest_avail = ['file', 'syslog'] + if not log_destination in log_dest_avail: + raise CBConfigInvalidValueError("Log", "Destination", log_destination, + "invalid log destination: only %s are allowed" % str(log_dest_avail)) + if log_destination == 'file': try: log_handler = logging.FileHandler(self.prefs["Log"]["Details"]) - except KeyError: - raise CBConfigUndefinedError("Log", "Details") - except IOError: - raise CBEnvironmentError("could not write to log file (%s)" % \ - self.prefs["Log"]["Details"]) - log_handler.setFormatter( - logging.Formatter('%(asctime)s CryptoBox %(levelname)s: %(message)s')) + except IOError: + raise CBEnvironmentError("could not write to log file (%s)" % \ + self.prefs["Log"]["Details"]) + log_handler.setFormatter( + logging.Formatter('%(asctime)s %(levelname)s: %(message)s')) + elif log_destination == 'syslog': + log_facility = self.prefs["Log"]["Details"].upper() + log_facil_avail = ['KERN', 'USER', 'MAIL', 'DAEMON', 'AUTH', 'SYSLOG', + 'LPR', 'NEWS', 'UUCP', 'CRON', 'AUTHPRIV', 'LOCAL0', 'LOCAL1', + 'LOCAL2', 'LOCAL3', 'LOCAL4', 'LOCAL5', 'LOCAL6', 'LOCAL7'] + if not log_facility in log_facil_avail: + raise CBConfigInvalidValueError("Log", "Details", log_facility, + "invalid log details for 'syslog': only %s are allowed" % \ + str(log_facil_avail)) + ## retrive the log priority from the syslog module + log_handler = LocalSysLogHandler("CryptoBox", + getattr(syslog, 'LOG_%s' % log_facility)) + log_handler.setFormatter( + logging.Formatter('%(asctime)s CryptoBox %(levelname)s: %(message)s')) + else: + ## this should never happen - we just have it in case someone forgets + ## to update the spec, the 'log_dest_avail' or the above branches + raise CBConfigInvalidValueError("Log", "Destination", log_destination, + "invalid log destination: only %s are allowed" % str(log_dest_avail)) cbox_log = logging.getLogger("CryptoBox") - ## remove previous handlers + ## remove previous handlers (from 'basicConfig') cbox_log.handlers = [] ## add new one cbox_log.addHandler(log_handler) @@ -446,8 +472,8 @@ EventDir = string(default="/etc/cryptobox-server/events.d") [Log] Level = option("debug", "info", "warn", "error", default="warn") -Destination = option("file", default="file") -Details = string(min=1) +Destination = option("file", "syslog", default="file") +Details = string(min=1, default="/var/log/cryptobox-server/cryptobox.log") [WebSettings] Stylesheet = string(min=1) @@ -595,3 +621,34 @@ class MiscConfigFile: fdesc.close() return False + + +class LocalSysLogHandler(logging.Handler): + """Pass logging messages to a local syslog server without unix sockets. + + derived from: logging.SysLogHandler + """ + + def __init__(self, prepend='CryptoBox', facility=syslog.LOG_USER): + logging.Handler.__init__(self) + self.formatter = None + self.facility = facility + syslog.openlog(prepend, 0, facility) + + + def close(self): + """close the syslog connection + """ + syslog.closelog() + logging.Handler.close(self) + + + def emit(self, record): + """format and send the log message + """ + msg = "%s: %s" % (record.levelname, record.getMessage()) + try: + syslog.syslog(record.levelno, msg) + except: + self.handleError(record) + diff --git a/src/cryptobox/core/tools.py b/src/cryptobox/core/tools.py index e574f59..1aebd4e 100644 --- a/src/cryptobox/core/tools.py +++ b/src/cryptobox/core/tools.py @@ -164,7 +164,7 @@ def get_parent_blockdevices(): 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): + if re.search(r'\D', p_major) or re.search(r'\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)): diff --git a/src/cryptobox/plugins/base.py b/src/cryptobox/plugins/base.py index 4aa7499..8d679be 100644 --- a/src/cryptobox/plugins/base.py +++ b/src/cryptobox/plugins/base.py @@ -83,6 +83,18 @@ class CryptoBoxPlugin: return self.__module__ + def setup(self): + """Any plugin that wants to define bootup actions may override this. + """ + pass + + + def cleanup(self): + """Any plugin that wants to define shutdown actions may override this. + """ + pass + + @cherrypy.expose def get_icon(self, image=None, **kargs): """return the image data of the icon of the plugin @@ -92,7 +104,7 @@ class CryptoBoxPlugin: '**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)): + if (image is None) or (not re.match(r'[\w\-\.]*$', image)): plugin_icon_file = os.path.join(self.plugin_dir, self.default_icon_filename) else: plugin_icon_file = os.path.join(self.plugin_dir, image) diff --git a/src/cryptobox/tests/test.cryptobox.py b/src/cryptobox/tests/test.cryptobox.py index c0e722e..aad5383 100755 --- a/src/cryptobox/tests/test.cryptobox.py +++ b/src/cryptobox/tests/test.cryptobox.py @@ -144,7 +144,7 @@ CryptoBoxRootActions = CryptoBoxRootActions filename=self.filenames["configFileBroken"]) self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox, self.filenames["configFileBroken"]) - self.write_config("Details", "#out", + self.write_config("Destination", "Destination = foobar", filename=self.filenames["configFileBroken"]) self.assertRaises(CBConfigError, cryptobox.core.main.CryptoBox, self.filenames["configFileBroken"]) diff --git a/src/cryptobox/web/sites.py b/src/cryptobox/web/sites.py index 3018d0a..6c300af 100644 --- a/src/cryptobox/web/sites.py +++ b/src/cryptobox/web/sites.py @@ -83,6 +83,25 @@ class WebInterfaceSites: self._cp_on_http_error = self.new_http_error_handler ## set initial language order self.lang_order = self.cbox.prefs["WebSettings"]["Languages"][:] + self.setup() + + + def setup(self): + """Prepare the webinterface. + """ + self.cbox.setup() + for plugin in self.__plugin_manager.get_plugins(): + if plugin: + plugin.setup() + + + def cleanup(self): + """Shutdown the webinterface safely. + """ + for plugin in self.__plugin_manager.get_plugins(): + if plugin: + plugin.cleanup() + self.cbox.cleanup() def __reset_dataset(self): @@ -421,7 +440,7 @@ class WebInterfaceSites: 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 lang_order) and (not re.search(u'\W', value)): + if value and (value in lang_order) and (not re.search(r'\W', value)): lang_order.remove(value) lang_order.insert(0, value) self.cbox.log.debug( @@ -447,7 +466,7 @@ class WebInterfaceSites: 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 - regex = re.compile(u"\w+(-\w+)?(;q=[\d\.]+)?$") + regex = re.compile(r"\w+(-\w+)?(;q=[\d\.]+)?$") pref_langs = [e.split(";", 1)[0] for e in pref_lang_header.split(",") if regex.match(e)] @@ -468,7 +487,7 @@ class WebInterfaceSites: 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) \ + if device and re.match(r'[\w /\-]+$', device) \ and self.cbox.get_container(device): self.cbox.log.debug("select device: %s" % device) return True diff --git a/templates/language.hdf b/templates/language.hdf index 5173a1e..d580b7c 100644 --- a/templates/language.hdf +++ b/templates/language.hdf @@ -64,9 +64,9 @@ WarningMessage { } VolumeMayNotBeMounted { - Title = The container is mounted - Text = This action is not available while the container is active. Please turn it off first. - Link.Text = Deactivate volume + Title = The volume is open + Text = This action is not available while the container is active. Please close it first. + Link.Text = Close volume Link.Rel = volume_mount } @@ -85,7 +85,7 @@ WarningMessage { Text = We (the developer of the CryptoBox) would like to fix this problem for you and others. Please send the most recent part of the CryptoBox log to info@cryptobox.org. Thanks for your contribution! Link.Text = View log Link.Rel = logs - Link.Attr1.name = pattern + Link.Attr1.name = level Link.Attr1.value = ERROR } } diff --git a/templates/macros.cs b/templates/macros.cs index ea355a2..54c711a 100644 --- a/templates/macros.cs +++ b/templates/macros.cs @@ -62,13 +62,13 @@ def:message_dispatch(mname, type, category) ?>