unittests for CryptoBoxTools
mount/umount moved to separate volume plugins volume name change moved to 'volume_props' plugin webinterface for password change (luks) added attribute "pluginCapabilities" added to plugins attribute "requestAuth" added to plugins http authentication implemented (for now: static user database)
This commit is contained in:
parent
ca13aebdc8
commit
9321677078
9 changed files with 226 additions and 216 deletions
|
@ -3,6 +3,10 @@ import WebInterfaceDataset
|
|||
import re
|
||||
import Plugins
|
||||
from CryptoBoxExceptions import *
|
||||
import cherrypy
|
||||
|
||||
# TODO: for now the admin access is defined statically
|
||||
authDict = {"test": "tester"}
|
||||
|
||||
|
||||
class WebInterfacePlugins:
|
||||
|
@ -57,10 +61,48 @@ class WebInterfaceSites:
|
|||
return False
|
||||
|
||||
|
||||
## this is a function decorator to check authentication
|
||||
## it has to be defined before any page definition requiring authentification
|
||||
def __requestAuth(self, authDict):
|
||||
def check_credentials(site):
|
||||
def _inner_wrapper(self, *args, **kargs):
|
||||
import base64
|
||||
## define a "non-allowed" function
|
||||
user, password = None, None
|
||||
try:
|
||||
resp = cherrypy.request.headers["Authorization"][6:] # ignore "Basic "
|
||||
(user, password) = base64.b64decode(resp).split(":",1)
|
||||
except KeyError:
|
||||
## no "authorization" header was sent
|
||||
pass
|
||||
except TypeError:
|
||||
## invalid base64 string
|
||||
pass
|
||||
except AttributeError:
|
||||
## no cherrypy response header defined
|
||||
pass
|
||||
if user in authDict.keys():
|
||||
if password == authDict[user]:
|
||||
## ok: return the choosen page
|
||||
self.cbox.log.info("access granted for: %s" % user)
|
||||
return site(self, *args, **kargs)
|
||||
else:
|
||||
self.cbox.log.info("wrong password supplied for: %s" % user)
|
||||
else:
|
||||
self.cbox.log.info("unknown user: %s" % str(user))
|
||||
## wrong credentials: return "access denied"
|
||||
cherrypy.response.headers["WWW-Authenticate"] = '''Basic realm="Test-Arena"'''
|
||||
cherrypy.response.status = 401
|
||||
return self.__render("access_denied")
|
||||
return _inner_wrapper
|
||||
return check_credentials
|
||||
|
||||
|
||||
######################################################################
|
||||
## put real sites down here and don't forget to expose them at the end
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def status(self, weblang=""):
|
||||
'''shows the current status of the box
|
||||
'''
|
||||
|
@ -79,6 +121,7 @@ class WebInterfaceSites:
|
|||
return self.__render("show_status")
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def doc(self,page="",weblang=""):
|
||||
'''prints the offline wikipage
|
||||
'''
|
||||
|
@ -96,18 +139,21 @@ class WebInterfaceSites:
|
|||
return self.__render("show_doc")
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def system(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
return self.__render("form_system")
|
||||
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
return self.__render("show_status")
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def show_volume(self, device="", weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
|
@ -120,204 +166,75 @@ class WebInterfaceSites:
|
|||
return self.__render("show_status")
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def show_volumes(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
return self.__render("show_volumes")
|
||||
|
||||
|
||||
def volume_name_set(self, device="", volume_name="", weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if self.__setDevice(device):
|
||||
volume_name = volume_name.strip()
|
||||
if self.__checkVolumeName(volume_name):
|
||||
container = self.cbox.getContainer(device)
|
||||
try:
|
||||
container.setName(volume_name)
|
||||
except CBContainerError, errMsg:
|
||||
self.log.warn("failed to rename the volume '%s' to '%s: %s'" % (device, volume_name, errMsg))
|
||||
self.dataset["Data.Warning"] = "SetVolumeNameFailed"
|
||||
else:
|
||||
self.log.info("successfully renamed volume '%s' to '%s'" % (device, volume_name))
|
||||
self.dataset.setCurrentDiskState(device)
|
||||
else:
|
||||
self.dataset["Data.Warning"] = "InvalidVolumeName"
|
||||
return self.__render("show_volume")
|
||||
else:
|
||||
if self.cbox.getContainerList():
|
||||
return self.__render("show_volumes")
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
|
||||
|
||||
def mount_do(self, device, crypto_password=None, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if self.__setDevice(device):
|
||||
container = self.cbox.getContainer(device)
|
||||
if container.isMounted():
|
||||
self.dataset["Data.Warning"] = "IsMounted"
|
||||
self.log.warn("the device (%s) is already mounted" % device)
|
||||
else:
|
||||
try:
|
||||
if container.getType() == container.Types["luks"]:
|
||||
## encrypted luks container
|
||||
if not crypto_password:
|
||||
self.dataset["Data.Warning"] = "EmptyCryptoPassword"
|
||||
self.log.warn("no password was supplied for mounting of device '%s'" % device)
|
||||
return self.__render("show_volume")
|
||||
else:
|
||||
container.mount(crypto_password)
|
||||
elif container.getType() == container.Types["plain"]:
|
||||
## plain container
|
||||
container.mount()
|
||||
else:
|
||||
## mounting is not possible
|
||||
self.dataset["Data.Warning"] = "InvalidType"
|
||||
self.log.warn("this type of container (%s) cannot be mounted - sorry!" % device)
|
||||
except (Exception, "MountError"):
|
||||
self.dataset["Data.Warning"] = "MountFailed"
|
||||
self.log.warn("failed to mount the device (%s)" % device)
|
||||
else:
|
||||
self.log.info("successfully mounted the container (%s)" % device)
|
||||
self.dataset.setCurrentDiskState(device)
|
||||
else:
|
||||
if self.cbox.getContainerList():
|
||||
return self.__render("show_volumes")
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
return self.__render("show_volume")
|
||||
|
||||
|
||||
def volume_init_ask(self, device, encryption=None, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if self.__setDevice(device):
|
||||
container = self.cbox.getContainer(device)
|
||||
if container.isMounted():
|
||||
self.dataset["Data.Warning"] = "VolumeMayNotBeMounted"
|
||||
self.log.warn("initialization is not possible as long as the device (%s) is mounted" % device)
|
||||
return self.__render("show_volume")
|
||||
else:
|
||||
if encryption is None:
|
||||
self.dataset["Data.Init.isCrypto"] = 0
|
||||
else:
|
||||
self.dataset["Data.Init.isCrypto"] = 1
|
||||
return self.__render("form_init")
|
||||
else:
|
||||
if self.cbox.getContainerList():
|
||||
return self.__render("show_volumes")
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
|
||||
|
||||
def init_do(self, device, confirm="", crypto_password=None, crypto_password2=None, encryption=None, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if self.__setDevice(device):
|
||||
container = self.cbox.getContainer(device)
|
||||
## set 'Data.Init.isCrypto' - just in case, we have to show the same form again
|
||||
if encryption is None:
|
||||
self.dataset["Data.Init.isCrypto"] = 0
|
||||
else:
|
||||
self.dataset["Data.Init.isCrypto"] = 1
|
||||
if container.isMounted():
|
||||
self.dataset["Data.Warning"] = "VolumeMayNotBeMounted"
|
||||
self.log.warn("initialization is not possible as long as the device (%s) is mounted" % device)
|
||||
return self.__render("form_init")
|
||||
else:
|
||||
if confirm != self.__getLanguageValue("Text.ConfirmInit"):
|
||||
self.dataset["Data.Warning"] = "InitNotConfirmed"
|
||||
self.log.warn("the confirmation sentence for initialization of the device '%s' was wrong" % device)
|
||||
return self.__render("form_init")
|
||||
try:
|
||||
if not encryption is None:
|
||||
if not crypto_password:
|
||||
self.dataset["Data.Warning"] = "EmptyCryptoPassword"
|
||||
self.log.warn("no crypto password was supplied for initialization of device '%s'" % device)
|
||||
return self.__render("form_init")
|
||||
if crypto_password != crypto_password2:
|
||||
self.dataset["Data.Warning"] = "DifferentCryptoPasswords"
|
||||
self.log.warn("the crypto password was not repeated correctly for initialization of device '%s'" % device)
|
||||
return self.__render("form_init")
|
||||
container.create(container.Types["luks"], crypto_password)
|
||||
else:
|
||||
container.create(container.Types["plain"])
|
||||
except CBContainerError, errMsg:
|
||||
self.dataset["Data.Warning"] = "CreateFailed"
|
||||
self.log.warn("initialization of device '%s' failed" % device)
|
||||
self.log.warn("reason: %s" % errMsg)
|
||||
return self.__render("form_init")
|
||||
else:
|
||||
self.log.info("successfully initialized device '%s'" % device)
|
||||
# reread the dataset
|
||||
self.dataset.setCurrentDiskState(device)
|
||||
return self.__render("show_volume")
|
||||
else:
|
||||
if self.cbox.getContainerList():
|
||||
return self.__render("show_volumes")
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
|
||||
|
||||
def test(self, weblang=""):
|
||||
import cherrypy
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
return "test passed"
|
||||
|
||||
|
||||
def umount_do(self, device, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if self.__setDevice(device):
|
||||
container = self.cbox.getContainer(device)
|
||||
if not container.isMounted():
|
||||
self.dataset["Data.Warning"] = "NotMounted"
|
||||
self.log.warn("the device (%s) is currently not mounted" % device)
|
||||
else:
|
||||
try:
|
||||
if container.getType() == container.Types["luks"]:
|
||||
## encrypted luks container
|
||||
container.umount()
|
||||
elif container.getType() == container.Types["plain"]:
|
||||
## plain container
|
||||
container.umount()
|
||||
else:
|
||||
## umounting is not possible
|
||||
self.dataset["Data.Warning"] = "InvalidType"
|
||||
self.log.warn("this type of container (%s) cannot be umounted - sorry!" % device)
|
||||
except (Exception, "UmountError"):
|
||||
self.dataset["Data.Warning"] = "UmountFailed"
|
||||
self.log.warn("failed to unmount the device (%s)" % device)
|
||||
else:
|
||||
self.log.info("successfully unmounted the container (%s)" % device)
|
||||
# reread the dataset
|
||||
self.dataset.setCurrentDiskState(device)
|
||||
else:
|
||||
if self.cbox.getContainerList():
|
||||
return self.__render("show_volumes")
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
return self.__render("show_volume")
|
||||
|
||||
|
||||
def return_plugin_action(self, plugin):
|
||||
def handler(**args):
|
||||
def handler(self, **args):
|
||||
self.__resetDataset()
|
||||
try:
|
||||
self.__setWebLang(args["weblang"])
|
||||
del args["weblang"]
|
||||
except KeyError:
|
||||
pass
|
||||
## check the device argument of volume plugins
|
||||
if "volume" in plugin.pluginCapabilities:
|
||||
try:
|
||||
## initialize the dataset of the selected device if necessary
|
||||
if self.__setDevice(args["device"]):
|
||||
plugin.device = args["device"]
|
||||
self.dataset.setCurrentDiskState(plugin.device)
|
||||
else:
|
||||
return self.__render("show_status")
|
||||
except KeyError:
|
||||
return self.__render("show_status")
|
||||
else:
|
||||
## the parameter 'device' exists - we have to remove it
|
||||
del args["device"]
|
||||
## call the plugin handler
|
||||
nextTemplate = plugin.doAction(**args)
|
||||
## set the default template
|
||||
if not nextTemplate: nextTemplate = "form_system"
|
||||
## for 'volume' plugins: reread the dataset of the current disk
|
||||
## additionally: set the default template for plugins
|
||||
if "volume" in plugin.pluginCapabilities:
|
||||
self.dataset.setCurrentDiskState(plugin.device)
|
||||
if not nextTemplate: nextTemplate = "show_volume"
|
||||
else:
|
||||
if not nextTemplate: nextTemplate = "form_system"
|
||||
## save the currently active plugin name
|
||||
self.dataset["Data.ActivePlugin"] = plugin.getName()
|
||||
return self.__render(nextTemplate, plugin)
|
||||
return handler
|
||||
## apply authentication?
|
||||
if plugin.requestAuth:
|
||||
return lambda **args: self.__requestAuth(authDict)(handler)(self, **args)
|
||||
else:
|
||||
return lambda **args: handler(self, **args)
|
||||
|
||||
|
||||
## test authentication
|
||||
@cherrypy.expose
|
||||
@__requestAuth(None, authDict)
|
||||
def test(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
return "test passed"
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def test_stream(self):
|
||||
"""just for testing purposes - to check if the "stream_response" feature
|
||||
actually works - for now (September 02006) it does not seem to be ok"""
|
||||
import time
|
||||
yield "<html><head><title>neu</title></head><body><p><ul>"
|
||||
for a in range(10):
|
||||
yield "<li>yes: %d - %s</li>" % (a, str(time.time()))
|
||||
time.sleep(1)
|
||||
yield "</ul></p></html>"
|
||||
|
||||
|
||||
|
||||
##################### input checker ##########################
|
||||
def __setWebLang(self, value):
|
||||
|
@ -453,6 +370,7 @@ class WebInterfaceSites:
|
|||
plugin_cs_file = plugin.getTemplateFileName(template)
|
||||
if plugin_cs_file:
|
||||
self.dataset["Settings.TemplateFile"] = plugin_cs_file
|
||||
|
||||
## add the current state of the plugins to the hdf dataset
|
||||
self.dataset["Data.Status.Plugins.%s" % plugin.getName()] = plugin.getStatus()
|
||||
## load the language data
|
||||
|
@ -494,31 +412,3 @@ class WebInterfaceSites:
|
|||
yield line + "\n"
|
||||
|
||||
|
||||
def test_stream(self):
|
||||
"""just for testing purposes - to check if the "stream_response" feature
|
||||
actually works - for now (September 02006) it does not seem to be ok"""
|
||||
import time
|
||||
yield "<html><head><title>neu</title></head><body><p><ul>"
|
||||
for a in range(10):
|
||||
yield "<li>yes: %d - %s</li>" % (a, str(time.time()))
|
||||
time.sleep(1)
|
||||
yield "</ul></p></html>"
|
||||
|
||||
|
||||
############################################################################
|
||||
## to make the sites visible through the webserver they must be exposed here
|
||||
index.exposed = True
|
||||
doc.exposed = True
|
||||
system.exposed = True
|
||||
status.exposed = True
|
||||
show_volume.exposed = True
|
||||
volume_name_set.exposed = True
|
||||
mount_do.exposed = True
|
||||
volume_init_ask.exposed = True
|
||||
init_do.exposed = True
|
||||
umount_do.exposed = True
|
||||
show_volumes.exposed = True
|
||||
test.exposed = True
|
||||
test_stream.exposed = True
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue