added "missing dependency" warnings to network, data, encrypted_webinterface and partition plugins
add "self.root_action" to the plugin specification implement non-interactive key certificate creation during startup if necessary (the produced certificate is still broken) run stunnel during startup returned environment warnings are expected to be lists
This commit is contained in:
parent
c4d4ea399d
commit
ad3de60dd1
|
@ -32,5 +32,5 @@ mkdir -p "$BIN_DIR/../ttt/settings"
|
||||||
cd "$BIN_DIR"
|
cd "$BIN_DIR"
|
||||||
|
|
||||||
## run the webserver
|
## run the webserver
|
||||||
"$BIN_DIR/CryptoBoxWebserver" --config="$CONFIG_FILE" --pidfile=/tmp/cryptoboxwebserver.pid --logfile=/tmp/cryptoboxwebser.log --port=8080 --datadir="$BIN_DIR/../www-data" "$@"
|
"$BIN_DIR/CryptoBoxWebserver" --config="$CONFIG_FILE" --pidfile=/tmp/cryptoboxwebserver.pid --logfile=/tmp/cryptoboxwebserver.log --port=8080 --datadir="$BIN_DIR/../www-data" "$@"
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
"""Change date and time.
|
"""Change date and time.
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- date
|
||||||
|
- ntpdate (planned)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "$Id"
|
__revision__ = "$Id"
|
||||||
|
@ -68,6 +72,13 @@ class date(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
(now.year, now.month, now.day, now.hour, now.minute, now.second)
|
(now.year, now.month, now.day, now.hour, now.minute, now.second)
|
||||||
|
|
||||||
|
|
||||||
|
def get_warnings(self):
|
||||||
|
warnings = []
|
||||||
|
if not os.path.isfile(self.root_action.DATE_BIN):
|
||||||
|
warnings.append((48, "Plugins.%s.MissingProgramDate" % self.get_name()))
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
def __prepare_form_data(self):
|
def __prepare_form_data(self):
|
||||||
"""Set some hdf values.
|
"""Set some hdf values.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -37,3 +37,11 @@ WarningMessage {
|
||||||
Text = An invalid value for date or time was supplied. Please try again.
|
Text = An invalid value for date or time was supplied. Please try again.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnvironmentWarning {
|
||||||
|
MissingProgramDate {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The program 'date' is not installed. Please ask the administrator of the CryptoBox server to configure it properly.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,32 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
"""Create an SSL certificate to encrypt the webinterface connection via stunnel
|
"""Create an SSL certificate to encrypt the webinterface connection via stunnel
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- stunnel (>= 4.0)
|
||||||
|
- "M2Crypto" python module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "$Id"
|
__revision__ = "$Id"
|
||||||
|
|
||||||
import cryptobox.plugins.base
|
import cryptobox.plugins.base
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import cherrypy
|
||||||
|
|
||||||
|
CERT_FILENAME = 'cryptobox-ssl-certificate.pem'
|
||||||
|
KEY_BITS = 409
|
||||||
|
CERT_INFOS = {
|
||||||
|
"C": "SomeCountry",
|
||||||
|
"ST": "SomeState",
|
||||||
|
"L": "SomeLocality",
|
||||||
|
"O": "SomeOrganization",
|
||||||
|
"OU": "CryptoBox-Server",
|
||||||
|
"CN": "*",
|
||||||
|
"emailAddress": ""}
|
||||||
|
EXPIRE_TIME = 60*60*24*365*20 # 20 years
|
||||||
|
SIGN_DIGEST = "sha256"
|
||||||
|
PID_FILE = os.path.join("/tmp/cryptobox-stunnel.pid")
|
||||||
|
|
||||||
|
|
||||||
class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
|
@ -50,16 +71,137 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
def get_warnings(self):
|
def get_warnings(self):
|
||||||
"""check if the connection is encrypted
|
"""check if the connection is encrypted
|
||||||
"""
|
"""
|
||||||
import cherrypy, os
|
warnings = []
|
||||||
if cherrypy.request.scheme == "https":
|
## check if m2crypto is available
|
||||||
return None
|
try:
|
||||||
|
import M2Crypto
|
||||||
|
except ImportError:
|
||||||
|
warnings.append((45, "Plugins.%s.MissingModuleM2Crypto" % self.get_name()))
|
||||||
|
if not os.path.isfile(self.root_action.STUNNEL_BIN):
|
||||||
|
warnings.append((44, "Plugins.%s.MissingProgramStunnel" % self.get_name()))
|
||||||
|
## perform some checks for encrypted connections
|
||||||
## check an environment setting - this is quite common behind proxies
|
## check an environment setting - this is quite common behind proxies
|
||||||
if os.environ.has_key("HTTPS"):
|
## the arbitrarily chosen header is documented in README.proxy
|
||||||
return None
|
if (cherrypy.request.scheme != "https") \
|
||||||
## this arbitrarily chosen header is documented in README.proxy
|
and (not os.environ.has_key("HTTPS")) \
|
||||||
if cherrypy.request.headers.has_key("X-SSL-Request") \
|
and (not (cherrypy.request.headers.has_key("X-SSL-Request") \
|
||||||
and (cherrypy.request.headers["X-SSL-Request"] == "1"):
|
and (cherrypy.request.headers["X-SSL-Request"] == "1"))):
|
||||||
return None
|
## plaintext connection -> "heavy security risk" (priority=20..39)
|
||||||
## plaintext connection -> "heavy security risk" (priority=20..39)
|
warnings.append((25, "Plugins.%s.NoSSL" % self.get_name()))
|
||||||
return (25, "Plugins.%s.NoSSL" % self.get_name())
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
|
def handle_event(self, event, event_info=None):
|
||||||
|
"""Create a certificate during startup (if it does not exist) and run stunnel
|
||||||
|
"""
|
||||||
|
if event == "bootup":
|
||||||
|
cert_abs_name = self.cbox.prefs.get_misc_config_filename(CERT_FILENAME)
|
||||||
|
if not os.path.isfile(cert_abs_name):
|
||||||
|
try:
|
||||||
|
self.__create_certificate(cert_abs_name)
|
||||||
|
self.cbox.log.info("Created new SSL certificate: %s" % cert_abs_name)
|
||||||
|
except IOError, err_msg:
|
||||||
|
## do not run stunnel without a certificate
|
||||||
|
self.cbox.log.warn("Failed to create new SSL certificate (%s): %s" % \
|
||||||
|
(cert_abs_name, err_msg))
|
||||||
|
return
|
||||||
|
self.__run_stunnel(cert_abs_name)
|
||||||
|
elif event == "shutdown":
|
||||||
|
self.__kill_stunnel()
|
||||||
|
|
||||||
|
|
||||||
|
def __kill_stunnel(self):
|
||||||
|
"""try to kill a running stunnel daemon
|
||||||
|
"""
|
||||||
|
if not os.path.isfile(PID_FILE):
|
||||||
|
self.cbox.log.warn("Could not find the pid file of a running stunnel daemon: %s" % PID_FILE)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
pfile = open(PID_FILE, "r")
|
||||||
|
try:
|
||||||
|
pid = pfile.read().strip()
|
||||||
|
except IOError, err_msg:
|
||||||
|
self.cbox.log.warn("Failed to read the pid file (%s): %s" % (PID_FILE, err_msg))
|
||||||
|
pfile.close()
|
||||||
|
return
|
||||||
|
pfile.close()
|
||||||
|
except IOError, err_msg:
|
||||||
|
self.cbox.log.warn("Failed to open the pid file (%s): %s" % (PID_FILE, err_msg))
|
||||||
|
return
|
||||||
|
if pid.isdigit():
|
||||||
|
pid = int(pid)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
## SIGTERM = 15
|
||||||
|
os.kill(pid, 15)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def __run_stunnel(self, cert_name, dest_port=443):
|
||||||
|
## retrieve currently requested port (not necessarily the port served
|
||||||
|
## by cherrypy - e.g. in a proxy setup)
|
||||||
|
request_port = cherrypy.config.get("server.socket_port", 80)
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
shell = False,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
|
args = [
|
||||||
|
self.cbox.prefs["Programs"]["super"],
|
||||||
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
|
"plugin", os.path.join(self.plugin_dir, "root_action.py"),
|
||||||
|
cert_name,
|
||||||
|
str(request_port),
|
||||||
|
str(dest_port),
|
||||||
|
PID_FILE ])
|
||||||
|
(output, error) = proc.communicate()
|
||||||
|
if proc.returncode == 0:
|
||||||
|
self.cbox.log.info("Successfully started 'stunnel'")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.cbox.log.warn("Failed to run 'stunnel': %s" % error)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def __create_certificate(self, filename):
|
||||||
|
import M2Crypto
|
||||||
|
import time
|
||||||
|
string_type = 0x1000 | 1 # see http://www.koders.com/python/..
|
||||||
|
# ../fid07A99E089F55187896A06CD4E0B6F21B9B8F5B0B.aspx?s=bavaria
|
||||||
|
key_gen_number = 0x10001 # commonly used for key generation: 65537
|
||||||
|
rsa_key = M2Crypto.RSA.gen_key(KEY_BITS, key_gen_number, callback=lambda: None)
|
||||||
|
pkey = M2Crypto.EVP.PKey(md=SIGN_DIGEST)
|
||||||
|
pkey.assign_rsa(rsa_key)
|
||||||
|
issuer = M2Crypto.X509.X509_Name()
|
||||||
|
for (key, value) in CERT_INFOS.items():
|
||||||
|
issuer.add_entry_by_txt(key, string_type, value, 1, 1, 0)
|
||||||
|
## time object
|
||||||
|
asn_time1 = M2Crypto.ASN1.ASN1_UTCTIME()
|
||||||
|
asn_time1.set_time(long(time.time()) - EXPIRE_TIME)
|
||||||
|
asn_time2 = M2Crypto.ASN1.ASN1_UTCTIME()
|
||||||
|
asn_time2.set_time(long(time.time()) + EXPIRE_TIME)
|
||||||
|
cert = M2Crypto.X509.X509()
|
||||||
|
cert.set_issuer(issuer)
|
||||||
|
cert.set_subject(issuer)
|
||||||
|
cert.set_pubkey(pkey)
|
||||||
|
cert.set_not_before(asn_time1)
|
||||||
|
cert.set_not_after(asn_time2)
|
||||||
|
cert.sign(pkey, SIGN_DIGEST)
|
||||||
|
result = ""
|
||||||
|
result += cert.as_pem()
|
||||||
|
result += pkey.as_pem(cipher=None)
|
||||||
|
if not os.path.exists(os.path.dirname(filename)):
|
||||||
|
os.mkdir(os.path.dirname(filename))
|
||||||
|
try:
|
||||||
|
certfile = open(filename, "w")
|
||||||
|
except IOError:
|
||||||
|
raise
|
||||||
|
try:
|
||||||
|
certfile.write(result)
|
||||||
|
except IOError:
|
||||||
|
certfile.close()
|
||||||
|
raise
|
||||||
|
certfile.close()
|
||||||
|
os.chmod(filename, 0600)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,16 @@ EnvironmentWarning {
|
||||||
Text = The connection is not encrypted - passwords can be easily intercepted.
|
Text = The connection is not encrypted - passwords can be easily intercepted.
|
||||||
Link.Text = Use encrypted connection
|
Link.Text = Use encrypted connection
|
||||||
Link.Prot = https
|
Link.Prot = https
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MissingModuleM2Crypto {
|
||||||
|
Title = Missing module
|
||||||
|
Text = The python module 'M2Crypto' is missing. It is required for an encrypted connection to the CryptoBox webinterface. Please ask the administrator of the CryptoBox server to install the module.
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingProgramStunnel {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The program 'stunnel' is not installed. Please ask the administrator tof the CryptoBox server to configure it properly.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,17 @@ STUNNEL_BIN = "/usr/bin/stunnel"
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def run_stunnel(cert_file, src_port, dst_port):
|
|
||||||
|
def _get_username(uid):
|
||||||
|
import pwd
|
||||||
|
try:
|
||||||
|
user_entry = pwd.getpwuid(uid)
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
return user_entry[0]
|
||||||
|
|
||||||
|
|
||||||
|
def run_stunnel(cert_file, src_port, dst_port, pid_file):
|
||||||
import subprocess
|
import subprocess
|
||||||
if not src_port.isdigit():
|
if not src_port.isdigit():
|
||||||
sys.stderr.write("Source port is not a number: %s" % src_port)
|
sys.stderr.write("Source port is not a number: %s" % src_port)
|
||||||
|
@ -38,15 +48,21 @@ def run_stunnel(cert_file, src_port, dst_port):
|
||||||
if not dst_port.isdigit():
|
if not dst_port.isdigit():
|
||||||
sys.stderr.write("Destination port is not a number: %s" % dst_port)
|
sys.stderr.write("Destination port is not a number: %s" % dst_port)
|
||||||
return False
|
return False
|
||||||
if not os.path.isfile(cert_file, src_port, dst_port):
|
if not os.path.isfile(cert_file):
|
||||||
sys.stderr.write("The certificate file (%s) does not exist!" % cert_file)
|
sys.stderr.write("The certificate file (%s) does not exist!" % cert_file)
|
||||||
return False
|
return False
|
||||||
|
username = _get_username(os.getuid())
|
||||||
|
if not username:
|
||||||
|
sys.stderr.write("Could not retrieve the username with uid=%d." % os.getuid())
|
||||||
|
return False
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
shell = False,
|
shell = False,
|
||||||
args = [ STUNNEL_BIN,
|
args = [ STUNNEL_BIN,
|
||||||
|
"-P", pid_file,
|
||||||
"-p", cert_file,
|
"-p", cert_file,
|
||||||
"-d", dst_port,
|
"-d", dst_port,
|
||||||
"-r", src_port ])
|
"-r", src_port,
|
||||||
|
"-s", username ])
|
||||||
proc.wait()
|
proc.wait()
|
||||||
return proc.returncode == 0
|
return proc.returncode == 0
|
||||||
|
|
||||||
|
@ -56,13 +72,13 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
self_bin = sys.argv[0]
|
self_bin = sys.argv[0]
|
||||||
|
|
||||||
if len(args) != 3:
|
if len(args) != 4:
|
||||||
sys.stderr.write("%s: invalid number of arguments (%d instead of %d))\n" % \
|
sys.stderr.write("%s: invalid number of arguments (%d instead of %d))\n" % \
|
||||||
(self_bin, len(args), 3))
|
(self_bin, len(args), 4))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not run_stunnel(args[0], args[1], args[2]):
|
if not run_stunnel(args[0], args[1], args[2], args[3]):
|
||||||
sys.stderr.write("%s: failed to run 'stunnel'!")
|
sys.stderr.write("%s: failed to run 'stunnel'!" % self_bin)
|
||||||
sys.exit(100)
|
sys.exit(100)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
|
@ -27,3 +27,16 @@ SuccessMessage {
|
||||||
Text = The network address has been changed. In a few seconds you will get redirected to the new address.
|
Text = The network address has been changed. In a few seconds you will get redirected to the new address.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnvironmentWarning {
|
||||||
|
MissingProgramIfconfig {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The 'ifconfig' program is not installed. Please ask the administrator of the CryptoBox server to install it.
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingProgramRoute {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The 'route' program is not installed. Please ask the administrator of the CryptoBox server to configure it properly.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
"""The network feature of the CryptoBox.
|
"""The network feature of the CryptoBox.
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- ifconfig
|
||||||
|
- route
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "$Id"
|
__revision__ = "$Id"
|
||||||
|
@ -116,6 +120,17 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
self.__set_ip(self.prefs["_address"])
|
self.__set_ip(self.prefs["_address"])
|
||||||
|
|
||||||
|
|
||||||
|
def get_warnings(self):
|
||||||
|
"""Check for missing programs
|
||||||
|
"""
|
||||||
|
warnings = []
|
||||||
|
if not os.path.isfile(self.root_action.IFCONFIG_BIN):
|
||||||
|
warnings.append((55, "MissingProgramIfconfig"))
|
||||||
|
if not os.path.isfile(self.root_action.GWCONFIG_BIN):
|
||||||
|
warnings.append((52, "Plugins.%s.MissingProgramRoute" % self.get_name()))
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
def __get_redirect_destination(self, ip):
|
def __get_redirect_destination(self, ip):
|
||||||
"""Put the new URL together.
|
"""Put the new URL together.
|
||||||
"""
|
"""
|
||||||
|
@ -142,16 +157,12 @@ class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
"""Retrieve the current IP.
|
"""Retrieve the current IP.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
import imp
|
|
||||||
## load some values from the root_action.py script
|
|
||||||
root_action_plug = imp.load_source("root_action",
|
|
||||||
os.path.join(self.plugin_dir, "root_action.py"))
|
|
||||||
## get the current IP of the network interface
|
## get the current IP of the network interface
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
shell = False,
|
shell = False,
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
args = [
|
args = [
|
||||||
root_action_plug.IFCONFIG_BIN,
|
self.root_action.IFCONFIG_BIN,
|
||||||
self.__get_interface()])
|
self.__get_interface()])
|
||||||
(stdout, stderr) = proc.communicate()
|
(stdout, stderr) = proc.communicate()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
|
|
@ -55,6 +55,23 @@ EnvironmentWarning {
|
||||||
Link.Text = Initialize partition
|
Link.Text = Initialize partition
|
||||||
Link.Rel = partition
|
Link.Rel = partition
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MissingProgramSfdisk {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The program 'sfdisk' is not installed. Please ask the administrator of the CryptoBox to configure it properly.
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingProgramMkfs {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The program 'mkfs' is not installed. Please ask the administrator of the CryptoBox to configure it properly.
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingProgramE2label {
|
||||||
|
Title = Missing program
|
||||||
|
Text = The program 'e2label' is not installed. Please ask the administrator of the CryptoBox to configure it properly.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -99,12 +99,20 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
|
|
||||||
|
|
||||||
def get_warnings(self):
|
def get_warnings(self):
|
||||||
|
warnings = []
|
||||||
## this check is done _after_ "reset_dataset" -> if there is
|
## this check is done _after_ "reset_dataset" -> if there is
|
||||||
## a config partition, then it was loaded before
|
## a config partition, then it was loaded before
|
||||||
if self.cbox.prefs.requires_partition() \
|
if self.cbox.prefs.requires_partition() \
|
||||||
and not self.cbox.prefs.get_active_partition():
|
and not self.cbox.prefs.get_active_partition():
|
||||||
return (50, "Plugins.%s.ReadOnlyConfig" % self.get_name())
|
warnings.append((50, "Plugins.%s.ReadOnlyConfig" % self.get_name()))
|
||||||
return None
|
## check required programs
|
||||||
|
if not os.path.isfile(self.root_action.SFDISK_BIN):
|
||||||
|
warnings.append((53, "Plugins.%s.MissingProgramSfdisk" % self.get_name()))
|
||||||
|
if not os.path.isfile(self.root_action.MKFS_BIN):
|
||||||
|
warnings.append((56, "Plugins.%s.MissingProgramMkfs" % self.get_name()))
|
||||||
|
if not os.path.isfile(self.root_action.LABEL_BIN):
|
||||||
|
warnings.append((40, "Plugins.%s.MissingProgramE2label" % self.get_name()))
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
def __prepare_dataset(self):
|
def __prepare_dataset(self):
|
||||||
|
|
|
@ -41,6 +41,9 @@ Python code interface:
|
||||||
- the class variable "plugin_capabilities" must be an array of strings (supported: "system" and
|
- the class variable "plugin_capabilities" must be an array of strings (supported: "system" and
|
||||||
"volume")
|
"volume")
|
||||||
- method "is_useful(self, device)": defaults to "True" - overwrite it, if there could be circumstances, which could make the plugin useless - e.g. "automount" is not useful for encrypted containers
|
- method "is_useful(self, device)": defaults to "True" - overwrite it, if there could be circumstances, which could make the plugin useless - e.g. "automount" is not useful for encrypted containers
|
||||||
|
- method "get_warnings(self)": return a tuple of (Priority, WarningName) or None if
|
||||||
|
no problems exist
|
||||||
|
- "WarningName" should be something like "Plugins.PLUGINNAME.NoSSL"
|
||||||
- the class variable "plugin_visibility" may contain one or more of the following items:
|
- the class variable "plugin_visibility" may contain one or more of the following items:
|
||||||
menu/preferences/volume. This should fit to the 'plugin_capabilities' variable.
|
menu/preferences/volume. This should fit to the 'plugin_capabilities' variable.
|
||||||
An empty list is interpreted as an invisible plugin.
|
An empty list is interpreted as an invisible plugin.
|
||||||
|
@ -48,6 +51,8 @@ Python code interface:
|
||||||
for this plugin
|
for this plugin
|
||||||
- the class variable "rank" is an integer in the range of 0..100 - it determines the order
|
- the class variable "rank" is an integer in the range of 0..100 - it determines the order
|
||||||
of plugins in listings (lower value -> higher priority)
|
of plugins in listings (lower value -> higher priority)
|
||||||
|
- the class variable "root_action" is None or the module as sourced out of "root_actions.py"
|
||||||
|
in the directory of the plugin - this allows to access constant settings in this file
|
||||||
- volume plugins contain the attribute "device" (you may trust this value - a volume plugin will
|
- volume plugins contain the attribute "device" (you may trust this value - a volume plugin will
|
||||||
never get called with an invalid device)
|
never get called with an invalid device)
|
||||||
- the python module which contains the plugin's class should also contain a class called
|
- the python module which contains the plugin's class should also contain a class called
|
||||||
|
|
|
@ -58,10 +58,12 @@ class CryptoBoxSettings:
|
||||||
self.plugin_conf = self.__get_plugin_config()
|
self.plugin_conf = self.__get_plugin_config()
|
||||||
self.user_db = self.__get_user_db()
|
self.user_db = self.__get_user_db()
|
||||||
self.misc_files = []
|
self.misc_files = []
|
||||||
self.__read_misc_files()
|
self.reload_misc_files()
|
||||||
|
|
||||||
|
|
||||||
def __read_misc_files(self):
|
def reload_misc_files(self):
|
||||||
|
"""Call this method after creating or removing a 'misc' configuration file
|
||||||
|
"""
|
||||||
self.misc_files = self.__get_misc_files()
|
self.misc_files = self.__get_misc_files()
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,6 +94,14 @@ class CryptoBoxSettings:
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def get_misc_config_filename(self, name):
|
||||||
|
"""Return an absolute filename for a given filename 'name'
|
||||||
|
|
||||||
|
'name' should not contain slashes (no directory part!)
|
||||||
|
"""
|
||||||
|
return os.path.join(self.prefs["Locations"]["SettingsDir"], "misc", name)
|
||||||
|
|
||||||
|
|
||||||
def requires_partition(self):
|
def requires_partition(self):
|
||||||
return bool(self.prefs["Main"]["UseConfigPartition"])
|
return bool(self.prefs["Main"]["UseConfigPartition"])
|
||||||
|
|
||||||
|
@ -127,8 +137,10 @@ class CryptoBoxSettings:
|
||||||
return False
|
return False
|
||||||
conf_partitions = self.get_available_partitions()
|
conf_partitions = self.get_available_partitions()
|
||||||
if not conf_partitions:
|
if not conf_partitions:
|
||||||
self.log.error("no configuration partition found - you have to create "
|
self.log.warn("no configuration partition found - you have to create "
|
||||||
+ "it first")
|
+ "it first")
|
||||||
|
#TODO: mount tmpfs in settings directory
|
||||||
|
self.log.info("Ramdisk (tmpfs) mounted as config partition ...")
|
||||||
return False
|
return False
|
||||||
partition = conf_partitions[0]
|
partition = conf_partitions[0]
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
|
|
|
@ -28,6 +28,7 @@ __revision__ = "$Id"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import cherrypy
|
import cherrypy
|
||||||
|
import imp
|
||||||
|
|
||||||
|
|
||||||
class CryptoBoxPlugin:
|
class CryptoBoxPlugin:
|
||||||
|
@ -72,6 +73,12 @@ class CryptoBoxPlugin:
|
||||||
self.defaults = {}
|
self.defaults = {}
|
||||||
self.cbox.log.debug("Plugin '%s': configuration " % self.get_name() + \
|
self.cbox.log.debug("Plugin '%s': configuration " % self.get_name() + \
|
||||||
"settings imported from global config file: %s" % str(self.defaults))
|
"settings imported from global config file: %s" % str(self.defaults))
|
||||||
|
## load a possibly existing "root_action.py" scripts as self.root_action
|
||||||
|
if os.path.isfile(os.path.join(self.plugin_dir, "root_action.py")):
|
||||||
|
self.root_action = imp.load_source("root_action",
|
||||||
|
os.path.join(self.plugin_dir, "root_action.py"))
|
||||||
|
else:
|
||||||
|
self.root_action = None
|
||||||
|
|
||||||
|
|
||||||
def do_action(self, **args):
|
def do_action(self, **args):
|
||||||
|
@ -121,7 +128,7 @@ class CryptoBoxPlugin:
|
||||||
- 20..39 heavy security risk OR broken recommended features
|
- 20..39 heavy security risk OR broken recommended features
|
||||||
- 00..19 possible mild security risk OR broken/missing optional features
|
- 00..19 possible mild security risk OR broken/missing optional features
|
||||||
"""
|
"""
|
||||||
return None
|
return []
|
||||||
|
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
|
|
|
@ -421,9 +421,7 @@ class WebInterfaceSites:
|
||||||
"""
|
"""
|
||||||
warnings = []
|
warnings = []
|
||||||
for pl in self.__plugin_manager.get_plugins():
|
for pl in self.__plugin_manager.get_plugins():
|
||||||
warnings.append(pl.get_warnings())
|
warnings.extend(pl.get_warnings())
|
||||||
## remove empty warnings
|
|
||||||
warnings = [ e for e in warnings if e ]
|
|
||||||
warnings.sort(reverse=True)
|
warnings.sort(reverse=True)
|
||||||
for (index, (warn_prio, warn_text)) in enumerate(warnings):
|
for (index, (warn_prio, warn_text)) in enumerate(warnings):
|
||||||
self.__dataset["Data.EnvironmentWarning.%d" % index] = warn_text
|
self.__dataset["Data.EnvironmentWarning.%d" % index] = warn_text
|
||||||
|
|
Loading…
Reference in a new issue