import CryptoBox import WebInterfaceDataset import re import Plugins from CryptoBoxExceptions import * import cherrypy import types import os try: import neo_cgi, neo_util, neo_cs except ImportError: errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'." self.log.error(errorMsg) sys.stderr.write(errorMsg) raise ImportError, errorMsg class PluginIconHandler: def __init__(self, plugins): for plugin in plugins.getPlugins(): if not plugin: continue plname = plugin.getName() ## expose the getIcon function of this plugin setattr(self, plname, plugin.getIcon) class WebInterfaceSites: ''' ''' ## this template is used under strange circumstances defaultTemplate = "empty" def __init__(self): import logging self.cbox = CryptoBox.CryptoBoxProps() self.log = logging.getLogger("CryptoBox") self.prefs = self.cbox.prefs self.__resetDataset() def __resetDataset(self): """this method has to be called at the beginning of every "site" action important: only at the beginning of an action (to not loose information) important: for _every_ "site" action (cherrypy is stateful) also take care for the plugins, as they also contain datasets """ self.__loadPlugins() self.dataset = WebInterfaceDataset.WebInterfaceDataset(self.cbox, self.prefs, self.pluginList.getPlugins()) ## publish plugin icons self.icons = PluginIconHandler(self.pluginList) self.icons.exposed = True ## check, if a configuration partition has become available self.cbox.prefs.preparePartition() def __loadPlugins(self): self.pluginList = Plugins.PluginManager(self.cbox, self.prefs["Locations"]["PluginDir"]) for plugin in self.pluginList.getPlugins(): if not plugin: continue plname = plugin.getName() if plugin.isEnabled(): self.cbox.log.info("Plugin '%s' loaded" % plname) ## this should be the "easiest" way to expose all plugins as URLs setattr(self, plname, self.return_plugin_action(plugin)) setattr(getattr(self, plname), "exposed", True) # TODO: check, if this really works - for now the "stream_response" feature seems to be broken #setattr(getattr(self, plname), "stream_respones", True) else: self.cbox.log.info("Plugin '%s' is disabled" % plname) ## remove the plugin, if it was active before setattr(self, plname, None) ## this is a function decorator to check authentication ## it has to be defined before any page definition requiring authentification def __requestAuth(self=None): 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 authDict = self.cbox.prefs.userDB["admins"] if user in authDict.keys(): if self.cbox.prefs.userDB.getDigest(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="CryptoBox"''' 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 index(self, weblang=""): self.__resetDataset() self.__setWebLang(weblang) self.__checkEnvironment() ## do not forget the language! param_dict = {"weblang":weblang} ## render "disks" plugin by default return self.return_plugin_action(self.pluginList.getPlugin("disks"))(**param_dict) def return_plugin_action(self, plugin): def handler(self, **args): self.__resetDataset() self.__checkEnvironment() args_orig = dict(args) ## set web interface language try: self.__setWebLang(args["weblang"]) del args["weblang"] except KeyError: self.__setWebLang("") ## we always read the "device" setting - otherwise volume-plugin links ## would not work easily (see "volume_props" linking to "format_fs") ## it will get ignored for non-volume plugins try: plugin.device = None if self.__setDevice(args["device"]): plugin.device = args["device"] del args["device"] except KeyError: pass ## check the device argument of volume plugins if "volume" in plugin.pluginCapabilities: ## initialize the dataset of the selected device if necessary if plugin.device: self.dataset.setCurrentDiskState(plugin.device) else: ## invalid (or missing) device setting return self.__render(self.defaultTemplate) ## check if there is a "redirect" setting - this will override the return ## value of the doAction function (e.g. useful for umount-before-format) try: if args["redirect"]: override_nextTemplate = { "plugin":args["redirect"] } if "volume" in plugin.pluginCapabilities: override_nextTemplate["values"] = {"device":plugin.device} del args["redirect"] except KeyError: override_nextTemplate = None ## call the plugin handler nextTemplate = plugin.doAction(**args) ## for 'volume' plugins: reread the dataset of the current disk ## additionally: set the default template for plugins if "volume" in plugin.pluginCapabilities: ## maybe the state of the current volume was changed? self.dataset.setCurrentDiskState(plugin.device) if not nextTemplate: nextTemplate = { "plugin":"volume_mount", "values":{"device":plugin.device}} else: ## maybe a non-volume plugin changed some plugin settings (e.g. plugin_manager) self.dataset.setPluginData() ## update the container hdf-dataset (maybe a plugin changed the state of a container) self.dataset.setContainersState() ## default page for non-volume plugins is the disk selection if not nextTemplate: nextTemplate = { "plugin":"disks", "values":{} } ## was a redirect requested? if override_nextTemplate: nextTemplate = override_nextTemplate ## if another plugins was choosen for 'nextTemplate', then do it! if isinstance(nextTemplate, types.DictType) \ and "plugin" in nextTemplate.keys() \ and "values" in nextTemplate.keys() \ and self.pluginList.getPlugin(nextTemplate["plugin"]): valueDict = dict(nextTemplate["values"]) ## force the current weblang attribute - otherwise it gets lost valueDict["weblang"] = self.dataset["Settings.Language"] new_plugin = self.pluginList.getPlugin(nextTemplate["plugin"]) return self.return_plugin_action(new_plugin)(**valueDict) ## save the currently active plugin name self.dataset["Data.ActivePlugin"] = plugin.getName() return self.__render(nextTemplate, plugin) ## apply authentication? if plugin.isAuthRequired(): return lambda **args: self.__requestAuth()(handler)(self, **args) else: return lambda **args: handler(self, **args) ## test authentication @cherrypy.expose @__requestAuth def test(self, weblang=""): self.__resetDataset() self.__setWebLang(weblang) self.__checkEnvironment() 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 "