diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py index 7ad6e3b0f6..82c468cf64 100644 --- a/liberapay/utils/__init__.py +++ b/liberapay/utils/__init__.py @@ -200,22 +200,28 @@ def is_card_expired(exp_year, exp_month): return exp_year < cur_year or exp_year == cur_year and exp_month < cur_month +def ensure_str(s): + if isinstance(s, str): + return s + return s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii') + + def set_cookie(cookies, key, value, expires=None, httponly=True, path='/'): - key = str(key) - cookies[key] = str(value) + key = ensure_str(key) + cookies[key] = ensure_str(value) cookie = cookies[key] if expires: if isinstance(expires, timedelta): expires += utcnow() if isinstance(expires, datetime): expires = to_rfc822(expires) - cookie[str('expires')] = str(expires) + cookie[str('expires')] = ensure_str(expires) if httponly: cookie[str('httponly')] = True if path: - cookie[str('path')] = str(path) + cookie[str('path')] = ensure_str(path) if website.canonical_domain: - cookie[str('domain')] = str(website.canonical_domain) + cookie[str('domain')] = ensure_str(website.canonical_domain) if website.canonical_scheme == 'https': cookie[str('secure')] = True diff --git a/tests/py/test_hooks.py b/tests/py/test_hooks.py index 180a527533..362e179887 100644 --- a/tests/py/test_hooks.py +++ b/tests/py/test_hooks.py @@ -20,12 +20,15 @@ def setUp(self): Harness.setUp(self) self.client.website.canonical_scheme = 'https' self.client.website.canonical_host = 'example.com' + self._canonical_domain = self.client.website.canonical_domain + self.client.website.canonical_domain = b'.example.com' def tearDown(self): Harness.tearDown(self) website = self.client.website website.canonical_scheme = website.env.canonical_scheme website.canonical_host = website.env.canonical_host + website.canonical_domain = self._canonical_domain def test_canonize_canonizes(self): response = self.client.GxT("/", @@ -105,6 +108,19 @@ def test_i18n_subdomain_is_redirected_to_https(self): assert not r.headers.cookie assert r.headers[b'Location'] == b'https://en.example.com/' + def test_csrf_cookie_properties(self): + r = self.client.GET( + '/', + HTTP_X_FORWARDED_PROTO=b'https', HTTP_HOST=b'en.example.com', + csrf_token=None, raise_immediately=False, + ) + assert r.code == 200 + cookie = r.headers.cookie[csrf.CSRF_TOKEN] + assert cookie[str('domain')] == str('.example.com') + assert cookie[str('expires')][-4:] == str(' GMT') + assert cookie[str('path')] == str('/') + assert cookie[str('secure')] is True + class Tests2(Harness):