Example #1
0
def server_start():
    from optparse import OptionParser

    p = OptionParser()
    p.add_option('-d',
                 action="store_true",
                 dest='daemonize',
                 help="Run the server as a daemon")
    p.add_option('-q',
                 '--quiet',
                 action="store_true",
                 dest='quiet',
                 help="Don't log to console")
    p.add_option('-p',
                 '--pidfile',
                 dest='pidfile',
                 default=None,
                 help="Store the process id in the given file")
    p.add_option('--config',
                 dest='config',
                 default=None,
                 help="Path to config.ini file")
    p.add_option('--datadir',
                 dest='datadir',
                 default=None,
                 help="Path to the data directory")

    options, args = p.parse_args()

    if options.datadir:
        datadir = options.datadir

        if not os.path.isdir(datadir):
            os.makedirs(datadir)

    else:
        datadir = rundir

    datadir = os.path.abspath(datadir)

    if not os.access(datadir, os.W_OK):
        raise SystemExit("Data dir must be writeable '" + datadir + "'")

    import app.config
    app.config.DATADIR = datadir

    if options.config:
        config = options.config
    else:
        config = os.path.join(datadir, 'config.ini')

    config = os.path.abspath(config)

    if not os.access(os.path.dirname(config), os.W_OK) and not os.access(
            config, os.W_OK):
        if not os.path.exists(os.path.dirname(config)):
            os.makedirs(os.path.dirname(config))
        else:
            raise SystemExit("Directory for config file must be writeable")

    import cherrypy
    import app.config.render

    # Configure logging
    from app.config.cplog import CPLog

    # Setup logging
    debug = os.path.isfile(os.path.join(datadir, 'debug.conf'))
    log = CPLog()
    log.config(os.path.join(datadir, 'logs'), debug)

    # Create cache dir
    cachedir = os.path.join(datadir, 'cache')
    if not os.path.isdir(cachedir):
        os.mkdir(cachedir)

    # Stop logging
    if options.quiet or options.daemonize:
        cherrypy.config.update({'log.screen': False})

    # Config app
    from app.config.configApp import configApp
    ca = configApp(config)

    # Setup db
    from app.config.db import initDb
    initDb()

    from app.config.routes import setup as Routes
    from app.lib.cron import CronJobs
    from app.config.updater import Updater
    from cherrypy.process import plugins

    # Check an see if CP is already running
    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    host = ca.get('global', 'host')
    port = int(ca.get('global', 'port'))
    try:
        s.connect((host, port))
        s.shutdown(0)
        app.launchBrowser(host, port)
        return
    except:
        pass

    # Start threads
    myCrons = CronJobs(cherrypy.engine, ca, debug)
    myCrons.subscribe()

    # Update script
    myUpdater = Updater(cherrypy.engine)
    myUpdater.subscribe()

    # User config, use own stuff to prevent unexpected results
    cherrypy.config.update({
        'global': {
            'server.thread_pool': 10,
            'server.socket_port': int(ca.get('global', 'port')),
            'server.socket_host': ca.get('global', 'host'),
            'server.environment': ca.get('global', 'server.environment'),
            'engine.autoreload_on':
            ca.get('global', 'server.environment') == 'development',
            'tools.mako.collection_size': 500,
            'tools.mako.directories': os.path.join(path_base, 'app', 'views'),
            'basePath': path_base,
            'runPath': rundir,
            'cachePath': cachedir,
            'debug': debug,
            'frozen': frozen,

            # Global workers
            'config': ca,
            'updater': myUpdater,
            'cron': myCrons.threads,
            'searchers': myCrons.searchers,
            'flash': app.flash()
        }
    })

    # Static config
    conf = {
        '/': {
            'request.dispatch':
            Routes(),
            'tools.sessions.on':
            True,
            'tools.sessions.timeout':
            240,
            'tools.gzip.on':
            True,
            'tools.gzip.mime_types': [
                'text/html', 'text/plain', 'text/css', 'text/javascript',
                'application/javascript'
            ]
        },
        '/media': {
            'tools.staticdir.on': True,
            'tools.staticdir.root': path_base,
            'tools.staticdir.dir': "media",
            'tools.expires.on': True,
            'tools.expires.secs': 3600 * 24 * 7
        },
        '/cache': {
            'tools.staticdir.on': True,
            'tools.staticdir.root': datadir,
            'tools.staticdir.dir': "cache",
            'tools.expires.on': True,
            'tools.expires.secs': 3600 * 24 * 7
        }
    }

    # Don't use auth when password is empty
    if ca.get('global', 'password') != '':
        conf['/'].update({
            'tools.basic_auth.on': True,
            'tools.basic_auth.realm': 'Awesomeness',
            'tools.basic_auth.users': {
                ca.get('global', 'username'): ca.get('global', 'password')
            },
            'tools.basic_auth.encrypt': app.clearAuthText
        })
        cherrypy.tools.mybasic_auth = cherrypy.Tool('on_start_resource',
                                                    app.basicAuth)

    # I'll do my own logging, thanks!
    #cherrypy.log.error_log.propagate = False
    #cherrypy.log.access_log.propagate = False

    #No Root controller as we provided all our own.
    cherrypy.tree.mount(root=None, config=conf)

    #HTTP Errors
    def http_error_hander(status, message, traceback, version):
        args = [status, message, traceback, version]
        return "<html><body><h1>Error %s</h1>Something unexpected has happened.</body></html>" % args[
            0]

    cherrypy.config.update({'error_page.default': http_error_hander})

    # Deamonize
    if options.daemonize:
        plugins.Daemonizer(cherrypy.engine).subscribe()

    # PIDfile
    if options.pidfile:
        plugins.PIDFile(cherrypy.engine, options.pidfile).subscribe()

    # Setup the signal handler
    if hasattr(cherrypy.engine, "signal_handler"):
        cherrypy.engine.signal_handler.subscribe()
    if hasattr(cherrypy.engine, "console_control_handler"):
        cherrypy.engine.console_control_handler.subscribe()

    ## start the app
    try:
        cherrypy.engine.start()
    except:
        sys.exit(1)
    else:

        # Launch browser
        if ca.get('global', 'launchbrowser'):
            app.launchBrowser(ca.get('global', 'host'),
                              ca.get('global', 'port'))

        cherrypy.engine.block()
Example #2
0
    Renders a mako template to HTML and
    sets the CherryPy response's body with it.
    """
    if cherrypy.response.status > 399:
        return

    data = cherrypy.response.body or {}
    template = lookup.get_template(template)

    if template and isinstance(data, dict):
        cherrypy.response.body = template.render(**data)


# Creating our tool so that they can be
# used below in the CherryPy applications
cherrypy.tools.render = cherrypy.Tool('before_finalize', render_template)
cherrypy.tools.websocket = WebSocketTool()


# Web Application
class SharedDrawingBoardApp(object):
    @cherrypy.expose
    @cherrypy.tools.render(template='index.html')
    def index(self):
        return {'boardid': str(uuid.uuid4())[:4], 'baseurl': BASE_URL}

    @cherrypy.expose
    @cherrypy.tools.render(template='board.html')
    def board(self, board_id):
        bus.websockets.register_board(board_id)
        return {
Example #3
0
            "tools.addheader.on": True
        }


def addheader(*args, **kwargs):
    "This function's only purpose is to tell the browser to cache requests for an hour"
    cherrypy.response.headers['Cache-Control'] = "max-age=3600"
    #del cherrypy.response.headers['Expires']


def pageloadnotify(*args, **kwargs):
    systasks.aPageJustLoaded()


cherrypy.config.update(site_config)
cherrypy.tools.pageloadnotify = cherrypy.Tool('on_start_resource',
                                              pageloadnotify)
cherrypy.config['tools.pageloadnotify.on'] = True

cherrypy.tools.addheader = cherrypy.Tool('before_finalize', addheader)

if hasattr(cherrypy.engine, 'signal_handler'):
    cherrypy.engine.signal_handler.subscribe()

cherrypy.tree.mount(root, config=cnf)

#As far as I can tell, this second server inherits everything from the "implicit" server
#except what we override.
server2 = cherrypy._cpserver.Server()
server2.socket_port = config['http-port']
server2._socket_host = bindto
server2.thread_pool = config['http-thread-pool']
Example #4
0
    def _configureCherryPy(self):
        """
        _configureCherryPy_
        Configure the CherryPy server, ignoring items in the configuration file that
        aren't CherryPy configurables.
        """
        configDict = self.serverConfig.dictionary_()

        # If you add configurables update the testLongHandConfigurables in Root_t
        configurables = [
            'engine', 'hooks', 'log', 'request', 'response', 'server', 'tools',
            'wsgi', 'checker'
        ]
        # Deal with "long hand" configuration variables
        for i in configurables:
            if i in configDict.keys():
                for config_param, param_value in configDict[i].dictionary_(
                ).items():
                    if isinstance(param_value, ConfigSection):
                        # TODO: make this loads better
                        for child_param, child_param_value in param_value.dictionary_(
                        ).items():
                            cherrypy.config["%s.%s.%s" %
                                            (i, config_param,
                                             child_param)] = child_param_value
                    elif type(param_value) in [type('string'), type(123)]:
                        cherrypy.config["%s.%s" %
                                        (i, config_param)] = param_value
                    else:
                        raise Exception("Unsupported configuration type: %s" %
                                        type(v))

        # which we then over write with short hand variables if necessary
        cherrypy.config["server.environment"] = configDict.get(
            "environment", "production")

        #Set up the tools and the logging
        cherrypy.tools.time = cherrypy.Tool('on_start_resource', mytime)
        cherrypy.config.update({'tools.time.on': True})

        if configDict.get("proxy_base", False):
            cherrypy.tools.proxy = cherrypy.Tool('before_request_body',
                                                 myproxy,
                                                 priority=30)
            cherrypy.config.update({
                'tools.proxy.on': True,
                'tools.proxy.base': configDict["proxy_base"]
            })

        cherrypy.log = WTLogger()
        cherrypy.config["log.screen"] = bool(
            configDict.get("log_screen", False))

        cherrypy.config.update({
            'tools.expires.on':
            True,
            'tools.expires.secs':
            configDict.get("expires", 300),
            'tools.response_headers.on':
            True,
            'tools.etags.on':
            True,
            'tools.etags.autotags':
            True,
            'tools.encode.on':
            True,
            'tools.gzip.on':
            True,
        })

        if cherrypy.config["server.environment"] == "production":
            # If we're production these should be set regardless
            cherrypy.config["request.show_tracebacks"] = False
            cherrypy.config["engine.autoreload_on"] = False
            # In production mode only allow errors at WARNING or greater to the log
            err_lvl = max((configDict.get("error_log_level",
                                          logging.WARNING), logging.WARNING))
            acc_lvl = max((configDict.get("access_log_level",
                                          logging.INFO), logging.INFO))
            cherrypy.log.error_log.setLevel(err_lvl)
            cherrypy.log.access_log.setLevel(acc_lvl)
        else:
            print
            print 'THIS BETTER NOT BE A PRODUCTION SERVER'
            print
            cherrypy.config["request.show_tracebacks"] = configDict.get(
                "show_tracebacks", False)
            cherrypy.config["engine.autoreload_on"] = configDict.get(
                "autoreload", False)
            # Allow debug output
            cherrypy.log.error_log.setLevel(
                configDict.get("error_log_level", logging.DEBUG))
            cherrypy.log.access_log.setLevel(
                configDict.get("access_log_level", logging.DEBUG))

        default_port = 8080
        if "server.socket_port" in cherrypy.config.keys():
            default_port = cherrypy.config["server.socket_port"]
        cherrypy.config["server.thread_pool"] = configDict.get(
            "thread_pool", 10)
        cherrypy.config["server.socket_port"] = configDict.get(
            "port", default_port)
        cherrypy.config["server.socket_host"] = configDict.get(
            "host", "0.0.0.0")
        #A little hacky way to pass the expire second to config
        self.appconfig.default_expires = cherrypy.config["tools.expires.secs"]

        # SecurityModule config
        # Registers secmodv2 into cherrypy.tools so it can be used through
        # decorators
        if self.secconfig.dictionary_().get('dangerously_insecure', False):
            cherrypy.tools.secmodv2 = NullAuth(self.secconfig)
        else:
            cherrypy.tools.secmodv2 = FrontEndAuth(self.secconfig)
            if hasattr(self.secconfig, "default"):
                # If the 'default' section is present, it will force the
                # authn/z to be called even for non-decorated methods
                cherrypy.config.update({
                    'tools.secmodv2.on':
                    True,
                    'tools.secmodv2.role':
                    self.secconfig.default.role,
                    'tools.secmodv2.group':
                    self.secconfig.default.group,
                    'tools.secmodv2.site':
                    self.secconfig.default.site
                })
        cherrypy.log.error_log.debug('Application %s initialised in %s mode' %
                                     (self.app, self.mode))
Example #5
0
    def _validate_event_scheduled_failed(self, event):
        if 'message' not in event:
            raise cherrypy.HTTPError(400, 'Missing message')


def actually_decode():
    """
	CherryPy decode tool doesn't actually decode anything unless the body
	is multipart. This tool is different and will decode the body.
	"""
    # assume UTF-8 and to hell with the specs
    dec = codecs.getincrementaldecoder('utf-8')()
    cherrypy.request.body = map(dec.decode, cherrypy.request.body)


adt = cherrypy.Tool('before_handler', actually_decode)
cherrypy.tools.actually_decode = adt


class Server(object):
    queue = []

    new_relic = NewRelic()
    kiln = Kiln()
    jenkins = Jenkins()
    fogbugz = FogBugz()
    bitbucket = BitBucket()
    velociraptor = Velociraptor()

    @classmethod
    def send_to(cls, channel, *msgs):
Example #6
0
class App(object):
    @cherrypy.expose
    def __init__(self):
        self.auth = AuthController()
        self.postprocessing = Postprocessing()
        self.api = api.API()

        if core.CONFIG['Server']['authrequired']:
            self._cp_config = {'auth.require': []}

        self.ajax = ajax.Ajax()
        localization.get()
        localization.install()

        # point server toward custom 404
        cherrypy.config.update({'error_page.404': self.error_page_404})

        if core.CONFIG['Server']['checkupdates']:
            scheduler.AutoUpdateCheck.update_check(install=False)

    def https_redirect(self=None):
        ''' Cherrypy tool to redirect http:// to https://

        Use as before_handler when https is enabled for the server.

        Enable in config as {'tools.https_redirect.on': True}

        '''
        if cherrypy.request.scheme == 'http':
            raise cherrypy.HTTPRedirect(cherrypy.url().replace(
                'http:', 'https:'),
                                        status=302)

    cherrypy.tools.https_redirect = cherrypy.Tool('before_handler',
                                                  https_redirect)

    def defaults(self):
        defaults = {
            'head': self.head(),
            'navbar':
            self.nav_bar(current=sys._getframe().f_back.f_code.co_name),
            'url_base': core.URL_BASE
        }
        return defaults

    # All dispatching methods from here down

    status_template = Template(filename='templates/library/status.html',
                               module_directory=core.MAKO_CACHE)
    manage_template = Template(filename='templates/library/manage.html',
                               module_directory=core.MAKO_CACHE)
    import_template = Template(filename='templates/library/import.html',
                               module_directory=core.MAKO_CACHE)
    couchpotato_template = Template(
        filename='templates/library/import/couchpotato.html',
        module_directory=core.MAKO_CACHE)
    kodi_template = Template(filename='templates/library/import/kodi.html',
                             module_directory=core.MAKO_CACHE)
    plex_template = Template(filename='templates/library/import/plex.html',
                             module_directory=core.MAKO_CACHE)
    directory_template = Template(
        filename='templates/library/import/directory.html',
        module_directory=core.MAKO_CACHE)
    stats_template = Template(filename='templates/library/stats.html',
                              module_directory=core.MAKO_CACHE)

    add_movie_template = Template(filename='templates/add_movie.html',
                                  module_directory=core.MAKO_CACHE)

    server_template = Template(filename='templates/settings/server.html',
                               module_directory=core.MAKO_CACHE)
    search_template = Template(filename='templates/settings/search.html',
                               module_directory=core.MAKO_CACHE)
    quality_template = Template(filename='templates/settings/quality.html',
                                module_directory=core.MAKO_CACHE)
    indexers_template = Template(filename='templates/settings/indexers.html',
                                 module_directory=core.MAKO_CACHE)
    downloader_template = Template(
        filename='templates/settings/downloader.html',
        module_directory=core.MAKO_CACHE)
    postprocessing_template = Template(
        filename='templates/settings/postprocessing.html',
        module_directory=core.MAKO_CACHE)
    plugins_template = Template(filename='templates/settings/plugins.html',
                                module_directory=core.MAKO_CACHE)
    logs_template = Template(filename='templates/settings/logs.html',
                             module_directory=core.MAKO_CACHE)

    system_template = Template(filename='templates/system.html',
                               module_directory=core.MAKO_CACHE)
    shutdown_template = Template(filename='templates/system/shutdown.html',
                                 module_directory=core.MAKO_CACHE)
    restart_template = Template(filename='templates/system/restart.html',
                                module_directory=core.MAKO_CACHE)
    update_template = Template(filename='templates/system/update.html',
                               module_directory=core.MAKO_CACHE)

    fourohfour_template = Template(filename='templates/404.html',
                                   module_directory=core.MAKO_CACHE)
    head_template = Template(filename='templates/head.html',
                             module_directory=core.MAKO_CACHE)
    navbar_template = Template(filename='templates/navbar.html',
                               module_directory=core.MAKO_CACHE)

    @cherrypy.expose
    def default(self):
        return self.library('status')

    @cherrypy.expose
    def _test(self):
        return 'This is not the page you are looking for.'

    @cherrypy.expose
    def library(self, *path):
        page = path[0] if len(path) > 0 else 'status'

        if page == 'status':
            if core.CONFIG['Server']['hidefinished']:
                movie_count = core.sql.get_library_count(hide_finished=True)
                hidden_count = core.sql.get_library_count() - movie_count
            else:
                movie_count = core.sql.get_library_count()
                hidden_count = 0
            return App.status_template.render(
                profiles=core.CONFIG['Quality']['Profiles'].keys(),
                movie_count=movie_count,
                hidden_count=hidden_count,
                **self.defaults())
        elif page == 'manage':
            movies = core.sql.get_user_movies()
            return App.manage_template.render(
                movies=movies,
                profiles=core.CONFIG['Quality']['Profiles'].keys(),
                **self.defaults())
        elif page == 'import':
            subpage = path[1] if len(path) > 1 else None

            if not subpage:
                return App.import_template.render(**self.defaults())
            elif subpage == 'couchpotato':
                return App.couchpotato_template.render(
                    sources=core.SOURCES,
                    profiles=core.CONFIG['Quality']['Profiles'].keys(),
                    **self.defaults())
            elif subpage == 'kodi':
                return App.kodi_template.render(
                    sources=core.SOURCES,
                    profiles=core.CONFIG['Quality']['Profiles'].keys(),
                    **self.defaults())
            elif subpage == 'plex':
                return App.plex_template.render(
                    sources=core.SOURCES,
                    profiles=core.CONFIG['Quality']['Profiles'].keys(),
                    **self.defaults())
            elif subpage == 'directory':
                try:
                    start_dir = os.path.expanduser('~')
                    file_list = [
                        i for i in os.listdir(start_dir)
                        if os.path.isdir(os.path.join(start_dir, i))
                        and not i.startswith('.')
                    ]
                except Exception as e:
                    start_dir = core.PROG_PATH
                    file_list = [
                        i for i in os.listdir(start_dir)
                        if os.path.isdir(os.path.join(start_dir, i))
                        and not i.startswith('.')
                    ]
                file_list.append('..')
                return App.directory_template.render(
                    sources=core.SOURCES,
                    profiles=core.CONFIG['Quality']['Profiles'].keys(),
                    current_dir=start_dir,
                    file_list=file_list,
                    **self.defaults())
            else:
                return self.error_page_404()
        elif page == 'stats':
            return App.stats_template.render(**self.defaults())
        else:
            return self.error_page_404()

    @cherrypy.expose
    def add_movie(self):
        return App.add_movie_template.render(profiles=[
            i for i in core.CONFIG['Quality']['Profiles'] if i != 'Default'
        ],
                                             **self.defaults())

    @cherrypy.expose
    def settings(self, *path):
        page = path[0] if len(path) > 0 else 'server'
        tor = torrent.Torrent()
        if page == 'server':
            themes = [
                i[:-4] for i in os.listdir('static/css/themes/')
                if i.endswith('.css') and os.path.isfile(
                    os.path.join(core.PROG_PATH, 'static/css/themes', i))
            ]
            return App.server_template.render(config=core.CONFIG['Server'],
                                              themes=themes,
                                              version=core.CURRENT_HASH or '',
                                              languages=core.LANGUAGES.keys(),
                                              **self.defaults())
        elif page == 'search':
            return App.search_template.render(config=core.CONFIG['Search'],
                                              **self.defaults())
        elif page == 'quality':
            return App.quality_template.render(config=core.CONFIG['Quality'],
                                               sources=core.SOURCES,
                                               **self.defaults())
        elif page == 'indexers':
            return App.indexers_template.render(
                config=core.CONFIG['Indexers'],
                providers=tor.get_torrent_providers(),
                **self.defaults())
        elif page == 'downloader':
            return App.downloader_template.render(
                config=core.CONFIG['Downloader'], **self.defaults())
        elif page == 'postprocessing':
            return App.postprocessing_template.render(
                config=core.CONFIG['Postprocessing'],
                os=core.PLATFORM,
                **self.defaults())
        elif page == 'plugins':
            plugs = plugins.list_plugins()
            return App.plugins_template.render(config=core.CONFIG['Plugins'],
                                               plugins=plugs,
                                               **self.defaults())
        elif page == 'logs':
            logdir = os.path.join(core.PROG_PATH, core.LOG_DIR)
            logfiles = [
                i for i in os.listdir(logdir)
                if os.path.isfile(os.path.join(logdir, i))
            ]
            return App.logs_template.render(logdir=logdir,
                                            logfiles=logfiles,
                                            **self.defaults())
        elif page == 'download_log':
            if len(path) > 1:
                l = os.path.join(os.path.abspath(core.LOG_DIR), path[1])
                return cherrypy.lib.static.serve_file(
                    l, 'application/x-download', 'attachment')
            else:
                raise cherrypy.HTTPError(400)
        elif page == 'system':
            tasks = {}
            for name, obj in core.scheduler_plugin.task_list.items():
                tasks[name] = {
                    'name': name,
                    'interval': obj.interval,
                    'last_execution': obj.last_execution,
                    'enabled': obj.timer.is_alive() if obj.timer else False
                }

            system = {
                'database': {
                    'file': core.DB_FILE,
                    'size': os.path.getsize(core.DB_FILE) / 1024
                },
                'config': {
                    'file': core.CONF_FILE
                },
                'system': {
                    'path': core.PROG_PATH,
                    'arguments': sys.argv,
                    'version': sys.version[:5]
                }
            }
            t = int(time.time())
            dt = time.strftime('%a, %B %d, %Y %H:%M:%S %z', time.localtime(t))

            return App.system_template.render(tasks=json.dumps(tasks),
                                              system=system,
                                              server_time=[dt, t],
                                              **self.defaults())
        else:
            return self.error_page_404()

    @cherrypy.expose
    def system(self, *path, **kwargs):
        if len(path) == 0:
            return self.error_page_404()

        page = path[0]

        if page == 'shutdown':
            return App.shutdown_template.render(**self.defaults())
        if page == 'restart':
            return App.restart_template.render(**self.defaults())
        if page == 'update':
            return App.update_template.render(updating=core.UPDATING,
                                              **self.defaults())

    @cherrypy.expose
    def error_page_404(self, *args, **kwargs):
        return App.fourohfour_template.render(**self.defaults())

    def head(self):
        return App.head_template.render(
            url_base=core.URL_BASE,
            uitheme=core.CONFIG['Server']['uitheme'],
            notifications=json.dumps(
                [i for i in core.NOTIFICATIONS if i is not None]),
            language=core.LANGUAGE)

    def nav_bar(self, current=None):
        show_logout = True if cherrypy.session.get(core.SESSION_KEY) else False
        return App.navbar_template.render(url_base=core.URL_BASE,
                                          current=current,
                                          show_logout=show_logout)
    cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"


if __name__ == '__main__':
    cherrypy_cors.install()
    conf = {
        '/': {
            'request.dispatch':
            cherrypy.dispatch.MethodDispatcher(),
            'tools.sessions.on':
            True,
            'tools.response_headers.on':
            True,
            'tools.CORS.on':
            True,
            'cors.expose.on':
            True,
            'tools.response_headers.headers': [
                ('Content-Type', 'application/json'),
            ]
        }
    }
    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 9191,
    })
    cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
    cherrypy.tree.mount(loginWebService(), '/loginservice', conf)
    cherrypy.engine.start()
    cherrypy.engine.block()
Example #8
0
        return "http://www.qlik.com/"


def secureheaders():
    headers = cherrypy.response.headers
    headers['X-Frame-Options'] = 'DENY'
    headers['X-XSS-Protection'] = '1; mode=block'
    headers['Content-Security-Policy'] = "default-src='self'"
    if (cherrypy.server.ssl_certificate != None
            and cherrypy.server.ssl_private_key != None):
        headers['Strict-Transport-Security'] = 'max-age=31536000'  # one year


if __name__ == '__main__':
    server_config = {
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 1443,
        'server.ssl_module': 'builtin',
        'server.ssl_certificate': 'cert.pem',
        'server.ssl_private_key': 'privkey.pem',
        'tools.secureheaders.on': True,
        'tools.sessions.on': True,
        'tools.sessions.secure': True,
        'tools.sessions.httponly': True
    }
    cherrypy.tools.secureheaders = cherrypy.Tool('before_finalize',
                                                 secureheaders,
                                                 priority=60)
    cherrypy.config.update(server_config)
    cherrypy.quickstart(GoogleAuth())
Example #9
0
 def __init__(self, *args, **kwargs):
     cherrypy.tools.authenticate = cherrypy.Tool('before_handler', Auth.check_auth)
     cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool()
     cherrypy.config.update({'error_page.default': json_error_page})
     super(ControllerTestCase, self).__init__(*args, **kwargs)
Example #10
0
from lib import FileService
from lib.CAS import CAS
from lib.Constants import Actions
from lib.Models import *
from lib.Formatters import *
from lib.FileFieldStorage import FileFieldStorage

cherrypy.server.max_request_body_size = 0


def before_upload(**kwargs):
    cherrypy.request.process_request_body = False


cherrypy.tools.before_upload = cherrypy.Tool('before_request_body',
                                             before_upload,
                                             priority=71)


def requires_login(permissionId=None, **kwargs):
    from lib import AccountService
    format, rootURL = None, cherrypy.request.app.config['filelocker'][
        'root_url']
    if cherrypy.request.params.has_key("format"):
        format = cherrypy.request.params['format']
    if cherrypy.session.has_key("user") and cherrypy.session.get(
            'user') is not None:
        user = cherrypy.session.get('user')
        if user.date_tos_accept == None:
            raise cherrypy.HTTPRedirect(rootURL + "/sign_tos")
        elif permissionId is not None:
Example #11
0
import cherrypy
import imp
import os
import uuid
import tempfile
from cgi import FieldStorage


def noBodyProcess():
    """Sets cherrypy.request.process_request_body = False, giving
    us direct control of the file upload destination. By default
    cherrypy loads it to memory, we are directing it to disk."""
    cherrypy.request.process_request_body = False


cherrypy.tools.noBodyProcess = cherrypy.Tool('before_request_body',
                                             noBodyProcess)


class PyCurlRESTModel(RESTModel):
    """
    Check if the file upload work with the rest model
    """
    def __init__(self, config={}):
        RESTModel.__init__(self, config)

        self._addMethod('POST', 'file', self.uploadFile, args=['file1'])

        cherrypy.engine.subscribe('start_thread', self.initThread)

    def initThread(self, thread_index):
        """
Example #12
0
    def setup_server():
        class Root:
            def index(self):
                return "hello"

            index.exposed = True

            favicon_ico = tools.staticfile.handler(filename=favicon_path)

            def defct(self, newct):
                newct = "text/%s" % newct
                cherrypy.config.update({
                    'tools.response_headers.on':
                    True,
                    'tools.response_headers.headers': [('Content-Type', newct)]
                })

            defct.exposed = True

            def baseurl(self, path_info, relative=None):
                return cherrypy.url(path_info, relative=bool(relative))

            baseurl.exposed = True

        root = Root()
        root.expose_dec = ExposeExamples()

        class TestType(type):
            """Metaclass which automatically exposes all functions in each
            subclass, and adds an instance of the subclass as an attribute
            of root.
            """
            def __init__(cls, name, bases, dct):
                type.__init__(cls, name, bases, dct)
                for value in itervalues(dct):
                    if isinstance(value, types.FunctionType):
                        value.exposed = True
                setattr(root, name.lower(), cls())

        Test = TestType('Test', (object, ), {})

        class URL(Test):

            _cp_config = {'tools.trailing_slash.on': False}

            def index(self, path_info, relative=None):
                if relative != 'server':
                    relative = bool(relative)
                return cherrypy.url(path_info, relative=relative)

            def leaf(self, path_info, relative=None):
                if relative != 'server':
                    relative = bool(relative)
                return cherrypy.url(path_info, relative=relative)

        def log_status():
            Status.statuses.append(cherrypy.response.status)

        cherrypy.tools.log_status = cherrypy.Tool('on_end_resource',
                                                  log_status)

        class Status(Test):
            def index(self):
                return "normal"

            def blank(self):
                cherrypy.response.status = ""

            # According to RFC 2616, new status codes are OK as long as they
            # are between 100 and 599.

            # Here is an illegal code...
            def illegal(self):
                cherrypy.response.status = 781
                return "oops"

            # ...and here is an unknown but legal code.
            def unknown(self):
                cherrypy.response.status = "431 My custom error"
                return "funky"

            # Non-numeric code
            def bad(self):
                cherrypy.response.status = "error"
                return "bad news"

            statuses = []

            def on_end_resource_stage(self):
                return repr(self.statuses)

            on_end_resource_stage._cp_config = {'tools.log_status.on': True}

        class Redirect(Test):
            class Error:
                _cp_config = {
                    "tools.err_redirect.on": True,
                    "tools.err_redirect.url": "/errpage",
                    "tools.err_redirect.internal": False,
                }

                def index(self):
                    raise NameError("redirect_test")

                index.exposed = True

            error = Error()

            def index(self):
                return "child"

            def custom(self, url, code):
                raise cherrypy.HTTPRedirect(url, code)

            def by_code(self, code):
                raise cherrypy.HTTPRedirect("somewhere%20else", code)

            by_code._cp_config = {'tools.trailing_slash.extra': True}

            def nomodify(self):
                raise cherrypy.HTTPRedirect("", 304)

            def proxy(self):
                raise cherrypy.HTTPRedirect("proxy", 305)

            def stringify(self):
                return str(cherrypy.HTTPRedirect("/"))

            def fragment(self, frag):
                raise cherrypy.HTTPRedirect("/some/url#%s" % frag)

            def url_with_quote(self):
                raise cherrypy.HTTPRedirect("/some\"url/that'we/want")

            def url_with_unicode(self):
                raise cherrypy.HTTPRedirect(
                    ntou("\u0442\u0435\u0441\u0442", 'escape'))

        def login_redir():
            if not getattr(cherrypy.request, "login", None):
                raise cherrypy.InternalRedirect("/internalredirect/login")

        tools.login_redir = _cptools.Tool('before_handler', login_redir)

        def redir_custom():
            raise cherrypy.InternalRedirect("/internalredirect/custom_err")

        class InternalRedirect(Test):
            def index(self):
                raise cherrypy.InternalRedirect("/")

            def choke(self):
                return 3 / 0

            choke.exposed = True
            choke._cp_config = {'hooks.before_error_response': redir_custom}

            def relative(self, a, b):
                raise cherrypy.InternalRedirect("cousin?t=6")

            def cousin(self, t):
                assert cherrypy.request.prev.closed
                return cherrypy.request.prev.query_string

            def petshop(self, user_id):
                if user_id == "parrot":
                    # Trade it for a slug when redirecting
                    raise cherrypy.InternalRedirect(
                        '/image/getImagesByUser?user_id=slug')
                elif user_id == "terrier":
                    # Trade it for a fish when redirecting
                    raise cherrypy.InternalRedirect(
                        '/image/getImagesByUser?user_id=fish')
                else:
                    # This should pass the user_id through to getImagesByUser
                    raise cherrypy.InternalRedirect(
                        '/image/getImagesByUser?user_id=%s' % str(user_id))

            # We support Python 2.3, but the @-deco syntax would look like
            # this:
            # @tools.login_redir()
            def secure(self):
                return "Welcome!"

            secure = tools.login_redir()(secure)

            # Since calling the tool returns the same function you pass in,
            # you could skip binding the return value, and just write:
            # tools.login_redir()(secure)

            def login(self):
                return "Please log in"

            def custom_err(self):
                return "Something went horribly wrong."

            def early_ir(self, arg):
                return "whatever"

            early_ir._cp_config = {'hooks.before_request_body': redir_custom}

        class Image(Test):
            def getImagesByUser(self, user_id):
                return "0 images for %s" % user_id

        class Flatten(Test):
            def as_string(self):
                return "content"

            def as_list(self):
                return ["con", "tent"]

            def as_yield(self):
                yield ntob("content")

            def as_dblyield(self):
                yield self.as_yield()

            as_dblyield._cp_config = {'tools.flatten.on': True}

            def as_refyield(self):
                for chunk in self.as_yield():
                    yield chunk

        class Ranges(Test):
            def get_ranges(self, bytes):
                return repr(httputil.get_ranges('bytes=%s' % bytes, 8))

            def slice_file(self):
                path = os.path.join(os.getcwd(), os.path.dirname(__file__))
                return static.serve_file(
                    os.path.join(path, "static/index.html"))

        class Cookies(Test):
            def single(self, name):
                cookie = cherrypy.request.cookie[name]
                # Python2's SimpleCookie.__setitem__ won't take unicode keys.
                cherrypy.response.cookie[str(name)] = cookie.value

            def multiple(self, names):
                list(map(self.single, names))

        def append_headers(header_list, debug=False):
            if debug:
                cherrypy.log(
                    "Extending response headers with %s" % repr(header_list),
                    "TOOLS.APPEND_HEADERS")
            cherrypy.serving.response.header_list.extend(header_list)

        cherrypy.tools.append_headers = cherrypy.Tool('on_end_resource',
                                                      append_headers)

        class MultiHeader(Test):
            def header_list(self):
                pass

            header_list = cherrypy.tools.append_headers(header_list=[
                (ntob('WWW-Authenticate'), ntob('Negotiate')),
                (ntob('WWW-Authenticate'), ntob('Basic realm="foo"')),
            ])(header_list)

            def commas(self):
                cherrypy.response.headers[
                    'WWW-Authenticate'] = 'Negotiate,Basic realm="foo"'

        cherrypy.tree.mount(root)
Example #13
0
    def _configure(self):
        """
        Configure CherryPy and initialize self.url_prefix

        :returns our URI
        """
        server_addr = self.get_localized_module_option(
            'server_addr', get_default_addr())
        ssl = self.get_localized_module_option('ssl', True)
        if not ssl:
            server_port = self.get_localized_module_option('server_port', 8080)
        else:
            server_port = self.get_localized_module_option('ssl_server_port', 8443)

        if server_addr is None:
            raise ServerConfigException(
                'no server_addr configured; '
                'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"'
                .format(self.module_name, self.get_mgr_id()))
        self.log.info('server: ssl=%s host=%s port=%d', 'yes' if ssl else 'no',
                      server_addr, server_port)

        # Initialize custom handlers.
        cherrypy.tools.authenticate = AuthManagerTool()
        cherrypy.tools.plugin_hooks_filter_request = cherrypy.Tool(
            'before_handler',
            lambda: PLUGIN_MANAGER.hook.filter_request_before_handler(request=cherrypy.request),
            priority=1)
        cherrypy.tools.request_logging = RequestLoggingTool()
        cherrypy.tools.dashboard_exception_handler = HandlerWrapperTool(dashboard_exception_handler,
                                                                        priority=31)

        # Apply the 'global' CherryPy configuration.
        config = {
            'engine.autoreload.on': False,
            'server.socket_host': server_addr,
            'server.socket_port': int(server_port),
            'error_page.default': json_error_page,
            'tools.request_logging.on': True,
            'tools.gzip.on': True,
            'tools.gzip.mime_types': [
                # text/html and text/plain are the default types to compress
                'text/html', 'text/plain',
                # We also want JSON and JavaScript to be compressed
                'application/json',
                'application/javascript',
            ],
            'tools.json_in.on': True,
            'tools.json_in.force': False,
            'tools.plugin_hooks_filter_request.on': True,
        }

        if ssl:
            # SSL initialization
            cert = self.get_store("crt")
            if cert is not None:
                self.cert_tmp = tempfile.NamedTemporaryFile()
                self.cert_tmp.write(cert.encode('utf-8'))
                self.cert_tmp.flush()  # cert_tmp must not be gc'ed
                cert_fname = self.cert_tmp.name
            else:
                cert_fname = self.get_localized_module_option('crt_file')

            pkey = self.get_store("key")
            if pkey is not None:
                self.pkey_tmp = tempfile.NamedTemporaryFile()
                self.pkey_tmp.write(pkey.encode('utf-8'))
                self.pkey_tmp.flush()  # pkey_tmp must not be gc'ed
                pkey_fname = self.pkey_tmp.name
            else:
                pkey_fname = self.get_localized_module_option('key_file')

            verify_tls_files(cert_fname, pkey_fname)

            config['server.ssl_module'] = 'builtin'
            config['server.ssl_certificate'] = cert_fname
            config['server.ssl_private_key'] = pkey_fname

        self.update_cherrypy_config(config)

        self._url_prefix = prepare_url_prefix(self.get_module_option('url_prefix',
                                                                     default=''))

        uri = "{0}://{1}:{2}{3}/".format(
            'https' if ssl else 'http',
            socket.getfqdn() if server_addr in ['::', '0.0.0.0'] else server_addr,
            server_port,
            self.url_prefix
        )

        return uri
Example #14
0
                '/favicon.ico': {
                    'tools.staticfile.on': True,
                    'tools.staticfile.filename': resourcedir + '/img/favicon.ico',
                }})
        api.v1.mount('/api/v1')
        log.i(_('Starting server on port %s ...') % config['server.port'])

        cherrypy.lib.caching.expires(0)  # disable expiry caching
        cherrypy.engine.start()
        cherrypy.engine.block()


def _cm_auth_tool(httphandler):
    if not httphandler.isAuthorized():
        raise cherrypy.HTTPError(403)
cherrypy.tools.cm_auth = cherrypy.Tool(
    'before_handler', _cm_auth_tool, priority=70)
    # priority=70 -->> make tool run after session is locked (at 50)


def _get_user_consent_for_db_schema_update(reasons):
    """Ask the user if the database schema update should happen now
    """
    import textwrap
    wrap = lambda r: os.linesep.join(
        textwrap.wrap(r, initial_indent=' - ', subsequent_indent="   "))
    msg = _("""
==========================================================================
A database schema update is needed and requires your consent.

{reasons}
Example #15
0

def check_auth(*args, **kwargs):
    conditions = cherrypy.request.config.get('auth.require', None)
    if conditions is not None:
        username = cherrypy.session.get(SESSION_KEY)
        if username:
            cherrypy.request.login = username
            for condition in conditions:
                if not condition():
                    raise cherrypy.HTTPRedirect('/auth/login')
        else:
            raise cherrypy.HTTPRedirect('/auth/login')


cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)


def require(*conditions):
    def decorate(f):
        if not hasattr(f, '_cp_config'):
            f._cp_config = dict()
        if 'auth.require' not in f._cp_config:
            f._cp_config['auth.require'] = []
        f._cp_config['auth.require'].extend(conditions)
        return f

    return decorate


class AuthController(object):
Example #16
0
    def _configure(self):
        """
        Configure CherryPy and initialize self.url_prefix

        :returns our URI
        """
        server_addr = self.get_localized_module_option(  # type: ignore
            'server_addr', get_default_addr())
        use_ssl = self.get_localized_module_option('ssl', True)  # type: ignore
        if not use_ssl:
            server_port = self.get_localized_module_option('server_port', 8080)  # type: ignore
        else:
            server_port = self.get_localized_module_option('ssl_server_port', 8443)  # type: ignore

        if server_addr is None:
            raise ServerConfigException(
                'no server_addr configured; '
                'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"'
                .format(self.module_name, self.get_mgr_id()))  # type: ignore
        self.log.info('server: ssl=%s host=%s port=%d', 'yes' if use_ssl else 'no',  # type: ignore
                      server_addr, server_port)

        # Initialize custom handlers.
        cherrypy.tools.authenticate = AuthManagerTool()
        cherrypy.tools.plugin_hooks_filter_request = cherrypy.Tool(
            'before_handler',
            lambda: PLUGIN_MANAGER.hook.filter_request_before_handler(request=cherrypy.request),
            priority=1)
        cherrypy.tools.request_logging = RequestLoggingTool()
        cherrypy.tools.dashboard_exception_handler = HandlerWrapperTool(dashboard_exception_handler,
                                                                        priority=31)

        cherrypy.log.access_log.propagate = False
        cherrypy.log.error_log.propagate = False

        # Apply the 'global' CherryPy configuration.
        config = {
            'engine.autoreload.on': False,
            'server.socket_host': server_addr,
            'server.socket_port': int(server_port),
            'error_page.default': json_error_page,
            'tools.request_logging.on': True,
            'tools.gzip.on': True,
            'tools.gzip.mime_types': [
                # text/html and text/plain are the default types to compress
                'text/html', 'text/plain',
                # We also want JSON and JavaScript to be compressed
                'application/json',
                'application/*+json',
                'application/javascript',
            ],
            'tools.json_in.on': True,
            'tools.json_in.force': True,
            'tools.plugin_hooks_filter_request.on': True,
        }

        if use_ssl:
            # SSL initialization
            cert = self.get_localized_store("crt")  # type: ignore
            if cert is not None:
                self.cert_tmp = tempfile.NamedTemporaryFile()
                self.cert_tmp.write(cert.encode('utf-8'))
                self.cert_tmp.flush()  # cert_tmp must not be gc'ed
                cert_fname = self.cert_tmp.name
            else:
                cert_fname = self.get_localized_module_option('crt_file')  # type: ignore

            pkey = self.get_localized_store("key")  # type: ignore
            if pkey is not None:
                self.pkey_tmp = tempfile.NamedTemporaryFile()
                self.pkey_tmp.write(pkey.encode('utf-8'))
                self.pkey_tmp.flush()  # pkey_tmp must not be gc'ed
                pkey_fname = self.pkey_tmp.name
            else:
                pkey_fname = self.get_localized_module_option('key_file')  # type: ignore

            verify_tls_files(cert_fname, pkey_fname)

            # Create custom SSL context to disable TLS 1.0 and 1.1.
            context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            context.load_cert_chain(cert_fname, pkey_fname)
            if sys.version_info >= (3, 7):
                context.minimum_version = ssl.TLSVersion.TLSv1_2
            else:
                context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1

            config['server.ssl_module'] = 'builtin'
            config['server.ssl_certificate'] = cert_fname
            config['server.ssl_private_key'] = pkey_fname
            config['server.ssl_context'] = context

        self.update_cherrypy_config(config)

        self._url_prefix = prepare_url_prefix(self.get_module_option(  # type: ignore
            'url_prefix', default=''))

        if server_addr in ['::', '0.0.0.0']:
            server_addr = self.get_mgr_ip()  # type: ignore
        base_url = build_url(
            scheme='https' if use_ssl else 'http',
            host=server_addr,
            port=server_port,
        )
        uri = f'{base_url}{self.url_prefix}/'
        return uri
Example #17
0
    def setup_sites(self):

        context_path = "%s/src/context" % self.install_dir
        doc_dir = "%s/doc" % self.install_dir
        plugin_dir = Environment.get_plugin_dir()
        builtin_plugin_dir = Environment.get_builtin_plugin_dir()
        dist_dir = Environment.get_dist_dir()

        log_dir = "%s/log" % Environment.get_tmp_dir()

        def CORS():
            #cherrypy.response.headers["Access-Control-Allow-Origin"] = "http://192.168.0.15:8100"
            cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
            cherrypy.response.headers[
                "Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"

        cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)

        config = {
            'global': {
                'server.socket_host': '127.0.0.1',
                'server.socket_port': 80,
                'log.screen': False,
                'request.show_tracebacks': True,
                'tools.log_headers.on': True,
                'server.log_file': "%s/tactic_log" % log_dir,
                'server.max_request_body_size': 0,
                #'server.socket_timeout': 60,
                'response.timeout': 3600,
                'tools.encode.on': True,
                'tools.encode.encoding': 'utf-8',
                'tools.decode.on': True,
                'tools.decode.encoding': 'utf-8',
                #'encoding_filter.on': True,
                #'decoding_filter.on': True
                'tools.CORS.on': True
            },
            '/context': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': context_path,
                # Need to do this because on windows servers, jar files
                # are served as text/html
                'tools.staticdir.content_types': {
                    'jar': 'application/java-archive'
                }
            },
            '/assets': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': Environment.get_asset_dir()
            },
            '/doc': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': doc_dir,
                'tools.staticdir.index': "index.html"
            },
            # NOTE: expose the entire plugins directory
            '/tactic/plugins': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': plugin_dir,
            },
            '/tactic/builtin_plugins': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': builtin_plugin_dir,
            },
            '/tactic/dist': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': dist_dir,
            },
            '/plugins': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': plugin_dir,
            },
            '/builtin_plugins': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': builtin_plugin_dir,
            },
            '/dist': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': dist_dir,
            },
        }

        # set up the root directory
        cherrypy.root = Root()
        cherrypy.tree.mount(cherrypy.root, config=config)

        from pyasm.search import Search
        search = Search("sthpw/project")
        search.add_filter("type", "resource", op="!=")
        projects = search.get_sobjects()

        # find out if one of the projects is the root
        root_initialized = False

        if not root_initialized:
            project_code = Project.get_default_project()
            if not project_code:
                project_code = Config.get_value('install', 'default_project')
            if project_code and project_code != 'default':
                from tactic.ui.app import SitePage
                cherrypy.root.tactic = SitePage(project_code)
                cherrypy.root.projects = SitePage(project_code)
                root_initialized = True

        if not root_initialized:
            # load in the base site at root
            from tactic_sites.default.context.Index import Index
            cherrypy.root.tactic = Index()
            cherrypy.root.projects = Index()

        for project in projects:
            project_code = project.get_code()
            self.register_project(project_code, config)
        self.register_project("default", config)

        from pyasm.security import Site
        site_obj = Site.get()
        site_obj.register_sites(self, config)

        #self.register_project("vfx", config, site="vfx_demo")
        #self.register_project("default", config, site="vfx_demo")
        return config
Example #18
0
if "APPENGINE_RUNTIME" in os.environ:
    google_app_engine = True
else:
    google_app_engine = False


# for simpler usage
rpcmethod = rpclib.rpcmethod


def _no_body_processor_tool():
    if cherrypy.request.method == "POST":
        cherrypy.request.body.processors = {}

cherrypy.tools.no_body_processor = cherrypy.Tool(
    "on_start_resource", _no_body_processor_tool
)


class CherryPyJsonRpc(rpclib.JsonRpc):
    """
    CherryPy JSON-RPC
    """

    @cherrypy.expose
    @cherrypy.tools.encode(encoding = "utf-8")
    @cherrypy.tools.no_body_processor()
    def request_handler(self, *args, **kwargs):
        """
        Json-RPC Handler
        """
Example #19
0
 def __init__(self, normalizer=None, svc_cfg=None):
     self.logger = c.logger
     self._backendp = BackendClientProcessor(exchange='', routing_key=c.AMQP_RPC_BACKEND_QUEUE)
     cherrypy.tools.cors_tool = cherrypy.Tool('before_request_body', cors_tool, name='cors_tool', priority=50)
     self._source_plugin = normalizer
     self._plugin_cfg = svc_cfg
Example #20
0
def main():
    p = argparse.ArgumentParser(description="Start a Tangelo server.")
    p.add_argument("-c",
                   "--config",
                   type=str,
                   default=None,
                   metavar="FILE",
                   help="specifies configuration file or json string to use")
    p.add_argument(
        "-a",
        "--access-auth",
        action="store_const",
        const=True,
        default=None,
        help=
        "enable HTTP authentication (i.e. processing of .htaccess files) (default)"
    )
    p.add_argument(
        "-na",
        "--no-access-auth",
        action="store_const",
        const=True,
        default=None,
        help="disable HTTP authentication (i.e. processing of .htaccess files)"
    )
    p.add_argument(
        "-p",
        "--drop-privileges",
        action="store_const",
        const=True,
        default=None,
        help="enable privilege drop when started as superuser (default)")
    p.add_argument("-np",
                   "--no-drop-privileges",
                   action="store_const",
                   const=True,
                   default=None,
                   help="disable privilege drop when started as superuser")
    p.add_argument("-s",
                   "--sessions",
                   action="store_const",
                   const=True,
                   default=None,
                   help="enable session tracking (default)")
    p.add_argument("-ns",
                   "--no-sessions",
                   action="store_const",
                   const=True,
                   default=None,
                   help="disable session tracking")
    p.add_argument("--list-dir",
                   action="store_true",
                   default=None,
                   help="enable directory content serving")
    p.add_argument("--no-list-dir",
                   action="store_true",
                   default=None,
                   help="disable directory content serving (default)")
    p.add_argument("--show-py",
                   action="store_true",
                   default=None,
                   help="enable Python service source code serving")
    p.add_argument("--no-show-py",
                   action="store_true",
                   default=None,
                   help="disable Python service source code serving (default)")
    p.add_argument(
        "--hostname",
        type=str,
        default=None,
        metavar="HOSTNAME",
        help="overrides configured hostname on which to run Tangelo")
    p.add_argument(
        "--port",
        type=int,
        default=None,
        metavar="PORT",
        help="overrides configured port number on which to run Tangelo")
    p.add_argument(
        "-u",
        "--user",
        type=str,
        default=None,
        metavar="USERNAME",
        help="specifies the user to run as when root privileges are dropped")
    p.add_argument(
        "-g",
        "--group",
        type=str,
        default=None,
        metavar="GROUPNAME",
        help="specifies the group to run as when root privileges are dropped")
    p.add_argument("-r",
                   "--root",
                   type=str,
                   default=None,
                   metavar="DIR",
                   help="the directory from which Tangelo will serve content")
    p.add_argument("--verbose",
                   "-v",
                   action="append_const",
                   help="display extra information as Tangelo runs",
                   default=[logging.INFO],
                   const=logging.DEBUG - logging.INFO)
    p.add_argument("--quiet",
                   "-q",
                   action="append_const",
                   help="reduce the amount of information displayed",
                   dest="verbose",
                   const=logging.INFO - logging.DEBUG)
    p.add_argument("--version",
                   action="store_true",
                   help="display Tangelo version number")
    p.add_argument(
        "--key",
        type=str,
        default=None,
        metavar="FILE",
        help=
        "the path to the SSL key.  You must also specify --cert to serve content over https."
    )
    p.add_argument(
        "--cert",
        type=str,
        default=None,
        metavar="FILE",
        help=
        "the path to the SSL certificate.  You must also specify --key to serve content over https."
    )
    p.add_argument("--examples",
                   action="store_true",
                   default=None,
                   help="Serve the Tangelo example applications")
    p.add_argument(
        "--watch",
        action="store_true",
        default=None,
        help="Add the watch plugin (reload python files if they change).")
    args = p.parse_args()

    # If version flag is present, print the version number and exit.
    if args.version:
        print tangelo_version
        return 0

    # Set the verbosity
    log_level = max(sum(args.verbose), 1)
    cherrypy.log.error_log.setLevel(log_level)

    # Make sure user didn't specify conflicting flags.
    if args.access_auth and args.no_access_auth:
        tangelo.log_critical(
            "ERROR",
            "can't specify both --access-auth (-a) and --no-access-auth (-na) together"
        )
        return 1

    if args.drop_privileges and args.no_drop_privileges:
        tangelo.log_critical(
            "ERROR",
            "can't specify both --drop-privileges (-p) and --no-drop-privileges (-np) together"
        )
        return 1

    if args.no_sessions and args.sessions:
        tangelo.log_critical(
            "ERROR",
            "can't specify both --sessions (-s) and --no-sessions (-ns) together"
        )
        return 1

    if args.examples and args.root:
        tangelo.log_critical(
            "ERROR", "can't specify both --examples and --root (-r) together")
        return 1

    if args.examples and args.config:
        tangelo.log_critical(
            "ERROR",
            "can't specify both --examples and --config (-c) together")
        return 1

    if args.no_list_dir and args.list_dir:
        tangelo.log_critical(
            "ERROR",
            "can't specify both --list-dir and --no-list-dir together")
        return 1

    if args.no_show_py and args.show_py:
        tangelo.log_critical(
            "ERROR", "can't specify both --show-py and --no-show-py together")
        return 1

    # Report the logging level.
    if log_level > logging.CRITICAL:
        log_level_tag = "NONE"
    elif log_level > logging.ERROR:
        log_level_tag = "CRITICAL"
    elif log_level > logging.WARNING:
        log_level_tag = "ERROR"
    elif log_level > logging.INFO:
        log_level_tag = "WARNING"
    elif log_level > logging.DEBUG:
        log_level_tag = "INFO"
    else:
        log_level_tag = "DEBUG"

    tangelo.log_info("TANGELO",
                     "Logging level: %s (%d)" % (log_level_tag, log_level))

    # Decide if we have a configuration file or not.
    cfg_file = args.config
    if cfg_file is None:
        tangelo.log_info(
            "TANGELO",
            "No configuration file specified - using command line args and defaults"
        )
    else:
        if os.path.exists(tangelo.util.expandpath(
                cfg_file)) or not cfg_file.startswith("{"):
            cfg_file = tangelo.util.expandpath(cfg_file)
            tangelo.log("TANGELO", "Using configuration file %s" % (cfg_file))
        else:
            tangelo.log("TANGELO", "Using configuration string")

    # Parse the config file; report errors if any.
    try:
        config = Config(cfg_file)
    except (IOError, ValueError) as e:
        tangelo.log_critical("ERROR", e)
        return 1

    # Type check the config entries.
    if not config.type_check():
        for message in config.errors:
            tangelo.log_critical("TANGELO", message)
        return 1

    # Determine whether to use access auth.
    access_auth = True
    if args.access_auth is None and args.no_access_auth is None:
        if config.access_auth is not None:
            access_auth = config.access_auth
    else:
        access_auth = (args.access_auth
                       is not None) or (not args.no_access_auth)

    tangelo.log_info(
        "TANGELO", "Access authentication %s" %
        ("enabled" if access_auth else "disabled"))

    # Determine whether to perform privilege drop.
    drop_privileges = True
    if args.drop_privileges is None and args.no_drop_privileges is None:
        if config.drop_privileges is not None:
            drop_privileges = config.drop_privileges
    else:
        drop_privileges = (args.drop_privileges
                           is not None) or (not args.no_drop_privileges)

    # Determine whether to enable sessions.
    sessions = True
    if args.sessions is None and args.no_sessions is None:
        if config.sessions is not None:
            sessions = config.sessions
    else:
        sessions = (args.sessions is not None) or (not args.no_sessions)

    tangelo.log_info("TANGELO",
                     "Sessions %s" % ("enabled" if sessions else "disabled"))

    # Determine whether to serve directory listings by default.
    listdir = False
    if args.list_dir is None and args.no_list_dir is None:
        if config.list_dir is not None:
            listdir = config.list_dir
    else:
        listdir = (args.list_dir is not None) or (not args.no_list_dir)

    cherrypy.config["listdir"] = listdir
    tangelo.log_info(
        "TANGELO", "Directory content serving %s" %
        ("enabled" if listdir else "disabled"))

    # Determine whether to serve web service Python source code by default.
    showpy = False
    if args.show_py is None and args.no_show_py is None:
        if config.show_py is not None:
            showpy = config.show_py
    else:
        showpy = (args.show_py is not None) or (not args.no_show_py)

    cherrypy.config["showpy"] = showpy
    tangelo.log_info(
        "TANGELO", "Web service source code serving %s" %
        ("enabled" if showpy else "disabled"))

    # Extract the rest of the arguments, giving priority first to command line
    # arguments, then to the configuration file (if any), and finally to a
    # hard-coded default value.
    hostname = args.hostname or config.hostname or "localhost"
    port = args.port or config.port or 8080
    user = args.user or config.user or "nobody"
    group = args.group or config.group or "nobody"

    tangelo.log_info("TANGELO", "Hostname: %s" % (hostname))
    tangelo.log_info("TANGELO", "Port: %d" % (port))

    tangelo.log_info(
        "TANGELO", "Privilege drop %s" %
        ("enabled (if necessary)" if drop_privileges else "disabled"))
    if drop_privileges:
        tangelo.log_info("TANGELO", "\tUser: %s" % (user))
        tangelo.log_info("TANGELO", "\tGroup: %s" % (group))

    # HTTPS support
    #
    # Grab the ssl key file.
    ssl_key = args.key or config.key
    if ssl_key is not None:
        ssl_key = tangelo.util.expandpath(ssl_key)

    # Grab the cert file.
    ssl_cert = args.cert or config.cert
    if ssl_cert is not None:
        ssl_cert = tangelo.util.expandpath(ssl_cert)

    # In order to enable HTTPS, *both* the key and cert must be specified.  If
    # only one or the other is specified, this is considered an error, because
    # we don't want to serve what the user is considering sensitive content over
    # HTTP by default.
    if ssl_key is not None and ssl_cert is not None:
        cherrypy.config.update({
            "server.ssl_module": "pyopenssl",
            "server.ssl_certificate": ssl_cert,
            "server.ssl_private_key": ssl_key
        })
        tangelo.log_info("TANGELO", "HTTPS enabled")
        tangelo.log_info("TANGELO", "\tSSL Cert file: %s" % (ssl_cert))
        tangelo.log_info("TANGELO", "\tSSL Key file: %s" % (ssl_key))
    elif not (ssl_key is None and ssl_cert is None):
        tangelo.log_critical("TANGELO", "error: SSL key or SSL cert missing")
        return 1
    else:
        tangelo.log_info("TANGELO", "HTTPS disabled")

    # We need a web root - use the installed example web directory as a
    # fallback.  This might be found in a few different places, so try them one
    # by one until we find one that exists.
    root = args.root or config.root
    if root:
        root = tangelo.util.expandpath(root)
    elif args.examples:
        # Set the examples web root.
        root = get_web_directory()
        tangelo.log_info("TANGELO",
                         "Looking for example web content path in %s" % (root))
        if not os.path.exists(root):
            tangelo.log_critical("ERROR", "could not find examples package")
            return 1

        # Set the examples plugins.
        config.plugins = [{
            "name": "config"
        }, {
            "name": "data"
        }, {
            "name": "docs"
        }, {
            "name": "mapping"
        }, {
            "name": "mongo"
        }, {
            "name": "stream"
        }, {
            "name": "tangelo"
        }, {
            "name": "ui"
        }, {
            "name": "vis"
        }]
    else:
        root = tangelo.util.expandpath(".")
    # All that the core does when --watch is includes is to make sure it is in
    # the list of plugins.  If it isn't present, it gets added to the beginning
    # of the list so that other plugins will be monitored.
    if args.watch:
        if config.plugins is None:
            config.plugins = []
        if "watch" not in [plugin.get("name") for plugin in config.plugins]:
            config.plugins.insert(0, {"name": "watch"})

    tangelo.log_info("TANGELO", "Serving content from %s" % (root))

    # Set the web root directory.
    cherrypy.config.update({"webroot": root})

    # Place an empty dict to hold per-module configuration into the global
    # configuration object, and one for persistent per-module storage (the
    # latter can be manipulated by the service).
    cherrypy.config.update({"module-config": {}})
    cherrypy.config.update({"module-store": {}})

    # Analogs of the module storage dicts, but for plugins.
    cherrypy.config.update({"plugin-config": {}})
    cherrypy.config.update({"plugin-store": {}})

    # Create a plugin manager.
    plugins = tangelo.server.Plugins("tangelo.plugin",
                                     config=config.plugins,
                                     plugin_dir=get_bundled_plugin_directory())

    # Check for any errors - if there are, report them and exit.
    if not plugins.good():
        for message in plugins.errors:
            tangelo.log_critical("PLUGIN", message)
        return 1

    # Save the plugin manager for use later (when unloading plugins during
    # shutdown).
    cherrypy.config.update({"plugins": plugins})

    # Create an instance of the main handler object.
    module_cache = tangelo.util.ModuleCache()
    tangelo_server = tangelo.server.Tangelo(module_cache=module_cache,
                                            plugins=plugins)
    rootapp = cherrypy.Application(tangelo_server, "/")

    # Place an AuthUpdate handler in the Tangelo object if access authorization
    # is on.
    tangelo_server.auth_update = tangelo.server.AuthUpdate(app=rootapp)

    # Mount the root application object.
    cherrypy.tree.mount(rootapp,
                        config={
                            "/": {
                                "tools.sessions.on": sessions
                            },
                            "/favicon.ico": {
                                "tools.staticfile.on": True,
                                "tools.staticfile.filename": get_tangelo_ico()
                            }
                        })

    # Set up the global configuration.
    cherrypy.config.update({
        "environment": "production",
        "log.screen": True,
        "server.socket_host": hostname,
        "server.socket_port": port
    })

    # Dump in any other global configuration present in the configuration.
    if config.server_settings:
        tangelo.log_info("TANGELO", "User server settings:")
        for setting, value in config.server_settings.iteritems():
            tangelo.util.set_server_setting(setting, value)
            tangelo.log_info(
                "TANGELO",
                "\t%s -> %s" % (setting, cherrypy.config.get(setting)))

    # Try to drop privileges if requested, since we've bound to whatever port
    # superuser privileges were needed for already.
    if drop_privileges:
        # If we're on windows, don't supply any username/groupname, and just
        # assume we should drop priveleges.
        if platform.system() == "Windows":
            tangelo.log_info("TANGELO", "Performing privilege drop")
            cherrypy.process.plugins.DropPrivileges(
                cherrypy.engine).subscribe()
        elif os.getuid() == 0:
            tangelo.log_info("TANGELO", "Performing privilege drop")

            # Reaching here means we're on unix, and we are the root user, so go
            # ahead and drop privileges to the requested user/group.
            import grp
            import pwd

            # On some systems, negative uids and gids are allowed.  These can
            # render in Python (in particular, on OS X) as very large unsigned
            # values.  This function first checks to see if the input value is
            # already negative; if so, there's no issue and we return it
            # unchanged.  Otherwise, we treat the argument as a bit
            # representation of a *signed* value, check the sign bit to see if
            # it *should* be a negative number, and then perform the proper
            # arithmetic to turn it into a signed one.
            def to_signed(val):
                # If we already see a negative number, just return it.
                if val < 0:
                    return val

                # Check sign bit, and subtract the unsigned range from the value
                # if it is set.
                return val - 0x100000000 if val & 0x80000000 else val

            # Find the UID and GID for the requested user and group.
            try:
                mode = "user"
                value = user
                uid = to_signed(pwd.getpwnam(user).pw_uid)

                mode = "group"
                value = group
                gid = to_signed(grp.getgrnam(group).gr_gid)
            except KeyError:
                tangelo.log_critical(
                    "TANGELO",
                    "no such %s '%s' to drop privileges to" % (mode, value))
                return 1

            # Set the process home directory to be the dropped-down user's.
            os.environ["HOME"] = os.path.expanduser("~%s" % (user))

            # Perform the actual UID/GID change.
            cherrypy.process.plugins.DropPrivileges(cherrypy.engine,
                                                    uid=uid,
                                                    gid=gid).subscribe()
        else:
            tangelo.log_info(
                "TANGELO",
                "Not performing privilege drop (because not running as superuser)"
            )

    # Set up websocket handling.  Use the pass-through subclassed version of the
    # plugin so we can set a priority on it that doesn't conflict with privilege
    # drop.
    tangelo.websocket.WebSocketLowPriorityPlugin(cherrypy.engine).subscribe()
    cherrypy.tools.websocket = ws4py.server.cherrypyserver.WebSocketTool()

    # Replace the stock auth_digest and auth_basic tools with ones that have
    # slightly lower priority (so the AuthUpdate tool can run before them).
    cherrypy.tools.auth_basic = cherrypy.Tool(
        "before_handler", cherrypy.lib.auth_basic.basic_auth, priority=2)
    cherrypy.tools.auth_digest = cherrypy.Tool(
        "before_handler", cherrypy.lib.auth_digest.digest_auth, priority=2)

    # Install signal handlers to allow for proper cleanup/shutdown.
    for sig in [signal.SIGINT, signal.SIGTERM]:
        signal.signal(sig, shutdown)

    # Send SIGQUIT to an immediate, ungraceful shutdown instead.
    if platform.system() != "Windows":
        signal.signal(signal.SIGQUIT, die)

    # Start the CherryPy engine.
    cherrypy.engine.start()
    tangelo.log_info("\033[32mTANGELO", "\033[32mServer is running")
    cherrypy.engine.block()
Example #21
0
    _version = get_version()
    _com_args, _op_arg, config = cb_setup(args)

    folder = os.path.abspath(os.curdir)
    _flowsdir = os.path.normpath(os.path.join(folder, args.flowsdir))
    _flows = Flow(_flowsdir, profile_handler=SimpleProfileHandler)
    try:
        csi = config.CHECK_SESSION_IFRAME
    except AttributeError:
        op_handler = OPHandler(provider.Provider, _op_arg, _com_args, _flows,
                               folder)
    else:
        op_handler = OPHandler(provider.Provider, _op_arg, _com_args, _flows,
                               folder, csi.format(args.port))

    cherrypy.tools.dumplog = cherrypy.Tool('before_finalize', dump_log)

    cherrypy.config.update({
        'environment': 'production',
        'log.error_file': 'site.log',
        'tools.trailing_slash.on': False,
        'server.socket_host': '0.0.0.0',
        'log.screen': True,
        'tools.sessions.on': True,
        'tools.encode.on': True,
        'tools.encode.encoding': 'utf-8',
        'tools.dumplog.on': True,
        'server.socket_port': args.port
    })

    provider_config = {
Example #22
0
    def _configure(self):
        """
        Configure CherryPy and initialize self.url_prefix

        :returns our URI
        """
        server_addr = self.get_localized_config('server_addr', '::')
        server_port = self.get_localized_config('server_port', '8443')
        if server_addr is None:
            raise ServerConfigException(
                'no server_addr configured; '
                'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"'.format(
                    self.module_name, self.get_mgr_id()))
        self.log.info('server_addr: %s server_port: %s', server_addr,
                      server_port)

        # Initialize custom handlers.
        cherrypy.tools.authenticate = cherrypy.Tool('before_handler',
                                                    Auth.check_auth)
        cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool(
        )
        cherrypy.tools.request_logging = RequestLoggingTool()

        # SSL initialization
        cert = self.get_store("crt")
        if cert is not None:
            self.cert_tmp = tempfile.NamedTemporaryFile()
            self.cert_tmp.write(cert.encode('utf-8'))
            self.cert_tmp.flush()  # cert_tmp must not be gc'ed
            cert_fname = self.cert_tmp.name
        else:
            cert_fname = self.get_localized_config('crt_file')

        pkey = self.get_store("key")
        if pkey is not None:
            self.pkey_tmp = tempfile.NamedTemporaryFile()
            self.pkey_tmp.write(pkey.encode('utf-8'))
            self.pkey_tmp.flush()  # pkey_tmp must not be gc'ed
            pkey_fname = self.pkey_tmp.name
        else:
            pkey_fname = self.get_localized_config('key_file')

        if not cert_fname or not pkey_fname:
            raise ServerConfigException('no certificate configured')
        if not os.path.isfile(cert_fname):
            raise ServerConfigException('certificate %s does not exist' %
                                        cert_fname)
        if not os.path.isfile(pkey_fname):
            raise ServerConfigException('private key %s does not exist' %
                                        pkey_fname)

        # Apply the 'global' CherryPy configuration.
        config = {
            'engine.autoreload.on': False,
            'server.socket_host': server_addr,
            'server.socket_port': int(server_port),
            'server.ssl_module': 'builtin',
            'server.ssl_certificate': cert_fname,
            'server.ssl_private_key': pkey_fname,
            'error_page.default': json_error_page,
            'tools.request_logging.on': True
        }
        cherrypy.config.update(config)

        self._url_prefix = prepare_url_prefix(
            self.get_config('url_prefix', default=''))

        uri = "https://{0}:{1}{2}/".format(
            socket.getfqdn() if server_addr == "::" else server_addr,
            server_port, self.url_prefix)

        return uri