diff --git a/docs/docs/configuration/server.rst b/docs/docs/configuration/server.rst index 51f5faf..977dd1f 100644 --- a/docs/docs/configuration/server.rst +++ b/docs/docs/configuration/server.rst @@ -41,7 +41,7 @@ session key and hostname. Here are the default values for this section: [general] dbpath = /tmp/isso.db name = - host = http://localhost:8080/ + host = max-age = 15m notify = @@ -54,21 +54,22 @@ name not used otherwise. host - URL to your website. When you start Isso, it will probe your website with - a simple ``GET /`` request to see if it can reach the webserver. If this - fails, Isso may not be able check if a web page exists, thus fails to - accept new comments. + Your website(s). If Isso is unable to connect to at least on site, you'll + get a warning during startup and comments are most likely non-functional. - You can supply more than one host: + You'll need at least one host/website to run Isso. This is due to security + reasons: Isso uses CORS_ to embed comments and to restrict comments only to + your website, you have to "whitelist" your website(s). + + I recommend the first value to be a non-SSL website that is used as fallback + if Firefox users (and only those) supress their HTTP referer completely. .. code-block:: ini [general] host = - http://localhost/ - https://localhost/ - - This is useful, when your website is available on HTTP and HTTPS. + http://example.tld/ + https://example.tld/ max-age time range that allows users to edit/remove their own comments. See @@ -79,6 +80,9 @@ notify is available. +.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS + + Moderation ---------- diff --git a/isso/tests/test_cors.py b/isso/tests/test_cors.py index c8f7258..4cfc20d 100644 --- a/isso/tests/test_cors.py +++ b/isso/tests/test_cors.py @@ -25,13 +25,12 @@ class CORSTest(unittest.TestCase): origin=origin([ "https://example.tld/", "http://example.tld/", - "http://example.tld", ]), allowed=("Foo", "Bar"), exposed=("Spam", )) client = Client(app, Response) - rv = client.get("/", headers={"ORIGIN": "https://example.tld"}) + rv = client.get("/", headers={"Origin": "https://example.tld"}) self.assertEqual(rv.headers["Access-Control-Allow-Origin"], "https://example.tld") self.assertEqual(rv.headers["Access-Control-Allow-Credentials"], "true") @@ -39,13 +38,13 @@ class CORSTest(unittest.TestCase): self.assertEqual(rv.headers["Access-Control-Allow-Headers"], "Foo, Bar") self.assertEqual(rv.headers["Access-Control-Expose-Headers"], "Spam") - a = client.get("/", headers={"ORIGIN": "http://example.tld"}) + a = client.get("/", headers={"Origin": "http://example.tld"}) self.assertEqual(a.headers["Access-Control-Allow-Origin"], "http://example.tld") - b = client.get("/", headers={"ORIGIN": "http://example.tld"}) + b = client.get("/", headers={"Origin": "http://example.tld"}) self.assertEqual(b.headers["Access-Control-Allow-Origin"], "http://example.tld") - c = client.get("/", headers={"ORIGIN": "http://foo.other"}) + c = client.get("/", headers={"Origin": "http://foo.other"}) self.assertEqual(c.headers["Access-Control-Allow-Origin"], "https://example.tld") @@ -55,7 +54,7 @@ class CORSTest(unittest.TestCase): allowed=("Foo", ), exposed=("Bar", )) client = Client(app, Response) - rv = client.open(method="OPTIONS", path="/", headers={"ORIGIN": "http://example.tld"}) + rv = client.open(method="OPTIONS", path="/", headers={"Origin": "http://example.tld"}) self.assertEqual(rv.status_code, 200) for hdr in ("Origin", "Headers", "Credentials", "Methods"): diff --git a/isso/tests/test_wsgi.py b/isso/tests/test_wsgi.py index 516858e..17e0b12 100644 --- a/isso/tests/test_wsgi.py +++ b/isso/tests/test_wsgi.py @@ -46,3 +46,4 @@ class TestWSGIUtilities(unittest.TestCase): "http://foo.bar") self.assertEqual(origin({"HTTP_ORIGIN": "http://spam.baz"}), "http://foo.bar") + self.assertEqual(origin({}), "http://foo.bar") diff --git a/isso/wsgi.py b/isso/wsgi.py index 984ada4..35e06e0 100644 --- a/isso/wsgi.py +++ b/isso/wsgi.py @@ -81,10 +81,13 @@ def origin(hosts): def func(environ): + if not hosts: + return "http://invalid.local" + loc = environ.get("HTTP_ORIGIN", environ.get("HTTP_REFERER", None)) - if not hosts or not loc: - return "http://invalid.local" + if loc is None: + return urljoin(*hosts[0]) for split in hosts: if urlsplit(loc) == split: diff --git a/share/isso.conf b/share/isso.conf index 425c88c..2955f74 100644 --- a/share/isso.conf +++ b/share/isso.conf @@ -10,14 +10,18 @@ dbpath = /tmp/comments.db # required to dispatch multiple websites, not used otherwise. name = -# URL to your website. When you start Isso, it will probe your website with a -# simple GET / request to see if it can reach the webserver. If this fails, Isso -# may not be able check if a web page exists, thus fails to accept new comments. -# You can supply more than one host: -# host = -# http://localhost/ -# https://localhost/ -host = http://localhost/ +# Your website(s). If Isso is unable to connect to at least on site, you'll +# get a warning during startup and comments are most likely non-functional. +# +# You'll need at least one host/website to run Isso. This is due to security +# reasons: Isso uses CORS_ to embed comments and to restrict comments only to +# your website, you have to "whitelist" your website(s). +# +# I recommend the first value to be a non-SSL website that is used as fallback +# if Firefox users (and only those) supress their HTTP referer completely. +host = + http://example.tld/ + https://example.tld/ # time range that allows users to edit/remove their own comments. # It supports years, weeks, days, hours, minutes, seconds.