added minor parts of slovene translation

fixed samba integration script
added syslog support
replaced 'pattern' with 'level' for 'logs' plugin
improved fetch_po_files script
improved output of log plugin
recursively storing setting files fixed
umask set to 022
defining bootup and shutdown handler for the server
implementing volume_automount mounting
simplified the output preperation of the partition plugin
"busy" flag handling moved from core/container to core/main
This commit is contained in:
lars 2006-12-11 14:16:10 +00:00
parent 86503d0aab
commit 77324ae946
61 changed files with 708 additions and 360 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -64,6 +64,7 @@ Destination = file
# syslog: $LOG_FACILITY
#Details = /var/log/cryptobox.log
Details = ./cryptobox.log
#Details = SYSLOG
[WebSettings]

View File

@ -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

View File

@ -5,7 +5,7 @@
<IfModule mod_dav_fs.c>
# 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

View File

@ -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]

View File

@ -1,2 +0,0 @@
# DO NOT REMOVE OR EDIT THIS FILE
# the file was automatically generated by the cryptobox package

10
debian/changelog vendored
View File

@ -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 <devel@sumpfralle.de> Mon, 11 Dec 2006 11:52:38 +0100
cryptobox (0.2.53-1) unstable; urgency=low
* constant screen width

2
debian/control vendored
View File

@ -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

View File

@ -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"
}

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"

View File

@ -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):

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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."

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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č"

View File

@ -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(":"))

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"

View File

@ -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")

View File

@ -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.
}

View File

@ -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;
}

View File

@ -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<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) " \
+ r"(?P<hour>\d{2}):(?P<minute>\d{2}):\d{2},\d{3} (?P<level>" \
+ "|".join([ "(?:%s)" % e for e in LOG_LEVELS]) + r"): (?P<text>.*)$")
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 "<br/>".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

View File

@ -6,21 +6,63 @@
<h1><?cs var:html_escape(Lang.Plugins.logs.Title.Log) ?></h1>
<div align="center">
<?cs call:print_form_header("log-form", "logs") ?>
<table border="0" align="center"><tr>
<td><?cs call:print_form_header("log-all", "logs") ?>
<button type="submit" value="refresh"><?cs
var:html_escape(Lang.Plugins.logs.Text.Refresh) ?></button>
</form>
</div>
var:html_escape(Lang.Plugins.logs.Text.ShowAll) ?></button>
</form></td>
<td><?cs call:print_form_header("log-warnings", "logs") ?>
<input type="hidden" name="level" value="WARNING" />
<button type="submit" value="refresh"><?cs
var:html_escape(Lang.Plugins.logs.Text.AtLeastWarnings) ?></button>
</form></td>
<td><?cs call:print_form_header("log-only-error", "logs") ?>
<input type="hidden" name="level" value="ERROR" />
<button type="submit" value="refresh"><?cs
var:html_escape(Lang.Plugins.logs.Text.OnlyErrors) ?></button>
</form></td>
</tr></table>
<?cs call:handle_messages() ?>
<div id="log">
<?cs if:Data.Plugins.logs.Content ?>
<p class="console"><?cs var:Data.Plugins.logs.Content ?></p>
<?cs if:subcount(Data.Plugins.logs.Content) > 0 ?>
<table class="log"><?cs # the first line dictates if we show meta info or not
?><?cs if:Data.Plugins.logs.Content.0.Level ?>
<tr><th></th>
<th><?cs var:html_escape(Lang.Plugins.logs.Text.AgeOfEvent) ?></th>
<th><?cs var:html_escape(Lang.Plugins.logs.Text.EventText) ?></th>
</tr>
<?cs loop:index = #0, subcount(Data.Plugins.logs.Content)-1, #1 ?><?cs
with:x=Data.Plugins.logs.Content[index] ?><?cs
if:x.Text ?><?cs
if:x.Level == "ERROR" ?><?cs
set:meta_file="dialog-error_tango.gif" ?><?cs
elif:x.Level == "WARNING" ?><?cs
set:meta_file="dialog-warning_tango.gif" ?><?cs
else ?><?cs
set:meta_file="dialog-information_tango.gif" ?><?cs
/if ?>
<tr><td class="level"><img src="<?cs
call:link("cryptobox-misc/" + meta_file, "", "", "", "") ?>"
alt="symbol: <?cs var:html_escape(x.Level) ?>" /></td>
<td class="time"><?cs if:x.TimeDiff.Value ?><?cs
var:html_escape(x.TimeDiff.Value) ?>&nbsp;<?cs
var:html_escape(Lang.Plugins.logs.Text.TimeUnits[
x.TimeDiff.Unit]) ?><?cs
/if ?></td>
<td class="text"><?cs var:html_escape(x.Text) ?></td></tr><?cs
/if ?><?cs /with ?><?cs /loop ?><?cs
else ?><?cs
loop:index = #0, subcount(Data.Plugins.logs.Content)-1, #1 ?><?cs
with:x=Data.Plugins.logs.Content[index] ?>
<tr><td><?cs var:html_escape(x.Text) ?></td></tr><?cs
/with ?><?cs /loop ?><?cs
/if ?>
</table>
<?cs else ?>
<p><?cs var:html_escape(Lang.Plugins.logs.Text.EmptyLog) ?></p>
<?cs call:hint("Plugins.logs.EmptyLog") ?>
<?cs /if ?>
</div>

