Example #1
0
    def test_create_https_certificates(self):
        """
        Test that create_https_certificates successfully generates certificate and private key
        """
        try:
            import OpenSSL
        except ImportError:
            self.skipTest('pyOpenSSL is not installed')
            return False

        base_path = os.path.dirname(__file__)
        cert_path = os.path.abspath(os.path.join(base_path, 'test.crt'))
        pkey_path = os.path.abspath(os.path.join(base_path, 'test.key'))

        def removeTestFiles():
            try:
                os.remove(cert_path)
                os.remove(pkey_path)
            except OSError:
                pass

        removeTestFiles()  # always remove existing
        self.assertTrue(helpers.create_https_certificates(
            cert_path, pkey_path))
        self.assertTrue(os.path.isfile(cert_path))
        self.assertTrue(os.path.isfile(pkey_path))

        FILETYPE_PEM = OpenSSL.crypto.FILETYPE_PEM
        try:
            with open(cert_path, 'rt') as f:
                cert = OpenSSL.crypto.load_certificate(FILETYPE_PEM, f.read())
        except Exception as error:
            removeTestFiles()
            self.fail('Unable to load certificate')

        try:
            with open(pkey_path, 'rt') as f:
                pkey = OpenSSL.crypto.load_privatekey(FILETYPE_PEM, f.read())
        except Exception as error:
            removeTestFiles()
            self.fail('Unable to load private key')

        context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
        context.use_privatekey(pkey)
        context.use_certificate(cert)
        failed = False
        try:
            context.check_privatekey()
        except OpenSSL.SSL.Error:
            failed = True
        finally:
            removeTestFiles()

        self.assertFalse(failed, 'private key does not match certificate')
Example #2
0
    def test_create_https_certificates(self):
        """
        Test that create_https_certificates successfully generates certificate and private key
        """
        try:
            import OpenSSL
        except ImportError:
            self.skipTest('pyOpenSSL is not installed')
            return False

        base_path = os.path.dirname(__file__)
        cert_path = os.path.abspath(os.path.join(base_path, 'test.crt'))
        pkey_path = os.path.abspath(os.path.join(base_path, 'test.key'))

        def removeTestFiles():
            try:
                os.remove(cert_path)
                os.remove(pkey_path)
            except OSError:
                pass

        removeTestFiles()  # always remove existing
        self.assertTrue(helpers.create_https_certificates(cert_path, pkey_path))
        self.assertTrue(os.path.isfile(cert_path))
        self.assertTrue(os.path.isfile(pkey_path))

        FILETYPE_PEM = OpenSSL.crypto.FILETYPE_PEM
        try:
            with open(cert_path, 'rt') as f:
                cert = OpenSSL.crypto.load_certificate(FILETYPE_PEM, f.read())
        except Exception as error:
            removeTestFiles()
            self.fail('Unable to load certificate')

        try:
            with open(pkey_path, 'rt') as f:
                pkey = OpenSSL.crypto.load_privatekey(FILETYPE_PEM, f.read())
        except Exception as error:
            removeTestFiles()
            self.fail('Unable to load private key')

        context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
        context.use_privatekey(pkey)
        context.use_certificate(cert)
        failed = False
        try:
            context.check_privatekey()
        except OpenSSL.SSL.Error:
            failed = True
        finally:
            removeTestFiles()

        self.assertFalse(failed, 'private key does not match certificate')
Example #3
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    # tornado setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    # Load the app
    app = Application([],
                        debug=False,
                        gzip=True,
                        xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                        cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo='
    )

    # Main Handler
    app.add_handlers(".*$", [
        (r"%s" % options['web_root'], RedirectHandler, {'url': '%s/home/' % options['web_root']}),
        (r'%s/api/(.*)(/?)' % options['web_root'], webapi.Api),
        (r'%s/(.*)(/?)' % options['web_root'], webserve.MainHandler)
    ])

    # Static Path Handler
    app.add_handlers(".*$", [
        (r'%s/(favicon\.ico)' % options['web_root'], MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'images/ico/favicon.ico')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'images'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'images'),
                    os.path.join(sickbeard.CACHE_DIR, 'images')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'css'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'css')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'js'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'js')]})

    ])

    global server

    if enable_https:
        protocol = "https"
        server = HTTPServer(app, no_keep_alive=True,
                            ssl_options={"certfile": https_cert, "keyfile": https_key})
    else:
        protocol = "http"
        server = HTTPServer(app, no_keep_alive=True)

    logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(
        options['port']) + "/")

    try:
        server.listen(options['port'], options['host'])
    except:
        pass
Example #4
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"Tornado caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % options['web_root']

    # tornado setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    # Load the app
    app = Application([],
                        debug=True,
                        gzip=True,
                        autoreload=True,
                        xheaders=False,
                        cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
                        login_url='/login'
    )

    # Index Handler
    app.add_handlers(".*$", [
        (r"/", RedirectHandler, {'url': '/home/'}),
        (r'/login', webserve.LoginHandler),
        (r'/api/(.*)(/?)', webapi.Api),
        (r'%s(.*)(/?)' % options['web_root'], webserve.IndexHandler)
    ])

    # Static Path Handler
    app.add_handlers(".*$", [
        ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'images'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'images'),
                    os.path.join(sickbeard.CACHE_DIR, 'images'),
                    os.path.join(sickbeard.CACHE_DIR, 'images', 'thumbnails')]}),
        ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'css'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'css')]}),
        ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'js'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'js')]})

    ])

    global server

    if enable_https:
        protocol = "https"
        server = HTTPServer(app, no_keep_alive=True,
                                 ssl_options={"certfile": https_cert, "keyfile": https_key})
    else:
        protocol = "http"
        server = HTTPServer(app, no_keep_alive=True)

    logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(
        options['port']) + "/")

    server.listen(options['port'], options['host'])
Example #5
0
    def __init__(self, options=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = 'TORNADO'
        self.io_loop = None
        self.server = None

        self.options = options or {}
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', None)
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # web root
        self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options['web_root'] else ''

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            make_cert = False
            update_cfg = False
            for (attr, ext) in [('https_cert', '.crt'), ('https_key', '.key')]:
                ssl_path = getattr(self, attr, None)
                if ssl_path and not os.path.isfile(ssl_path):
                    if not ssl_path.endswith(ext):
                        setattr(self, attr, os.path.join(ssl_path, 'server%s' % ext))
                        setattr(sickbeard, attr.upper(), 'server%s' % ext)
                    make_cert = True

            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if make_cert:
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u'Unable to create CERT/KEY files, disabling HTTPS')
                    update_cfg |= False is not sickbeard.ENABLE_HTTPS
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False
                else:
                    update_cfg = True

            if not (os.path.isfile(self.https_cert) and os.path.isfile(self.https_key)):
                logger.log(u'Disabled HTTPS because of missing CERT and KEY files', logger.WARNING)
                update_cfg |= False is not sickbeard.ENABLE_HTTPS
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

            if update_cfg:
                sickbeard.save_config()

        # Load the app
        self.app = Application([],
                               debug=True,
                               serve_traceback=True,
                               autoreload=False,
                               compress_response=True,
                               cookie_secret=sickbeard.COOKIE_SECRET,
                               xsrf_cookies=True,
                               login_url='%s/login/' % self.options['web_root'])

        re_host_pattern = re_valid_hostname()

        # webui login/logout handlers
        self.app.add_handlers(re_host_pattern, [
            (r'%s/login(/?)' % self.options['web_root'], webserve.LoginHandler),
            (r'%s/logout(/?)' % self.options['web_root'], webserve.LogoutHandler),
        ])

        # Web calendar handler (Needed because option Unprotected calendar)
        self.app.add_handlers(re_host_pattern, [
            (r'%s/calendar' % self.options['web_root'], webserve.CalendarHandler),
        ])

        # Static File Handlers
        self.app.add_handlers(re_host_pattern, [
            # favicon
            (r'%s/(favicon\.ico)' % self.options['web_root'], webserve.BaseStaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),

            # images
            (r'%s/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'images')}),

            # cached images
            (r'%s/cache/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
             {'path': os.path.join(sickbeard.CACHE_DIR, 'images')}),

            # css
            (r'%s/css/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'css')}),

            # javascript
            (r'%s/js/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'js')}),

            (r'%s/kodi/(.*)' % self.options['web_root'], webserve.RepoHandler,
             {'path': os.path.join(sickbeard.CACHE_DIR, 'clients', 'kodi'),
              'default_filename': 'index.html'}),
        ])

        # Main Handler
        self.app.add_handlers(re_host_pattern, [
            (r'%s/api/builder(/?)(.*)' % self.options['web_root'], webserve.ApiBuilder),
            (r'%s/api(/?.*)' % self.options['web_root'], webapi.Api),
            (r'%s/imagecache(/?.*)' % self.options['web_root'], webserve.CachedImages),
            (r'%s/cache(/?.*)' % self.options['web_root'], webserve.Cache),
            (r'%s/config/general(/?.*)' % self.options['web_root'], webserve.ConfigGeneral),
            (r'%s/config/search(/?.*)' % self.options['web_root'], webserve.ConfigSearch),
            (r'%s/config/providers(/?.*)' % self.options['web_root'], webserve.ConfigProviders),
            (r'%s/config/subtitles(/?.*)' % self.options['web_root'], webserve.ConfigSubtitles),
            (r'%s/config/postProcessing(/?.*)' % self.options['web_root'], webserve.ConfigPostProcessing),
            (r'%s/config/notifications(/?.*)' % self.options['web_root'], webserve.ConfigNotifications),
            (r'%s/config/anime(/?.*)' % self.options['web_root'], webserve.ConfigAnime),
            (r'%s/config(/?.*)' % self.options['web_root'], webserve.Config),
            (r'%s/errorlogs(/?.*)' % self.options['web_root'], webserve.ErrorLogs),
            (r'%s/history(/?.*)' % self.options['web_root'], webserve.History),
            (r'%s/home/is_alive(/?.*)' % self.options['web_root'], webserve.IsAliveHandler),
            (r'%s/home/addShows(/?.*)' % self.options['web_root'], webserve.NewHomeAddShows),
            (r'%s/home/postprocess(/?.*)' % self.options['web_root'], webserve.HomePostProcess),
            (r'%s/home(/?.*)' % self.options['web_root'], webserve.Home),
            (r'%s/manage/manageSearches(/?.*)' % self.options['web_root'], webserve.ManageSearches),
            (r'%s/manage/showProcesses(/?.*)' % self.options['web_root'], webserve.showProcesses),
            (r'%s/manage/(/?.*)' % self.options['web_root'], webserve.Manage),
            (r'%s/ui(/?.*)' % self.options['web_root'], webserve.UI),
            (r'%s/browser(/?.*)' % self.options['web_root'], webserve.WebFileBrowser),
            (r'%s(/?update_watched_state_kodi/?)' % self.options['web_root'], webserve.NoXSRFHandler),
            (r'%s(/?.*)' % self.options['web_root'], webserve.MainHandler),
        ])
Example #6
0
    def __init__(self, options=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "WEBSERVER"

        self.options = options or {}
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')

        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        self.server = None

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options['web_root']:
            sickbeard.WEB_ROOT = self.options['web_root'] = (
                '/' + self.options['web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options['api_root'] = r'{0}/api/{1}'.format(
            sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert
                    and ek(os.path.exists, self.https_cert)) or not (
                        self.https_key and ek(os.path.exists, self.https_key)):
                if not create_https_certificates(self.https_cert,
                                                 self.https_key):
                    logger.log(
                        "Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (ek(os.path.exists, self.https_cert)
                    and ek(os.path.exists, self.https_key)):
                logger.log(
                    "Disabled HTTPS because of missing CERT and KEY files",
                    logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=
            False,  # enables autoreload, compiled_template_cache, static_hash_cache, serve_traceback - This fixes the 404 page and fixes autoreload for
            #  devs. We could now update without restart possibly if we check DB version hasnt changed!
            autoreload=False,
            gzip=sickbeard.WEB_USE_GZIP,
            cookie_secret=sickbeard.WEB_COOKIE_SECRET,
            login_url='{0}/login/'.format(self.options['web_root']),
            static_path=self.options['data_root'],
            static_url_prefix='{0}/'.format(self.options['web_root'])
            # default_handler_class=Custom404Handler
        )

        # Static File Handlers
        self.app.add_handlers(
            ".*$",
            [
                url(r'{0}/favicon.ico'.format(self.options['web_root']),
                    StaticFileHandler, {
                        "path":
                        ek(os.path.join, self.options['data_root'],
                           'images/ico/favicon.ico')
                    },
                    name='favicon'),
                url(r'{0}/images/(.*)'.format(self.options['web_root']),
                    StaticFileHandler, {
                        "path":
                        ek(os.path.join, self.options['data_root'], 'images')
                    },
                    name='images'),
                url(r'{0}/cache/images/(.*)'.format(self.options['web_root']),
                    StaticFileHandler,
                    {"path": ek(os.path.join, sickbeard.CACHE_DIR, 'images')},
                    name='image_cache'),
                url(r'{0}/css/(.*)'.format(self.options['web_root']),
                    StaticFileHandler, {
                        "path": ek(os.path.join, self.options['data_root'],
                                   'css')
                    },
                    name='css'),
                url(r'{0}/js/(.*)'.format(self.options['web_root']),
                    StaticFileHandler, {
                        "path": ek(os.path.join, self.options['data_root'],
                                   'js')
                    },
                    name='js'),
                url(r'{0}/fonts/(.*)'.format(self.options['web_root']),
                    StaticFileHandler, {
                        "path":
                        ek(os.path.join, self.options['data_root'], 'fonts')
                    },
                    name='fonts')

                # TODO: WTF is this?
                # url(r'{0}/videos/(.*)'.format(self.options['web_root']), StaticFileHandler,
                #     {"path": self.video_root}, name='videos')
            ])

        # Main Handlers
        self.app.add_handlers(
            '.*$',
            [
                url(r'{0}(/?.*)'.format(self.options['api_root']),
                    ApiHandler,
                    name='api'),
                url(r'{0}/getkey(/?.*)'.format(self.options['web_root']),
                    KeyHandler,
                    name='get_api_key'),
                url(r'{0}/api/builder'.format(self.options['web_root']),
                    RedirectHandler,
                    {"url": self.options['web_root'] + '/apibuilder/'},
                    name='apibuilder'),
                url(r'{0}/login(/?)'.format(self.options['web_root']),
                    LoginHandler,
                    name='login'),
                url(r'{0}/logout(/?)'.format(self.options['web_root']),
                    LogoutHandler,
                    name='logout'),
                url(r'{0}/calendar/?'.format(self.options['web_root']),
                    CalendarHandler,
                    name='calendar'),

                # routes added by @route decorator
                # Plus naked index with missing web_root prefix
            ] + Route.get_routes(self.options['web_root']))
Example #7
0
    def __init__(self, options=None, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options or {}
        self.options.setdefault("port", 8081)
        self.options.setdefault("host", "0.0.0.0")
        self.options.setdefault("log_dir", None)
        self.options.setdefault("username", "")
        self.options.setdefault("password", "")
        self.options.setdefault("web_root", "/")
        assert isinstance(self.options["port"], int)
        assert "data_root" in self.options

        self.server = None

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split("|")
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options["web_root"]:
            sickbeard.WEB_ROOT = self.options["web_root"] = "/" + self.options["web_root"].lstrip("/").strip("/")

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options["api_root"] = r"{0}/api/{1}".format(sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options["enable_https"]
        self.https_cert = self.options["https_cert"]
        self.https_key = self.options["https_key"]

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and ek(os.path.exists, self.https_cert)) or not (
                self.https_key and ek(os.path.exists, self.https_key)
            ):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (ek(os.path.exists, self.https_cert) and ek(os.path.exists, self.https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=True,
            autoreload=False,
            gzip=sickbeard.WEB_USE_GZIP,
            xheaders=sickbeard.HANDLE_REVERSE_PROXY,
            cookie_secret=sickbeard.WEB_COOKIE_SECRET,
            login_url="{0}/login/".format(self.options["web_root"]),
        )

        # Main Handlers
        self.app.add_handlers(
            ".*$",
            [
                # webapi handler
                (r"{0}(/?.*)".format(self.options["api_root"]), ApiHandler),
                # webapi key retrieval
                (r"{0}/getkey(/?.*)".format(self.options["web_root"]), KeyHandler),
                # webapi builder redirect
                (
                    r"{0}/api/builder".format(self.options["web_root"]),
                    RedirectHandler,
                    {"url": self.options["web_root"] + "/apibuilder/"},
                ),
                # webui login/logout handlers
                (r"{0}/login(/?)".format(self.options["web_root"]), LoginHandler),
                (r"{0}/logout(/?)".format(self.options["web_root"]), LogoutHandler),
                # Web calendar handler (Needed because option Unprotected calendar)
                (r"{0}/calendar".format(self.options["web_root"]), CalendarHandler),
                # webui handlers
            ]
            + route.get_routes(self.options["web_root"]),
        )

        # Static File Handlers
        self.app.add_handlers(
            ".*$",
            [
                # favicon
                (
                    r"{0}/(favicon\.ico)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, self.options["data_root"], "images/ico/favicon.ico")},
                ),
                # images
                (
                    r"{0}/images/(.*)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, self.options["data_root"], "images")},
                ),
                # cached images
                (
                    r"{0}/cache/images/(.*)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, sickbeard.CACHE_DIR, "images")},
                ),
                # css
                (
                    r"{0}/css/(.*)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, self.options["data_root"], "css")},
                ),
                # javascript
                (
                    r"{0}/js/(.*)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, self.options["data_root"], "js")},
                ),
                # fonts
                (
                    r"{0}/fonts/(.*)".format(self.options["web_root"]),
                    StaticFileHandler,
                    {"path": ek(os.path.join, self.options["data_root"], "fonts")},
                ),
                # videos
                (r"{0}/videos/(.*)".format(self.options["web_root"]), StaticFileHandler, {"path": self.video_root}),
            ],
        )
Example #8
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % options['web_root']

    # cherrypy setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = ('text/html',
                 'text/plain',
                 'text/css',
                 'text/javascript',
                 'application/javascript',
                 'text/x-javascript',
                 'application/x-javascript',
                 'text/x-json',
                 'application/json'
    )

    options_dict = {
        'server.socket_port': options['port'],
        'server.socket_host': options['host'],
        'log.screen': False,
        'engine.autoreload.on': False,
        'engine.autoreload.frequency': 100,
        'engine.reexec_retry': 100,
        'tools.gzip.on': True,
        'tools.gzip.mime_types': mime_gzip,
        'error_page.401': http_error_401_hander,
        'error_page.404': http_error_404_hander,
    }

    if enable_https:
        options_dict['server.ssl_certificate'] = https_cert
        options_dict['server.ssl_private_key'] = https_key

        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(options['port']) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options['log_dir'] and os.path.isdir(options['log_dir']):
        cherrypy.config.update({'log.access_file': os.path.join(options['log_dir'], "cherrypy.log")})
        logger.log('Using %s for cherrypy log' % cherrypy.config['log.access_file'])

    conf = {
        '/': {
            'tools.staticdir.root': options['data_root'],
            'tools.encode.on': True,
            'tools.encode.encoding': 'utf-8',
            'tools.handle_reverse_proxy.on': True,
        },
        '/images': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'images'
        },
        '/js': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'js'
        },
        '/css': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'css'
        },
    }
    app = cherrypy.tree.mount(WebInterface(), options['web_root'], conf)

    # auth
    if options['username'] != "" and options['password'] != "":
        if sickbeard.CALENDAR_UNPROTECTED:
            checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options['username']: options['password']})
            app.merge({
                '/': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickRage',
                    'tools.auth_basic.checkpassword': checkpassword
                },
                '/api': {
                    'tools.auth_basic.on': False
                },
                '/calendar': {
                    'tools.auth_basic.on': False
                },
                '/api/builder': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickRage',
                    'tools.auth_basic.checkpassword': checkpassword
                }
            })
        else:
            checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options['username']: options['password']})
            app.merge({
                '/': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickRage',
                    'tools.auth_basic.checkpassword': checkpassword
                },
                '/api': {
                    'tools.auth_basic.on': False
                },
                '/api/builder': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickRage',
                    'tools.auth_basic.checkpassword': checkpassword
                }
            })


    cherrypy.server.thread_pool = 30
    cherrypy.server.start()
    cherrypy.server.wait()
Example #9
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    # tornado setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    # Load the app
    app = Application([],
                        debug=False,
                        gzip=True,
                        xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                        cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo='
    )

    # Main Handler
    app.add_handlers(".*$", [
        (r"/", RedirectHandler, {'url': '%s/home/' % options['web_root']}),
        (r'%s/api/(.*)(/?)' % options['web_root'], webapi.Api),
        (r'%s/(.*)(/?)' % options['web_root'], webserve.IndexHandler)
    ])

    # Static Path Handler
    app.add_handlers(".*$", [
        (r'%s/(favicon\.ico)' % options['web_root'], MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'images/ico/favicon.ico')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'images'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'images'),
                    os.path.join(sickbeard.CACHE_DIR, 'images')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'css'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'css')]}),
        (r'%s/%s/(.*)(/?)' % (options['web_root'], 'js'), MultiStaticFileHandler,
         {'paths': [os.path.join(options['data_root'], 'js')]})

    ])

    global server

    if enable_https:
        protocol = "https"
        server = HTTPServer(app, no_keep_alive=True,
                            ssl_options={"certfile": https_cert, "keyfile": https_key})
    else:
        protocol = "http"
        server = HTTPServer(app, no_keep_alive=True)

    logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(
        options['port']) + "/")

    try:
        server.listen(options['port'], options['host'])
    except:
        pass
Example #10
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.name = "TORNADO"
        self.alive = True

        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options[b'port'], int)
        assert 'gui_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options[b'web_root']:
            sickbeard.WEB_ROOT = self.options[b'web_root'] = ('/' + self.options[b'web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options[b'api_root'] = r'%s/api/%s' % (sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options[b'enable_https']
        self.https_cert = self.options[b'https_cert']
        self.https_key = self.options[b'https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and ek(os.path.exists, self.https_cert)) or not (
                        self.https_key and ek(os.path.exists, self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logging.info("Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert) and ek(os.path.exists, self.https_key)):
                logging.warning("Disabled HTTPS because of missing CERT and KEY files")
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application([],
                               debug=sickbeard.DEBUG,
                               autoreload=False,
                               gzip=sickbeard.WEB_USE_GZIP,
                               xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                               cookie_secret=sickbeard.WEB_COOKIE_SECRET,
                               login_url='%s/login/' % self.options[b'web_root'],
                               )

        # Main Handlers
        self.app.add_handlers('.*$', [
            # webapi handler
            (r'%s(/?.*)' % self.options[b'api_root'], ApiHandler),

            # webapi key retrieval
            (r'%s/getkey(/?.*)' % self.options[b'web_root'], KeyHandler),

            # webapi builder redirect
            (r'%s/api/builder' % self.options[b'web_root'], RedirectHandler,
             {"url": self.options[b'web_root'] + '/apibuilder/'}),

            # webui login/logout handlers
            (r'%s/login(/?)' % self.options[b'web_root'], LoginHandler),
            (r'%s/logout(/?)' % self.options[b'web_root'], LogoutHandler),

            # webui handlers
        ] + route.get_routes(self.options[b'web_root']))

        # Web calendar handler (Needed because option Unprotected calendar)
        self.app.add_handlers('.*$', [
            (r'%s/calendar' % self.options[b'web_root'], CalendarHandler),
        ])

        # Static File Handlers
        self.app.add_handlers(".*$", [
            # favicon
            (r'%s/(favicon\.ico)' % self.options[b'web_root'], StaticFileHandler,
             {"path": ek(os.path.join, self.options[b'gui_root'], 'images/ico/favicon.ico')}),

            # images
            (r'%s.*?/images/(.*)' % self.options[b'web_root'], StaticImageHandler,
             {"path": ek(os.path.join, self.options[b'gui_root'], 'images')}),

            # css
            (r'%s/css/(.*)' % self.options[b'web_root'], StaticFileHandler,
             {"path": ek(os.path.join, self.options[b'gui_root'], 'css')}),

            # javascript
            (r'%s/js/(.*)' % self.options[b'web_root'], StaticFileHandler,
             {"path": ek(os.path.join, self.options[b'gui_root'], 'js')}),

            # videos
        ] + [(r'%s/videos/(.*)' % self.options[b'web_root'], StaticFileHandler,
              {"path": self.video_root})])
Example #11
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    options.setdefault('ip_whitelist',   '')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % options['web_root']

    # cherrypy setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = ('text/html',
                 'text/plain',
                 'text/css',
                 'text/javascript',
                 'application/javascript',
                 'text/x-javascript',
                 'application/x-javascript',
                 'text/x-json',
                 'application/json'
                 )

    options_dict = {
        'server.socket_port': options['port'],
        'server.socket_host': options['host'],
        'log.screen': False,
        'engine.autoreload.on': False,
        'engine.autoreload.frequency': 100,
        'engine.reexec_retry': 100,
        'tools.gzip.on': True,
        'tools.gzip.mime_types': mime_gzip,
        'error_page.401': http_error_401_hander,
        'error_page.404': http_error_404_hander,
    }

    if enable_https:
        options_dict['server.ssl_certificate'] = https_cert
        options_dict['server.ssl_private_key'] = https_key
        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting Sick Beard on " + protocol + "://" + str(options['host']) + ":" + str(options['port']) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options['log_dir'] and os.path.isdir(options['log_dir']):
        cherrypy.config.update({ 'log.access_file': os.path.join(options['log_dir'], "cherrypy.log") })
        logger.log(u'Using %s for cherrypy log' % cherrypy.config['log.access_file'])

    conf = {
        '/': {
            'tools.staticdir.root': options['data_root'],
            'tools.encode.on': True,
            'tools.encode.encoding': 'utf-8',
        },
        '/images': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'images'
        },
        '/js': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'js'
        },
        '/css': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'css'
        },
    }
    app = cherrypy.tree.mount(WebInterface(), options['web_root'], conf)

    def addressInNetwork(ip,net):
            """Is an address in a network. 
               Returns: 
                  True - If 'ip' is an address in 'net' which is a string in the format x.x.x.x/y
                  False - If 'ip' not in 'net' or if there is an error."""
            
            if net == "":
                return False
            
            try:
                ipaddr = struct.unpack('>L',socket.inet_aton(ip))[0]
                netaddr,bits = net.split('/')
                ipnet = struct.unpack('>L',socket.inet_aton(netaddr))[0]
                mask = ((2L<<(int(bits))-1) - 1)<<(32-int(bits))

                return ipaddr & mask == ipnet & mask
            except ValueError: # Will get here if ip_whitelist is incorrectly formatted
                logger.log(u'Configuration Error: \'ip_whitelist\' option is malformed. Value: %s, assuming no whitelisted hosts until restart.' % net, logger.ERROR )
                options['ip_whitelist'] = ""
                
                return False

    def check_ip():
            """Will check current request address against 'ip_whitelist' and will disable authentication with those that match. 'ip_whitelist' is a list in the form of 'a.a.a.a/b[,c.c.c.c/d]'"""
            try:
                # Iterate through whitelisted networks
                for whitelist_network in options['ip_whitelist'].split(','): 
                        # Check if current network matches remote address
                        if addressInNetwork(cherrypy.request.remote.ip, whitelist_network.strip()):
                            
                                # Search for and remove basic_auth hook from list of hooks to execute
                                old_hooks = cherrypy.request.hooks['before_handler']
                                new_hooks = []
                                for hook in old_hooks:
                                        if hook.callback != cherrypy.lib.auth_basic.basic_auth:
                                                new_hooks.append(hook)

                                cherrypy.request.hooks['before_handler'] = new_hooks
                                
                                # No need to continue checking if already matched once
                                return True 
            except Exception:
                logger.log(u'webserverInit.py:check_ip() - Error while processing whitelist. ip_whitelist = %s' % options['ip_whitelist'], logger.ERROR)

            return True

    if options['ip_whitelist'] != "":
            checkipaddress = cherrypy.Tool('on_start_resource', check_ip, 1)
            cherrypy.tools.checkipaddress = checkipaddress

            app.merge({'/': { 'tools.checkipaddress.on': True } })


    # auth
    if options['username'] != "" and options['password'] != "":
        checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options['username']: options['password']})
        app.merge({
            '/': {
                'tools.auth_basic.on': True,
                'tools.auth_basic.realm': 'SickBeard',
                'tools.auth_basic.checkpassword': checkpassword
            },
            '/api': {
                'tools.auth_basic.on': False
            },
            '/api/builder': {
                'tools.auth_basic.on': True,
                'tools.auth_basic.realm': 'SickBeard',
                'tools.auth_basic.checkpassword': checkpassword
            }
        })

    cherrypy.server.start()
    cherrypy.server.wait()
Example #12
0
def initWebServer(options = {}):
        options.setdefault('port',      8081)
        options.setdefault('host',      '0.0.0.0')
        options.setdefault('log_dir',   None)
        options.setdefault('username',    '')
        options.setdefault('password',    '')
        options.setdefault('web_root',   '/')
        assert isinstance(options['port'], int)
        assert 'data_root' in options

        def http_error_401_hander(status, message, traceback, version):
            """ Custom handler for 401 error """
            if status != "401 Unauthorized":
                logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
                logger.log(traceback, logger.DEBUG)
            return r'''
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

        def http_error_404_hander(status, message, traceback, version):
            """ Custom handler for 404 error, redirect back to main page """
            return r'''
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % '/'

        # cherrypy setup
        enable_https = options['enable_https']
        https_port = options['https_port']
        https_cert = options['https_cert']
        https_key = options['https_key']
        if enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
                create_https_certificates(https_cert, https_key)

            if not (os.path.exists(https_cert) and os.path.exists(https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                enable_https = False

            if enable_https:
                if https_port:
                    logger.log(u"Starting Sick Beard on http://" + str(options['host']) + ":" + str(options['port']) + "/")
                    # Prepare an extra server for the HTTP port
                    http_server = _cpwsgi_server.CPWSGIServer()
                    http_server.bind_addr = (options['host'], options['port'])
                    #secure_server.ssl_certificate = https_cert
                    #secure_server.ssl_private_key = https_key
                    adapter = _cpserver.ServerAdapter(cherrypy.engine, http_server, http_server.bind_addr)
                    adapter.subscribe()
                    
                    logger.log(u"Starting Sick Beard on https://" + str(options['host']) + ":" + str(https_port) + "/")
                    cherrypy.config.update({
                            'server.socket_port': int(https_port),
                            'server.socket_host': options['host'],
                            'log.screen':         False,
                            'error_page.401':     http_error_401_hander,
                            'error_page.404':     http_error_404_hander,
                            'server.ssl_certificate' : https_cert,
                            'server.ssl_private_key' : https_key,
                    })
                else:
                    logger.log(u"Starting Sick Beard on https://" + str(options['host']) + ":" + str(options['port']) + "/")
                    cherrypy.config.update({
                            'server.socket_port': options['port'],
                            'server.socket_host': options['host'],
                            'log.screen':         False,
                            'error_page.401':     http_error_401_hander,
                            'error_page.404':     http_error_404_hander,
                            'server.ssl_certificate' : https_cert,
                            'server.ssl_private_key' : https_key,
                    })
        else:
            logger.log(u"Starting Sick Beard on http://" + str(options['host']) + ":" + str(options['port']) + "/")
            cherrypy.config.update({
                    'server.socket_port': options['port'],
                    'server.socket_host': options['host'],
                    'log.screen':         False,
                    'error_page.401':     http_error_401_hander,
                    'error_page.404':     http_error_404_hander,
            })

        # setup cherrypy logging
        if options['log_dir'] and os.path.isdir(options['log_dir']):
                cherrypy.config.update({ 'log.access_file': os.path.join(options['log_dir'], "cherrypy.log") })
                logger.log('Using %s for cherrypy log' % cherrypy.config['log.access_file'])

        conf = {
                        '/': {
                                'tools.staticdir.root': options['data_root'],
                                'tools.encode.on': True,
                                'tools.encode.encoding': 'utf-8',
                        },
                        '/images': {
                                'tools.staticdir.on':  True,
                                'tools.staticdir.dir': 'images'
                        },
                        '/js':     {
                                'tools.staticdir.on':  True,
                                'tools.staticdir.dir': 'js'
                        },
                        '/css':    {
                                'tools.staticdir.on':  True,
                                'tools.staticdir.dir': 'css'
                        },
        }
        app = cherrypy.tree.mount(WebInterface(), options['web_root'], conf)

        # auth
        if options['username'] != "" and options['password'] != "":
                checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options['username']: options['password']})
                app.merge({
                        '/': {
                                'tools.auth_basic.on':            True,
                                'tools.auth_basic.realm':         'SickBeard',
                                'tools.auth_basic.checkpassword': checkpassword
                        },
                        '/api':{
                                'tools.auth_basic.on':            False
                        },
                        '/api/builder':{
                                'tools.auth_basic.on':            True,
                                'tools.auth_basic.realm':         'SickBeard',
                                'tools.auth_basic.checkpassword': checkpassword
                        }
                })


        cherrypy.engine.start()
        cherrypy.server.wait()
Example #13
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.name = "TORNADO"
        self.alive = True

        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options[b'port'], int)
        assert 'gui_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options[b'web_root']:
            sickbeard.WEB_ROOT = self.options[b'web_root'] = (
                '/' + self.options[b'web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options[b'api_root'] = r'%s/api/%s' % (sickbeard.WEB_ROOT,
                                                    sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options[b'enable_https']
        self.https_cert = self.options[b'https_cert']
        self.https_key = self.options[b'https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert
                    and ek(os.path.exists, self.https_cert)) or not (
                        self.https_key and ek(os.path.exists, self.https_key)):
                if not create_https_certificates(self.https_cert,
                                                 self.https_key):
                    logging.info(
                        "Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert)
                    and ek(os.path.exists, self.https_key)):
                logging.warning(
                    "Disabled HTTPS because of missing CERT and KEY files")
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=sickbeard.DEBUG,
            autoreload=False,
            gzip=sickbeard.WEB_USE_GZIP,
            xheaders=sickbeard.HANDLE_REVERSE_PROXY,
            cookie_secret=sickbeard.WEB_COOKIE_SECRET,
            login_url='%s/login/' % self.options[b'web_root'],
        )

        # Main Handlers
        self.app.add_handlers(
            '.*$',
            [
                # webapi handler
                (r'%s(/?.*)' % self.options[b'api_root'], ApiHandler),

                # webapi key retrieval
                (r'%s/getkey(/?.*)' % self.options[b'web_root'], KeyHandler),

                # webapi builder redirect
                (r'%s/api/builder' % self.options[b'web_root'],
                 RedirectHandler, {
                     "url": self.options[b'web_root'] + '/apibuilder/'
                 }),

                # webui login/logout handlers
                (r'%s/login(/?)' % self.options[b'web_root'], LoginHandler),
                (r'%s/logout(/?)' % self.options[b'web_root'], LogoutHandler),

                # webui handlers
            ] + route.get_routes(self.options[b'web_root']))

        # Web calendar handler (Needed because option Unprotected calendar)
        self.app.add_handlers('.*$', [
            (r'%s/calendar' % self.options[b'web_root'], CalendarHandler),
        ])

        # Static File Handlers
        self.app.add_handlers(
            ".*$",
            [
                # favicon
                (r'%s/(favicon\.ico)' % self.options[b'web_root'],
                 StaticFileHandler, {
                     "path":
                     ek(os.path.join, self.options[b'gui_root'],
                        'images/ico/favicon.ico')
                 }),

                # images
                (r'%s.*?/images/(.*)' % self.options[b'web_root'],
                 StaticImageHandler, {
                     "path": ek(os.path.join, self.options[b'gui_root'],
                                'images')
                 }),

                # css
                (r'%s/css/(.*)' % self.options[b'web_root'], StaticFileHandler,
                 {
                     "path": ek(os.path.join, self.options[b'gui_root'], 'css')
                 }),

                # javascript
                (r'%s/js/(.*)' % self.options[b'web_root'], StaticFileHandler,
                 {
                     "path": ek(os.path.join, self.options[b'gui_root'], 'js')
                 }),

                # videos
            ] + [(r'%s/videos/(.*)' % self.options[b'web_root'],
                  StaticFileHandler, {
                      "path": self.video_root
                  })])
Example #14
0
def initWebServer(options={}):
    options.setdefault("port", 8081)
    options.setdefault("host", "0.0.0.0")
    options.setdefault("log_dir", None)
    options.setdefault("username", "")
    options.setdefault("password", "")
    options.setdefault("web_root", "/")
    assert isinstance(options["port"], int)
    assert "data_root" in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r"""
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
""" % (
            "Access denied",
            status,
        )

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return (
            r"""
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
"""
            % options["web_root"]
        )

    # cherrypy setup
    enable_https = options["enable_https"]
    https_cert = options["https_cert"]
    https_key = options["https_key"]

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create cert/key files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = (
        "text/html",
        "text/plain",
        "text/css",
        "text/javascript",
        "application/javascript",
        "text/x-javascript",
        "application/x-javascript",
        "text/x-json",
        "application/json",
    )

    options_dict = {
        "server.socket_port": options["port"],
        "server.socket_host": options["host"],
        "log.screen": False,
        "engine.autoreload.on": False,
        "engine.autoreload.frequency": 100,
        "engine.reexec_retry": 100,
        "tools.gzip.on": True,
        "tools.gzip.mime_types": mime_gzip,
        "error_page.401": http_error_401_hander,
        "error_page.404": http_error_404_hander,
    }

    if enable_https:
        options_dict["server.ssl_certificate"] = https_cert
        options_dict["server.ssl_private_key"] = https_key
        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting Sick Beard on " + protocol + "://" + str(options["host"]) + ":" + str(options["port"]) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options["log_dir"] and os.path.isdir(options["log_dir"]):
        cherrypy.config.update({"log.access_file": os.path.join(options["log_dir"], "cherrypy.log")})
        logger.log(u"Using %s for cherrypy log" % cherrypy.config["log.access_file"])

    conf = {
        "/": {"tools.staticdir.root": options["data_root"], "tools.encode.on": True, "tools.encode.encoding": "utf-8"},
        "/images": {"tools.staticdir.on": True, "tools.staticdir.dir": "images"},
        "/js": {"tools.staticdir.on": True, "tools.staticdir.dir": "js"},
        "/css": {"tools.staticdir.on": True, "tools.staticdir.dir": "css"},
    }
    app = cherrypy.tree.mount(WebInterface(), options["web_root"], conf)

    # auth
    if options["username"] != "" and options["password"] != "":
        checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options["username"]: options["password"]})
        app.merge(
            {
                "/": {
                    "tools.auth_basic.on": True,
                    "tools.auth_basic.realm": "SickBeard",
                    "tools.auth_basic.checkpassword": checkpassword,
                },
                "/api": {"tools.auth_basic.on": False},
                "/api/builder": {
                    "tools.auth_basic.on": True,
                    "tools.auth_basic.realm": "SickBeard",
                    "tools.auth_basic.checkpassword": checkpassword,
                },
            }
        )

    cherrypy.server.start()
    cherrypy.server.wait()
Example #15
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options['web_root']:
            sickbeard.WEB_ROOT = self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options['api_root'] = r'%s/api/%s' % (sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and os.path.exists(self.https_cert)) or not (
                        self.https_key and os.path.exists(self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application([],
                                 debug=True,
                                 autoreload=False,
                                 gzip=True,
                                 xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                                 cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
                                 login_url='/login/',
        )

        # Main Handlers
        self.app.add_handlers('.*$', [
            # webapi handler
            (r'%s(/?.*)' % self.options['api_root'], ApiHandler),

            # webapi key retrieval
            (r'%s/getkey(/?.*)' % self.options['web_root'], KeyHandler),

            # webapi builder redirect
            (r'%s/api/builder' % self.options['web_root'], RedirectHandler, {"url": self.options['web_root'] + '/apibuilder/'}),

            # webui login/logout handlers
            (r'%s/login(/?.*)' % self.options['web_root'], LoginHandler),
            (r'%s/logout(/?.*)' % self.options['web_root'], LogoutHandler),

            # webui redirect
            (r'/', RedirectHandler, {"url": self.options['web_root'] + '/home/'}),

            # webui handlers
        ] + route.get_routes(self.options['web_root']))

        # Static File Handlers
        self.app.add_handlers(".*$", [
            # favicon
            (r'%s/(favicon\.ico)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),

            # images
            (r'%s/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'images')}),

            # cached images
            (r'%s/cache/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(sickbeard.CACHE_DIR, 'images')}),

            # css
            (r'%s/css/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'css')}),

            # javascript
            (r'%s/js/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'js')}),

            # videos
        ] + [(r'%s/videos/(.*)' % self.options['web_root'], StaticFileHandler,
              {"path": self.video_root})])
Example #16
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = 'TORNADO'
        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', None)
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # web root
        self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options[
            'web_root'] else ''

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and os.path.exists(self.https_cert)) or not (
                self.https_key and os.path.exists(self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u'Unable to create CERT/KEY files, disabling HTTPS')
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
                logger.log(u'Disabled HTTPS because of missing CERT and KEY files', logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application([],
                                 debug=True,
                                 autoreload=False,
                                 gzip=True,
                                 xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                                 cookie_secret=sickbeard.COOKIE_SECRET,
                                 login_url='%s/login/' % self.options['web_root'],
        )

        # Main Handler
        self.app.add_handlers('.*$', [
            (r'%s/api/builder(/?)(.*)' % self.options['web_root'], webserve.ApiBuilder),
            (r'%s/api(/?.*)' % self.options['web_root'], webapi.Api),
            (r'%s/cache(/?.*)' % self.options['web_root'], webserve.Cache),
            (r'%s/config/general(/?.*)' % self.options['web_root'], webserve.ConfigGeneral),
            (r'%s/config/search(/?.*)' % self.options['web_root'], webserve.ConfigSearch),
            (r'%s/config/providers(/?.*)' % self.options['web_root'], webserve.ConfigProviders),
            (r'%s/config/subtitles(/?.*)' % self.options['web_root'], webserve.ConfigSubtitles),
            (r'%s/config/postProcessing(/?.*)' % self.options['web_root'], webserve.ConfigPostProcessing),
            (r'%s/config/notifications(/?.*)' % self.options['web_root'], webserve.ConfigNotifications),
            (r'%s/config/anime(/?.*)' % self.options['web_root'], webserve.ConfigAnime),
            (r'%s/config(/?.*)' % self.options['web_root'], webserve.Config),
            (r'%s/errorlogs(/?.*)' % self.options['web_root'], webserve.ErrorLogs),
            (r'%s/history(/?.*)' % self.options['web_root'], webserve.History),
            (r'%s/home/is_alive(/?.*)' % self.options['web_root'], webserve.IsAliveHandler),
            (r'%s/home/addShows(/?.*)' % self.options['web_root'], webserve.NewHomeAddShows),
            (r'%s/home/postprocess(/?.*)' % self.options['web_root'], webserve.HomePostProcess),
            (r'%s/home(/?.*)' % self.options['web_root'], webserve.Home),
            (r'%s/manage/manageSearches(/?.*)' % self.options['web_root'], webserve.ManageSearches),
            (r'%s/manage/showQueueOverview(/?.*)' % self.options['web_root'], webserve.showQueueOverview),
            (r'%s/manage/(/?.*)' % self.options['web_root'], webserve.Manage),
            (r'%s/ui(/?.*)' % self.options['web_root'], webserve.UI),
            (r'%s/browser(/?.*)' % self.options['web_root'], webserve.WebFileBrowser),
            (r'%s(/?.*)' % self.options['web_root'], webserve.MainHandler),
        ])

        # webui login/logout handlers
        self.app.add_handlers('.*$', [
            (r'%s/login(/?)' % self.options['web_root'], webserve.LoginHandler),
            (r'%s/logout(/?)' % self.options['web_root'], webserve.LogoutHandler),
        ])

        # Web calendar handler (Needed because option Unprotected calendar)
        self.app.add_handlers('.*$', [
            (r'%s/calendar' % self.options['web_root'], webserve.CalendarHandler),
        ])

        # Static File Handlers
        self.app.add_handlers('.*$', [
            # favicon
            (r'%s/(favicon\.ico)' % self.options['web_root'], StaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),

            # images
            (r'%s/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'images')}),

            # cached images
            (r'%s/cache/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {'path': os.path.join(sickbeard.CACHE_DIR, 'images')}),

            # css
            (r'%s/css/(.*)' % self.options['web_root'], StaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'css')}),

            # javascript
            (r'%s/js/(.*)' % self.options['web_root'], StaticFileHandler,
             {'path': os.path.join(self.options['data_root'], 'js')}),
        ])
Example #17
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', None)
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')
                                    ) if self.options['web_root'] else ''

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert
                    and os.path.exists(self.https_cert)) or not (
                        self.https_key and os.path.exists(self.https_key)):
                if not create_https_certificates(self.https_cert,
                                                 self.https_key):
                    logger.log(
                        u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert)
                    and os.path.exists(self.https_key)):
                logger.log(
                    u"Disabled HTTPS because of missing CERT and KEY files",
                    logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=True,
            autoreload=False,
            gzip=True,
            xheaders=sickbeard.HANDLE_REVERSE_PROXY,
            cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=')

        # Main Handler
        self.app.add_handlers(
            ".*$",
            [(r'%s/api/(.*)(/?)' % self.options['web_root'], webapi.Api),
             (r'%s/(.*)(/?)' % self.options['web_root'], webserve.MainHandler),
             (r'(.*)', webserve.MainHandler)])

        # Static Path Handler
        self.app.add_handlers(".*$", [
            (r'%s/(favicon\.ico)' % self.options['web_root'],
             MultiStaticFileHandler, {
                 'paths': [
                     os.path.join(self.options['data_root'],
                                  'images/ico/favicon.ico')
                 ]
             }),
            (r'%s/%s/(.*)(/?)' %
             (self.options['web_root'], 'images'), MultiStaticFileHandler, {
                 'paths': [
                     os.path.join(self.options['data_root'], 'images'),
                     os.path.join(sickbeard.CACHE_DIR, 'images')
                 ]
             }),
            (r'%s/%s/(.*)(/?)' %
             (self.options['web_root'], 'css'), MultiStaticFileHandler, {
                 'paths': [os.path.join(self.options['data_root'], 'css')]
             }),
            (r'%s/%s/(.*)(/?)' %
             (self.options['web_root'], 'js'), MultiStaticFileHandler, {
                 'paths': [os.path.join(self.options['data_root'], 'js')]
             }),
        ])

        # Static Videos Path
        if self.video_root:
            self.app.add_handlers(".*$", [
                (r'%s/%s/(.*)' % (self.options['web_root'], 'videos'),
                 MultiStaticFileHandler, {
                     'paths': [self.video_root]
                 }),
            ])
Example #18
0
def initWebServer(options={}):
    options.setdefault("port", 8081)
    options.setdefault("host", "0.0.0.0")
    options.setdefault("log_dir", None)
    options.setdefault("username", "")
    options.setdefault("password", "")
    options.setdefault("whitelist", "")
    options.setdefault("web_root", "/")
    assert isinstance(options["port"], int)
    assert "data_root" in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r"""<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
""" % (
            "Access denied",
            status,
        )

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return (
            r"""<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
"""
            % options["web_root"]
        )

    # cherrypy setup
    enable_https = options["enable_https"]
    https_cert = options["https_cert"]
    https_key = options["https_key"]

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = (
        "text/html",
        "text/plain",
        "text/css",
        "text/javascript",
        "application/javascript",
        "text/x-javascript",
        "application/x-javascript",
        "text/x-json",
        "application/json",
    )

    options_dict = {
        "server.socket_port": options["port"],
        "server.socket_host": options["host"],
        "log.screen": False,
        "engine.autoreload.on": False,
        "engine.autoreload.frequency": 100,
        "engine.reexec_retry": 100,
        "tools.gzip.on": True,
        "tools.gzip.mime_types": mime_gzip,
        "error_page.401": http_error_401_hander,
        "error_page.404": http_error_404_hander,
    }

    if enable_https:
        options_dict["server.ssl_certificate"] = https_cert
        options_dict["server.ssl_private_key"] = https_key
        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting Sick Beard on " + protocol + "://" + str(options["host"]) + ":" + str(options["port"]) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options["log_dir"] and os.path.isdir(options["log_dir"]):
        cherrypy.config.update({"log.access_file": os.path.join(options["log_dir"], "cherrypy.log")})
        logger.log(u"Using %s for cherrypy log" % cherrypy.config["log.access_file"])

    conf = {
        "/": {"tools.staticdir.root": options["data_root"], "tools.encode.on": True, "tools.encode.encoding": "utf-8"},
        "/images": {"tools.staticdir.on": True, "tools.staticdir.dir": "images"},
        "/js": {"tools.staticdir.on": True, "tools.staticdir.dir": "js"},
        "/css": {"tools.staticdir.on": True, "tools.staticdir.dir": "css"},
    }
    app = cherrypy.tree.mount(WebInterface(), options["web_root"], conf)

    def addressInNetwork(ip, net):
        """Is an address in a network. 
           Returns: 
              True - If 'ip' is an address in 'net' which is a string in the format x.x.x.x/y
              False - If 'ip' not in 'net' or if there is an error."""

        if net == "":
            return False

        try:
            ipaddr = struct.unpack(">L", socket.inet_aton(ip))[0]
            netaddr, bits = net.split("/")
            ipnet = struct.unpack(">L", socket.inet_aton(netaddr))[0]
            mask = ((2L << (int(bits)) - 1) - 1) << (32 - int(bits))

            return ipaddr & mask == ipnet & mask
        except ValueError:  # Will get here if whitelist is incorrectly formatted
            logger.log(
                u"Configuration Error: 'whitelist' option is malformed. Value: %s, assuming no whitelisted hosts until restart."
                % net,
                logger.ERROR,
            )
            options["whitelist"] = ""

            return False

    def check_ip():
        """Will check current request address against 'whitelist' and will disable authentication with those that match. 'whitelist' is a list in the form of 'a.a.a.a/b[,c.c.c.c/d]'"""
        try:
            # Iterate through whitelisted networks
            for whitelist_network in options["whitelist"].split(","):
                # Check if current network matches remote address
                if addressInNetwork(cherrypy.request.remote.ip, whitelist_network.strip()):

                    # Search for and remove basic_auth hook from list of hooks to execute
                    old_hooks = cherrypy.request.hooks["before_handler"]
                    new_hooks = []
                    for hook in old_hooks:
                        if hook.callback != cherrypy.lib.auth_basic.basic_auth:
                            new_hooks.append(hook)

                    cherrypy.request.hooks["before_handler"] = new_hooks

                    # No need to continue checking if already matched once
                    return True
        except Exception:
            logger.log(
                u"webserverInit.py:check_ip() - Error while processing whitelist. whitelist = %s"
                % options["whitelist"],
                logger.ERROR,
            )

        return True

    if options["whitelist"] != "":
        checkipaddress = cherrypy.Tool("on_start_resource", check_ip, 1)
        cherrypy.tools.checkipaddress = checkipaddress

        app.merge({"/": {"tools.checkipaddress.on": True}})

    # auth
    if options["username"] != "" and options["password"] != "":
        checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options["username"]: options["password"]})
        app.merge(
            {
                "/": {
                    "tools.auth_basic.on": True,
                    "tools.auth_basic.realm": "SickBeard",
                    "tools.auth_basic.checkpassword": checkpassword,
                },
                "/api": {"tools.auth_basic.on": False},
                "/api/builder": {
                    "tools.auth_basic.on": True,
                    "tools.auth_basic.realm": "SickBeard",
                    "tools.auth_basic.checkpassword": checkpassword,
                },
            }
        )

    cherrypy.server.start()
    cherrypy.server.wait()
Example #19
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message),
                       logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script type="text/javascript" charset="utf-8">
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % options['web_root']

    # cherrypy setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (
                https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files",
                       logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = ('text/html', 'text/plain', 'text/css', 'text/javascript',
                 'application/javascript', 'text/x-javascript',
                 'application/x-javascript', 'text/x-json', 'application/json')

    options_dict = {
        'server.socket_port': options['port'],
        'server.socket_host': options['host'],
        'log.screen': False,
        'engine.autoreload.on': False,
        'engine.autoreload.frequency': 100,
        'engine.reexec_retry': 100,
        'tools.gzip.on': True,
        'tools.gzip.mime_types': mime_gzip,
        'error_page.401': http_error_401_hander,
        'error_page.404': http_error_404_hander,
    }

    if enable_https:
        options_dict['server.ssl_certificate'] = https_cert
        options_dict['server.ssl_private_key'] = https_key
        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting Sick Beard on " + protocol + "://" +
               str(options['host']) + ":" + str(options['port']) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options['log_dir'] and os.path.isdir(options['log_dir']):
        cherrypy.config.update({
            'log.access_file':
            os.path.join(options['log_dir'], "cherrypy.log")
        })
        logger.log('Using %s for cherrypy log' %
                   cherrypy.config['log.access_file'])

    conf = {
        '/': {
            'tools.staticdir.root': options['data_root'],
            'tools.encode.on': True,
            'tools.encode.encoding': 'utf-8',
        },
        '/images': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'images'
        },
        '/js': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'js'
        },
        '/css': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'css'
        },
    }
    app = cherrypy.tree.mount(WebInterface(), options['web_root'], conf)

    # auth
    if options['username'] != "" and options['password'] != "":
        if sickbeard.CALENDAR_PROTECTED:
            checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(
                {options['username']: options['password']})
            app.merge({
                '/': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickBeard',
                    'tools.auth_basic.checkpassword': checkpassword
                },
                '/api': {
                    'tools.auth_basic.on': False
                },
                '/api/builder': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickBeard',
                    'tools.auth_basic.checkpassword': checkpassword
                }
            })
        else:
            checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(
                {options['username']: options['password']})
            app.merge({
                '/': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickBeard',
                    'tools.auth_basic.checkpassword': checkpassword
                },
                '/api': {
                    'tools.auth_basic.on': False
                },
                '/calendar': {
                    'tools.auth_basic.on': False
                },
                '/api/builder': {
                    'tools.auth_basic.on': True,
                    'tools.auth_basic.realm': 'SickBeard',
                    'tools.auth_basic.checkpassword': checkpassword
                }
            })

    cherrypy.server.start()
    cherrypy.server.wait()
Example #20
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', None)
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options[
            'web_root'] else ''

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and os.path.exists(self.https_cert)) or not (
                self.https_key and os.path.exists(self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application([],
                                 debug=True,
                                 autoreload=False,
                                 gzip=True,
                                 xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                                 cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo='
        )

        # Main Handler
        self.app.add_handlers(".*$", [
            (r'%s/api/(.*)(/?)' % self.options['web_root'], webapi.Api),
            (r'%s/(.*)(/?)' % self.options['web_root'], webserve.MainHandler),
            (r'(.*)', webserve.MainHandler)
        ])

        # Static Path Handler
        self.app.add_handlers(".*$", [
            (r'%s/(favicon\.ico)' % self.options['web_root'], MultiStaticFileHandler,
             {'paths': [os.path.join(self.options['data_root'], 'images/ico/favicon.ico')]}),
            (r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
             {'paths': [os.path.join(self.options['data_root'], 'images'),
                        os.path.join(sickbeard.CACHE_DIR, 'images')]}),
            (r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'css'), MultiStaticFileHandler,
             {'paths': [os.path.join(self.options['data_root'], 'css')]}),
            (r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'js'), MultiStaticFileHandler,
             {'paths': [os.path.join(self.options['data_root'], 'js')]}),
        ])

        # Static Videos Path
        if self.video_root:
            self.app.add_handlers(".*$", [
                (r'%s/%s/(.*)' % (self.options['web_root'], 'videos'), MultiStaticFileHandler,
                 {'paths': [self.video_root]}),
            ])
Example #21
0
    def __init__(self, options=None, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options or {}
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        self.server = None

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options['web_root']:
            sickbeard.WEB_ROOT = self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options['api_root'] = r'{0}/api/{1}'.format(sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and ek(os.path.exists, self.https_cert)) or not (
                    self.https_key and ek(os.path.exists, self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (ek(os.path.exists, self.https_cert) and ek(os.path.exists, self.https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=True,
            autoreload=False,
            gzip=sickbeard.WEB_USE_GZIP,
            cookie_secret=sickbeard.WEB_COOKIE_SECRET,
            login_url='{0}/login/'.format(self.options['web_root']),
        )

        # Main Handlers
        self.app.add_handlers('.*$', [
            # webapi handler
            (r'{0}(/?.*)'.format(self.options['api_root']), ApiHandler),

            # webapi key retrieval
            (r'{0}/getkey(/?.*)'.format(self.options['web_root']), KeyHandler),

            # webapi builder redirect
            (r'{0}/api/builder'.format(self.options['web_root']), RedirectHandler, {"url": self.options['web_root'] + '/apibuilder/'}),

            # webui login/logout handlers
            (r'{0}/login(/?)'.format(self.options['web_root']), LoginHandler),
            (r'{0}/logout(/?)'.format(self.options['web_root']), LogoutHandler),

            # Web calendar handler (Needed because option Unprotected calendar)
            (r'{0}/calendar'.format(self.options['web_root']), CalendarHandler),

            # webui handlers
        ] + route.get_routes(self.options['web_root']))

        # Static File Handlers
        self.app.add_handlers(".*$", [
            # favicon
            (r'{0}/(favicon\.ico)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, self.options['data_root'], 'images/ico/favicon.ico')}),

            # images
            (r'{0}/images/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, self.options['data_root'], 'images')}),

            # cached images
            (r'{0}/cache/images/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, sickbeard.CACHE_DIR, 'images')}),

            # css
            (r'{0}/css/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, self.options['data_root'], 'css')}),

            # javascript
            (r'{0}/js/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, self.options['data_root'], 'js')}),

            # fonts
            (r'{0}/fonts/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": ek(os.path.join, self.options['data_root'], 'fonts')}),

            # videos
            (r'{0}/videos/(.*)'.format(self.options['web_root']), StaticFileHandler,
             {"path": self.video_root})
        ])
Example #22
0
    def __init__(self, options=None, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options or {}
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        self.server = None

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options['web_root']:
            sickbeard.WEB_ROOT = self.options['web_root'] = (
                '/' + self.options['web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options['api_root'] = r'{0}/api/{1}'.format(
            sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert
                    and ek(os.path.exists, self.https_cert)) or not (
                        self.https_key and ek(os.path.exists, self.https_key)):
                if not create_https_certificates(self.https_cert,
                                                 self.https_key):
                    logger.log(
                        "Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (ek(os.path.exists, self.https_cert)
                    and ek(os.path.exists, self.https_key)):
                logger.log(
                    "Disabled HTTPS because of missing CERT and KEY files",
                    logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application(
            [],
            debug=True,
            autoreload=False,
            gzip=sickbeard.WEB_USE_GZIP,
            cookie_secret=sickbeard.WEB_COOKIE_SECRET,
            login_url='{0}/login/'.format(self.options['web_root']),
        )

        # Main Handlers
        self.app.add_handlers(
            '.*$',
            [
                # webapi handler
                (r'{0}(/?.*)'.format(self.options['api_root']), ApiHandler),

                # webapi key retrieval
                (r'{0}/getkey(/?.*)'.format(
                    self.options['web_root']), KeyHandler),

                # webapi builder redirect
                (r'{0}/api/builder'.format(
                    self.options['web_root']), RedirectHandler, {
                        "url": self.options['web_root'] + '/apibuilder/'
                    }),

                # webui login/logout handlers
                (r'{0}/login(/?)'.format(
                    self.options['web_root']), LoginHandler),
                (r'{0}/logout(/?)'.format(
                    self.options['web_root']), LogoutHandler),

                # Web calendar handler (Needed because option Unprotected calendar)
                (r'{0}/calendar'.format(
                    self.options['web_root']), CalendarHandler),

                # webui handlers
            ] + route.get_routes(self.options['web_root']))

        # Static File Handlers
        self.app.add_handlers(
            ".*$",
            [
                # favicon
                (r'{0}/(favicon\.ico)'.format(
                    self.options['web_root']), StaticFileHandler, {
                        "path":
                        ek(os.path.join, self.options['data_root'],
                           'images/ico/favicon.ico')
                    }),

                # images
                (r'{0}/images/(.*)'.format(
                    self.options['web_root']), StaticFileHandler, {
                        "path": ek(os.path.join, self.options['data_root'],
                                   'images')
                    }),

                # locale
                (r'{0}/locale/messages\.json'.format(
                    self.options['web_root']), LocaleFileHandler, {
                        "path":
                        ek(os.path.join, sickbeard.LOCALE_DIR,
                           '{lang_code}/LC_MESSAGES')
                    }),

                # cached images
                (r'{0}/cache/images/(.*)'.format(
                    self.options['web_root']), StaticFileHandler, {
                        "path": ek(os.path.join, sickbeard.CACHE_DIR, 'images')
                    }),

                # css
                (r'{0}/css/(.*)'.format(self.options['web_root']),
                 StaticFileHandler, {
                     "path": ek(os.path.join, self.options['data_root'], 'css')
                 }),

                # javascript
                (r'{0}/js/(.*)'.format(self.options['web_root']),
                 StaticFileHandler, {
                     "path": ek(os.path.join, self.options['data_root'], 'js')
                 }),

                # fonts
                (r'{0}/fonts/(.*)'.format(
                    self.options['web_root']), StaticFileHandler, {
                        "path": ek(os.path.join, self.options['data_root'],
                                   'fonts')
                    }),

                # videos
                (r'{0}/videos/(.*)'.format(
                    self.options['web_root']), StaticFileHandler, {
                        "path": self.video_root
                    })
            ])
Example #23
0
    def __init__(self, options=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = 'TORNADO'
        self.io_loop = None
        self.server = None

        self.options = options or {}
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', None)
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # web root
        self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options['web_root'] else ''

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            make_cert = False
            update_cfg = False
            for (attr, ext) in [('https_cert', '.crt'), ('https_key', '.key')]:
                ssl_path = getattr(self, attr, None)
                if ssl_path and not os.path.isfile(ssl_path):
                    if not ssl_path.endswith(ext):
                        setattr(self, attr, os.path.join(ssl_path, 'server%s' % ext))
                        setattr(sickbeard, attr.upper(), 'server%s' % ext)
                    make_cert = True

            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if make_cert:
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u'Unable to create CERT/KEY files, disabling HTTPS')
                    update_cfg |= False is not sickbeard.ENABLE_HTTPS
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False
                else:
                    update_cfg = True

            if not (os.path.isfile(self.https_cert) and os.path.isfile(self.https_key)):
                logger.log(u'Disabled HTTPS because of missing CERT and KEY files', logger.WARNING)
                update_cfg |= False is not sickbeard.ENABLE_HTTPS
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

            if update_cfg:
                sickbeard.save_config()

        # Load the app
        self.app = MyApplication([],
                                 debug=True,
                                 serve_traceback=True,
                                 autoreload=False,
                                 compress_response=True,
                                 cookie_secret=sickbeard.COOKIE_SECRET,
                                 xsrf_cookies=True,
                                 login_url='%s/login/' % self.options['web_root'])

        self.re_host_pattern = re_valid_hostname()
        self._add_loading_rules()
Example #24
0
    def __init__(self, options={}, io_loop=None):
        threading.Thread.__init__(self)
        self.daemon = True
        self.alive = True
        self.name = "TORNADO"
        self.io_loop = io_loop or IOLoop.current()

        self.options = options
        self.options.setdefault('port', 8081)
        self.options.setdefault('host', '0.0.0.0')
        self.options.setdefault('log_dir', None)
        self.options.setdefault('username', '')
        self.options.setdefault('password', '')
        self.options.setdefault('web_root', '/')
        assert isinstance(self.options['port'], int)
        assert 'data_root' in self.options

        # video root
        if sickbeard.ROOT_DIRS:
            root_dirs = sickbeard.ROOT_DIRS.split('|')
            self.video_root = root_dirs[int(root_dirs[0]) + 1]
        else:
            self.video_root = None

        # web root
        if self.options['web_root']:
            sickbeard.WEB_ROOT = self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/').strip('/'))

        # api root
        if not sickbeard.API_KEY:
            sickbeard.API_KEY = generateApiKey()
        self.options['api_root'] = r'%s/api/%s' % (sickbeard.WEB_ROOT, sickbeard.API_KEY)

        # tornado setup
        self.enable_https = self.options['enable_https']
        self.https_cert = self.options['https_cert']
        self.https_key = self.options['https_key']

        if self.enable_https:
            # If either the HTTPS certificate or key do not exist, make some self-signed ones.
            if not (self.https_cert and os.path.exists(self.https_cert)) or not (
                        self.https_key and os.path.exists(self.https_key)):
                if not create_https_certificates(self.https_cert, self.https_key):
                    logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                    sickbeard.ENABLE_HTTPS = False
                    self.enable_https = False

            if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
                logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
                sickbeard.ENABLE_HTTPS = False
                self.enable_https = False

        # Load the app
        self.app = Application([],
                                 debug=True,
                                 autoreload=False,
                                 gzip=True,
                                 xheaders=sickbeard.HANDLE_REVERSE_PROXY,
                                 cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
                                 login_url='%s/login/' % self.options['web_root'],
        )

        # Main Handlers
        self.app.add_handlers('.*$', [
            # webapi handler
            (r'%s(/?.*)' % self.options['api_root'], ApiHandler),

            # webapi key retrieval
            (r'%s/getkey(/?.*)' % self.options['web_root'], KeyHandler),

            # webapi builder redirect
            (r'%s/api/builder' % self.options['web_root'], RedirectHandler, {"url": self.options['web_root'] + '/apibuilder/'}),

            # webui login/logout handlers
            (r'%s/login(/?)' % self.options['web_root'], LoginHandler),
            (r'%s/logout(/?)' % self.options['web_root'], LogoutHandler),

            # webui handlers
        ] + route.get_routes(self.options['web_root']))

        # Static File Handlers
        self.app.add_handlers(".*$", [
            # favicon
            (r'%s/(favicon\.ico)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),

            # images
            (r'%s/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'images')}),

            # cached images
            (r'%s/cache/images/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(sickbeard.CACHE_DIR, 'images')}),

            # css
            (r'%s/css/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'css')}),

            # javascript
            (r'%s/js/(.*)' % self.options['web_root'], StaticFileHandler,
             {"path": os.path.join(self.options['data_root'], 'js')}),

            # videos
        ] + [(r'%s/videos/(.*)' % self.options['web_root'], StaticFileHandler,
              {"path": self.video_root})])
Example #25
0
def initWebServer(options={}):
    options.setdefault('port', 8081)
    options.setdefault('host', '0.0.0.0')
    options.setdefault('log_dir', None)
    options.setdefault('username', '')
    options.setdefault('password', '')
    options.setdefault('web_root', '/')
    assert isinstance(options['port'], int)
    assert 'data_root' in options

    def http_error_401_hander(status, message, traceback, version):
        """ Custom handler for 401 error """
        if status != "401 Unauthorized":
            logger.log(u"CherryPy caught an error: %s %s" % (status, message), logger.ERROR)
            logger.log(traceback, logger.DEBUG)
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>%s</title>
    </head>
    <body>
        <br/>
        <font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
    </body>
</html>
''' % ('Access denied', status)

    def http_error_404_hander(status, message, traceback, version):
        """ Custom handler for 404 error, redirect back to main page """
        return r'''<!DOCTYPE html>
<html>
    <head>
        <title>404</title>
        <script>
          <!--
          location.href = "%s/home/"
          //-->
        </script>
    </head>
    <body>
        <br/>
    </body>
</html>
''' % options['web_root']

    # cherrypy setup
    enable_https = options['enable_https']
    https_cert = options['https_cert']
    https_key = options['https_key']

    if enable_https:
        # If either the HTTPS certificate or key do not exist, make some self-signed ones.
        if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
            if not create_https_certificates(https_cert, https_key):
                logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
                sickbeard.ENABLE_HTTPS = False
                enable_https = False

        if not (os.path.exists(https_cert) and os.path.exists(https_key)):
            logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
            sickbeard.ENABLE_HTTPS = False
            enable_https = False

    mime_gzip = ('text/html',
                 'text/plain',
                 'text/css',
                 'text/javascript',
                 'application/javascript',
                 'text/x-javascript',
                 'application/x-javascript',
                 'text/x-json',
                 'application/json'
                 )

    options_dict = {
        'server.socket_port': options['port'],
        'server.socket_host': options['host'],
        'log.screen': False,
        'engine.autoreload.on': False,
        'engine.autoreload.frequency': 100,
        'engine.reexec_retry': 100,
        'tools.gzip.on': True,
        'tools.gzip.mime_types': mime_gzip,
        'error_page.401': http_error_401_hander,
        'error_page.404': http_error_404_hander,
        'tools.autoproxy.on': True,
    }

    if enable_https:
        options_dict['server.ssl_certificate'] = https_cert
        options_dict['server.ssl_private_key'] = https_key
        protocol = "https"
    else:
        protocol = "http"

    logger.log(u"Starting Sick Beard on " + protocol + "://" + str(options['host']) + ":" + str(options['port']) + "/")
    cherrypy.config.update(options_dict)

    # setup cherrypy logging
    if options['log_dir'] and os.path.isdir(options['log_dir']):
        cherrypy.config.update({ 'log.access_file': os.path.join(options['log_dir'], "cherrypy.log") })
        logger.log(u'Using %s for cherrypy log' % cherrypy.config['log.access_file'])

    conf = {
        '/': {
            'tools.staticdir.root': options['data_root'],
            'tools.encode.on': True,
            'tools.encode.encoding': 'utf-8',
        },
        '/images': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'images'
        },
        '/js': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'js'
        },
        '/css': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': 'css'
        },
    }
    app = cherrypy.tree.mount(WebInterface(), options['web_root'], conf)

    # auth
    if options['username'] != "" and options['password'] != "":
        checkpassword = cherrypy.lib.auth_basic.checkpassword_dict({options['username']: options['password']})
        app.merge({
            '/': {
                'tools.auth_basic.on': True,
                'tools.auth_basic.realm': 'SickBeard',
                'tools.auth_basic.checkpassword': checkpassword
            },
            '/api': {
                'tools.auth_basic.on': False
            },
            '/api/builder': {
                'tools.auth_basic.on': True,
                'tools.auth_basic.realm': 'SickBeard',
                'tools.auth_basic.checkpassword': checkpassword
            }
        })

    # Ensure that when behind a mod_rewrite Apache reverse proxy,
    # both direct requests and proxied requests are handled properly.
    def autoproxy(
        base   = None,
        local  = 'X-Forwarded-Host',
        remote = 'X-Forwarded-For',
        scheme = 'X-Forwarded-Proto',
        debug  = False,
    ):
        """
        Apply the CherryPy proxy tool only if the ``local`` header is set.

        Notice that it maps the parameters to the original proxy tool.

        Use it as per the usual proxy tool:
            tools.autoproxy.on: True
            tools.autoproxy.base: "http://www.mydomain.com"
        """
        # or to look for all of them
        # h = cherrypy.serving.request.headers
        # if local in h and remote in h and scheme in h:
        if local in cherrypy.serving.request.headers:
          cherrypy.lib.cptools.proxy(base, local, remote, scheme, debug)

    cherrypy.tools.autoproxy = cherrypy.Tool(
        'before_request_body',
        autoproxy,
        priority = 30,
    )

    cherrypy.server.start()
    cherrypy.server.wait()