diff --git a/README.rst b/README.rst index d66d15b..46a9e33 100644 --- a/README.rst +++ b/README.rst @@ -47,6 +47,9 @@ If you'd like to include subdomains in your HSTS policy, set the ``subdomains`` sslify = SSLify(app, subdomains=True) +Or by including ``SSLIFY_SUBDOMAINS`` in your app's config. + + HTTP 301 Redirects ------------------ @@ -55,6 +58,17 @@ by passing the ``permanent`` parameter:: sslify = SSLify(app, permanent=True) +Or by including ``SSLIFY_PERMANENT`` in your app's config. + + +Exclude Certain Paths from Being Redirected +------------------------------------------- +You can exlude a path that starts with given string by including a list called ``skips``:: + + sslify = SSLify(app, skips=['mypath', 'anotherpath']) + +Or by including ``SSLIFY_SKIPS`` in your app's config. + Install ------- diff --git a/flask_sslify.py b/flask_sslify.py index 2929f9f..979dc72 100644 --- a/flask_sslify.py +++ b/flask_sslify.py @@ -8,17 +8,23 @@ YEAR_IN_SECS = 31536000 class SSLify(object): """Secures your Flask App.""" - def __init__(self, app=None, age=YEAR_IN_SECS, subdomains=False, permanent=False): + def __init__(self, app=None, age=YEAR_IN_SECS, subdomains=False, permanent=False, skips=None): + self.app = app or current_app self.hsts_age = age - self.hsts_include_subdomains = subdomains - self.permanent = permanent + + self.app.config.setdefault('SSLIFY_SUBDOMAINS', False) + self.app.config.setdefault('SSLIFY_PERMANENT', False) + self.app.config.setdefault('SSLIFY_SKIPS', None) + + self.hsts_include_subdomains = subdomains or self.app.config['SSLIFY_SUBDOMAINS'] + self.permanent = permanent or self.app.config['SSLIFY_PERMANENT'] + self.skip_list = skips or self.app.config['SSLIFY_SKIPS'] if app is not None: self.init_app(app) def init_app(self, app): """Configures the configured Flask app to enforce SSL.""" - app.before_request(self.redirect_to_ssl) app.after_request(self.set_hsts_header) @@ -32,6 +38,16 @@ class SSLify(object): return hsts_policy + @property + def skip(self): + """Checks the skip list.""" + # Should we skip? + if self.skip_list and isinstance(self.skip_list, list): + for skip in self.skip_list: + if request.path.startswith('/{0}'.format(skip)): + return True + return False + def redirect_to_ssl(self): """Redirect incoming requests to HTTPS.""" # Should we redirect? @@ -41,18 +57,18 @@ class SSLify(object): request.headers.get('X-Forwarded-Proto', 'http') == 'https' ] - if not any(criteria): + if not any(criteria) and not self.skip: if request.url.startswith('http://'): url = request.url.replace('http://', 'https://', 1) code = 302 if self.permanent: code = 301 r = redirect(url, code=code) - return r def set_hsts_header(self, response): """Adds HSTS header to each response.""" - if request.is_secure: + # Should we add STS header? + if request.is_secure and not self.skip: response.headers.setdefault('Strict-Transport-Security', self.hsts_header) return response