View File

@ -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('<table class="log">')
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('<table class="log">')
self.cmd.go(log_url + "?lines=0")
self.cmd.find('class="console"')
self.cmd.find('<table class="log">')
self.cmd.go(log_url + "?lines=x")
self.cmd.find('class="console"')
self.cmd.find('<table class="log">')
self.cmd.go(log_url + "?size=1000")
self.cmd.find('class="console"')
self.cmd.find('<table class="log">')
self.cmd.go(log_url + "?size=0")
self.cmd.find('class="console"')
self.cmd.find('<table class="log">')
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('<table class="log">')
self.cmd.go(log_url + "?level=foobar")
self.cmd.find('<table class="log">')
self.cmd.go(log_url + r"?level=kfj!^(]")
self.cmd.find('<table class="log">')

View File

@ -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()])

View File

@ -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]))

View File

@ -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(".")

View File

@ -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
}

View File

@ -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 "<b>Error</b>"
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.
"""

View File

@ -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:

View File

@ -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()

View File

@ -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')

View File

@ -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)

View File

@ -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"

View File

@ -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")

View File

@ -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:

View File

@ -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
}
}

View File

@ -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?
}

View File

@ -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')

View File

@ -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

View File

@ -10,5 +10,5 @@ __all__ = ['core', 'web', 'plugins', 'tests']
__revision__ = "$Id$"
__version__ = "0.2.53"
__version__ = "0.2.54"

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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)):

View File

@ -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)

View File

@ -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"])

View File

@ -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

View File

@ -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
}
}

View File

@ -62,13 +62,13 @@ def:message_dispatch(mname, type, category)
?><?cs set:plugSuffix = string.slice(mname,savedX+1,string.length(mname))
?><?cs # choose the appropriate symbol file
?><?cs if:type == "success" ?><?cs
set:symbolFile = "dialog-information_tango.png"
set:symbolFile = "dialog-information_tango.gif"
?><?cs elif:type == "warning" ?><?cs
set:symbolFile = "dialog-error_tango.png"
set:symbolFile = "dialog-error_tango.gif"
?><?cs elif type == "environment_warning" ?><?cs
set:symbolFile = "dialog-error_tango.png"
set:symbolFile = "dialog-error_tango.gif"
?><?cs elif type == "hint" ?><?cs
set:symbolFile = "dialog-warning_tango.png"
set:symbolFile = "dialog-warning_tango.gif"
?><?cs /if
?><?cs # preparations are done - now start writing
?><div class="message"><table><tr><td class="message_symbol"><img src="<?cs

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB