[Python-modules-commits] [python-django] 01/01: Unapply patches and disable git-dpm

Raphaël Hertzog hertzog at moszumanska.debian.org
Sat May 20 14:02:52 UTC 2017


This is an automated email from the git hooks/post-receive script.

hertzog pushed a commit to branch debian/jessie
in repository python-django.

commit 3e5ffc824466e56ff04c17ce97f0c26f6c1029aa
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Sat May 20 15:55:45 2017 +0200

    Unapply patches and disable git-dpm
---
 debian/.git-dpm                           |  11 ---
 debian/gbp.conf                           |   2 +-
 django/contrib/auth/hashers.py            |  77 ++++++--------------
 django/contrib/auth/tests/test_hashers.py |  60 ----------------
 django/contrib/gis/geoip/base.py          |  19 +++--
 django/http/cookie.py                     |  29 ++++----
 django/utils/http.py                      |  13 +---
 django/views/debug.py                     |   4 +-
 docs/conf.py                              |   5 +-
 docs/man/django-admin.1                   |   6 +-
 docs/topics/auth/passwords.txt            | 113 ------------------------------
 tests/admin_views/admin.py                |   3 +-
 tests/admin_views/models.py               |   4 --
 tests/httpwrappers/tests.py               |  50 +------------
 tests/requests/tests.py                   |   5 +-
 tests/utils_tests/test_http.py            |  25 -------
 16 files changed, 57 insertions(+), 369 deletions(-)

diff --git a/debian/.git-dpm b/debian/.git-dpm
deleted file mode 100644
index 7b6f2ec..0000000
--- a/debian/.git-dpm
+++ /dev/null
@@ -1,11 +0,0 @@
-# see git-dpm(1) from git-dpm package
-NONE
-b66a3bcd305248e7e246884fd7906a75d69ffc94
-2d07f4b16101fcc8973128c4e4920b41f87175ee
-2d07f4b16101fcc8973128c4e4920b41f87175ee
-python-django_1.7.11.orig.tar.gz
-f9abaf7eacec73bc1c5e6080e2778a7174ebf9d4
-7586798
-debianTag="debian/%e%v"
-patchedTag="patched/%e%v"
-upstreamTag="upstream/%e%u"
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 9e794e3..c08fd3f 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,3 +1,3 @@
 [DEFAULT]
 upstream-branch=upstream/1.7.x
-debian-branch=debian/sid
+debian-branch=debian/jessie
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index 1ad4bcb..e459f39 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -5,7 +5,6 @@ import binascii
 from collections import OrderedDict
 import hashlib
 import importlib
-import warnings
 
 from django.dispatch import receiver
 from django.conf import settings
@@ -56,17 +55,10 @@ def check_password(password, encoded, setter=None, preferred='default'):
     preferred = get_hasher(preferred)
     hasher = identify_hasher(encoded)
 
-    hasher_changed = hasher.algorithm != preferred.algorithm
-    must_update = hasher_changed or preferred.must_update(encoded)
+    must_update = hasher.algorithm != preferred.algorithm
+    if not must_update:
+        must_update = preferred.must_update(encoded)
     is_correct = hasher.verify(password, encoded)
-
-    # If the hasher didn't change (we don't protect against enumeration if it
-    # does) and the password should get updated, try to close the timing gap
-    # between the work factor of the current encoded password and the default
-    # work factor.
-    if not is_correct and not hasher_changed and must_update:
-        hasher.harden_runtime(password, encoded)
-
     if setter and is_correct and must_update:
         setter(password)
     return is_correct
@@ -225,19 +217,6 @@ class BasePasswordHasher(object):
     def must_update(self, encoded):
         return False
 
-    def harden_runtime(self, password, encoded):
-        """
-        Bridge the runtime gap between the work factor supplied in `encoded`
-        and the work factor suggested by this hasher.
-
-        Taking PBKDF2 as an example, if `encoded` contains 20000 iterations and
-        `self.iterations` is 30000, this method should run password through
-        another 10000 iterations of PBKDF2. Similar approaches should exist
-        for any hasher that has a work factor. If not, this method should be
-        defined as a no-op to silence the warning.
-        """
-        warnings.warn('subclasses of BasePasswordHasher should provide a harden_runtime() method')
-
 
 class PBKDF2PasswordHasher(BasePasswordHasher):
     """
@@ -280,12 +259,6 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
         algorithm, iterations, salt, hash = encoded.split('$', 3)
         return int(iterations) != self.iterations
 
-    def harden_runtime(self, password, encoded):
-        algorithm, iterations, salt, hash = encoded.split('$', 3)
-        extra_iterations = self.iterations - int(iterations)
-        if extra_iterations > 0:
-            self.encode(password, salt, extra_iterations)
-
 
 class PBKDF2SHA1PasswordHasher(PBKDF2PasswordHasher):
     """
@@ -336,8 +309,23 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
     def verify(self, password, encoded):
         algorithm, data = encoded.split('$', 1)
         assert algorithm == self.algorithm
-        encoded_2 = self.encode(password, force_bytes(data))
-        return constant_time_compare(encoded, encoded_2)
+        bcrypt = self._load_library()
+
+        # Hash the password prior to using bcrypt to prevent password truncation
+        #   See: https://code.djangoproject.com/ticket/20138
+        if self.digest is not None:
+            # We use binascii.hexlify here because Python3 decided that a hex encoded
+            #   bytestring is somehow a unicode.
+            password = binascii.hexlify(self.digest(force_bytes(password)).digest())
+        else:
+            password = force_bytes(password)
+
+        # Ensure that our data is a bytestring
+        data = force_bytes(data)
+        # force_bytes() necessary for py-bcrypt compatibility
+        hashpw = force_bytes(bcrypt.hashpw(password, data))
+
+        return constant_time_compare(data, hashpw)
 
     def safe_summary(self, encoded):
         algorithm, empty, algostr, work_factor, data = encoded.split('$', 4)
@@ -350,16 +338,6 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
             (_('checksum'), mask_hash(checksum)),
         ])
 
-    def harden_runtime(self, password, encoded):
-        _, data = encoded.split('$', 1)
-        salt = data[:29]  # Length of the salt in bcrypt.
-        rounds = data.split('$')[2]
-        # work factor is logarithmic, adding one doubles the load.
-        diff = 2**(self.rounds - int(rounds)) - 1
-        while diff > 0:
-            self.encode(password, force_bytes(salt))
-            diff -= 1
-
 
 class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
     """
@@ -407,9 +385,6 @@ class SHA1PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
-    def harden_runtime(self, password, encoded):
-        pass
-
 
 class MD5PasswordHasher(BasePasswordHasher):
     """
@@ -438,9 +413,6 @@ class MD5PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
-    def harden_runtime(self, password, encoded):
-        pass
-
 
 class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
     """
@@ -473,9 +445,6 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
-    def harden_runtime(self, password, encoded):
-        pass
-
 
 class UnsaltedMD5PasswordHasher(BasePasswordHasher):
     """
@@ -509,9 +478,6 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(encoded, show=3)),
         ])
 
-    def harden_runtime(self, password, encoded):
-        pass
-
 
 class CryptPasswordHasher(BasePasswordHasher):
     """
@@ -546,6 +512,3 @@ class CryptPasswordHasher(BasePasswordHasher):
             (_('salt'), salt),
             (_('hash'), mask_hash(data, show=3)),
         ])
-
-    def harden_runtime(self, password, encoded):
-        pass
diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py
index 3a06b43..85f1c15 100644
--- a/django/contrib/auth/tests/test_hashers.py
+++ b/django/contrib/auth/tests/test_hashers.py
@@ -9,12 +9,7 @@ from django.contrib.auth.hashers import (is_password_usable, BasePasswordHasher,
     get_hasher, identify_hasher, UNUSABLE_PASSWORD_PREFIX, UNUSABLE_PASSWORD_SUFFIX_LENGTH)
 from django.test import SimpleTestCase
 from django.utils import six
-from django.utils.encoding import force_bytes
 
-try:
-    from unittest import mock
-except ImportError:
-    import mock
 
 try:
     import crypt
@@ -181,28 +176,6 @@ class TestUtilsHashPass(SimpleTestCase):
         self.assertTrue(check_password('', blank_encoded))
         self.assertFalse(check_password(' ', blank_encoded))
 
-    @skipUnless(bcrypt, "bcrypt not installed")
-    def test_bcrypt_harden_runtime(self):
-        hasher = get_hasher('bcrypt')
-        self.assertEqual('bcrypt', hasher.algorithm)
-
-        with mock.patch.object(hasher, 'rounds', 4):
-            encoded = make_password('letmein', hasher='bcrypt')
-
-        with mock.patch.object(hasher, 'rounds', 6), \
-                mock.patch.object(hasher, 'encode', side_effect=hasher.encode):
-            hasher.harden_runtime('wrong_password', encoded)
-
-            # Increasing rounds from 4 to 6 means an increase of 4 in workload,
-            # therefore hardening should run 3 times to make the timing the
-            # same (the original encode() call already ran once).
-            self.assertEqual(hasher.encode.call_count, 3)
-
-            # Get the original salt (includes the original workload factor)
-            algorithm, data = encoded.split('$', 1)
-            expected_call = (('wrong_password', force_bytes(data[:29])),)
-            self.assertEqual(hasher.encode.call_args_list, [expected_call] * 3)
-
     def test_unusable(self):
         encoded = make_password(None)
         self.assertEqual(len(encoded), len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH)
@@ -310,25 +283,6 @@ class TestUtilsHashPass(SimpleTestCase):
         finally:
             hasher.iterations = old_iterations
 
-    def test_pbkdf2_harden_runtime(self):
-        hasher = get_hasher('default')
-        self.assertEqual('pbkdf2_sha256', hasher.algorithm)
-
-        with mock.patch.object(hasher, 'iterations', 1):
-            encoded = make_password('letmein')
-
-        with mock.patch.object(hasher, 'iterations', 6), \
-                mock.patch.object(hasher, 'encode', side_effect=hasher.encode):
-            hasher.harden_runtime('wrong_password', encoded)
-
-            # Encode should get called once ...
-            self.assertEqual(hasher.encode.call_count, 1)
-
-            # ... with the original salt and 5 iterations.
-            algorithm, iterations, salt, hash = encoded.split('$', 3)
-            expected_call = (('wrong_password', salt, 5),)
-            self.assertEqual(hasher.encode.call_args, expected_call)
-
     def test_pbkdf2_upgrade_new_hasher(self):
         self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm)
         hasher = get_hasher('default')
@@ -357,20 +311,6 @@ class TestUtilsHashPass(SimpleTestCase):
             self.assertTrue(check_password('letmein', encoded, setter))
             self.assertTrue(state['upgraded'])
 
-    def test_check_password_calls_harden_runtime(self):
-        hasher = get_hasher('default')
-        encoded = make_password('letmein')
-
-        with mock.patch.object(hasher, 'harden_runtime'), \
-                mock.patch.object(hasher, 'must_update', return_value=True):
-            # Correct password supplied, no hardening needed
-            check_password('letmein', encoded)
-            self.assertEqual(hasher.harden_runtime.call_count, 0)
-
-            # Wrong password supplied, hardening needed
-            check_password('wrong_password', encoded)
-            self.assertEqual(hasher.harden_runtime.call_count, 1)
-
     def test_load_library_no_algorithm(self):
         with self.assertRaises(ValueError) as e:
             BasePasswordHasher()._load_library()
diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py
index 0b05f43..9295030 100644
--- a/django/contrib/gis/geoip/base.py
+++ b/django/contrib/gis/geoip/base.py
@@ -67,8 +67,7 @@ class GeoIP(object):
         * path: Base directory to where GeoIP data is located or the full path
             to where the city or country data files (*.dat) are located.
             Assumes that both the city and country data sets are located in
-            this directory. Overrides the GEOIP_PATH settings attribute.
-            If neither is set, defaults to '/usr/share/GeoIP'.
+            this directory; overrides the GEOIP_PATH settings attribute.
 
         * cache: The cache settings when opening up the GeoIP datasets,
             and may be an integer in (0, 1, 2, 4, 8) corresponding to
@@ -77,13 +76,11 @@ class GeoIP(object):
             settings,  respectively.  Defaults to 0, meaning that the data is read
             from the disk.
 
-        * country: The name of the GeoIP country data file. Overrides
-            the GEOIP_COUNTRY settings attribute. If neither is set,
-            defaults to 'GeoIP.dat'
+        * country: The name of the GeoIP country data file.  Defaults to
+            'GeoIP.dat'; overrides the GEOIP_COUNTRY settings attribute.
 
-        * city: The name of the GeoIP city data file. Overrides the
-            GEOIP_CITY settings attribute. If neither is set, defaults
-            to 'GeoIPCity.dat'.
+        * city: The name of the GeoIP city data file.  Defaults to
+            'GeoLiteCity.dat'; overrides the GEOIP_CITY settings attribute.
         """
         # Checking the given cache option.
         if cache in self.cache_options:
@@ -93,7 +90,9 @@ class GeoIP(object):
 
         # Getting the GeoIP data path.
         if not path:
-            path = GEOIP_SETTINGS.get('GEOIP_PATH', '/usr/share/GeoIP')
+            path = GEOIP_SETTINGS.get('GEOIP_PATH', None)
+            if not path:
+                raise GeoIPException('GeoIP path must be provided via parameter or the GEOIP_PATH setting.')
         if not isinstance(path, six.string_types):
             raise TypeError('Invalid path type: %s' % type(path).__name__)
 
@@ -106,7 +105,7 @@ class GeoIP(object):
                 self._country = GeoIP_open(force_bytes(country_db), cache)
                 self._country_file = country_db
 
-            city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoIPCity.dat'))
+            city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
             if os.path.isfile(city_db):
                 self._city = GeoIP_open(force_bytes(city_db), cache)
                 self._city_file = city_db
diff --git a/django/http/cookie.py b/django/http/cookie.py
index 07d8cbf..7084c87 100644
--- a/django/http/cookie.py
+++ b/django/http/cookie.py
@@ -71,21 +71,18 @@ else:
 
 
 def parse_cookie(cookie):
-    """
-    Return a dictionary parsed from a `Cookie:` header string.
-    """
+    if cookie == '':
+        return {}
+    if not isinstance(cookie, http_cookies.BaseCookie):
+        try:
+            c = SimpleCookie()
+            c.load(cookie)
+        except http_cookies.CookieError:
+            # Invalid cookie
+            return {}
+    else:
+        c = cookie
     cookiedict = {}
-    if six.PY2:
-        cookie = force_str(cookie)
-    for chunk in cookie.split(str(';')):
-        if str('=') in chunk:
-            key, val = chunk.split(str('='), 1)
-        else:
-            # Assume an empty name per
-            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
-            key, val = str(''), chunk
-        key, val = key.strip(), val.strip()
-        if key or val:
-            # unquote using Python's algorithm.
-            cookiedict[key] = http_cookies._unquote(val)
+    for key in c.keys():
+        cookiedict[key] = c.get(key).value
     return cookiedict
diff --git a/django/utils/http.py b/django/utils/http.py
index 972760e..ef88f65 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -274,17 +274,8 @@ def is_safe_url(url, host=None):
         url = url.strip()
     if not url:
         return False
-    if six.PY2:
-        try:
-            url = force_text(url)
-        except UnicodeDecodeError:
-            return False
-    # Chrome treats \ completely as / in paths but it could be part of some
-    # basic auth credentials so we need to check both URLs.
-    return _is_safe_url(url, host) and _is_safe_url(url.replace('\\', '/'), host)
-
-
-def _is_safe_url(url, host):
+    # Chrome treats \ completely as /
+    url = url.replace('\\', '/')
     # Chrome considers any URL with more than two slashes to be absolute, but
     # urlparse is not so flexible. Treat any url with three slashes as unsafe.
     if url.startswith('///'):
diff --git a/django/views/debug.py b/django/views/debug.py
index 7d8ea05..13992e9 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -637,13 +637,13 @@ TECHNICAL_500_TEMPLATE = """
       var s = link.getElementsByTagName('span')[0];
       var uarr = String.fromCharCode(0x25b6);
       var darr = String.fromCharCode(0x25bc);
-      s.textContent = s.textContent == uarr ? darr : uarr;
+      s.innerHTML = s.innerHTML == uarr ? darr : uarr;
       return false;
     }
     function switchPastebinFriendly(link) {
       s1 = "Switch to copy-and-paste view";
       s2 = "Switch back to interactive view";
-      link.textContent = link.textContent.trim() == s1 ? s2: s1;
+      link.innerHTML = link.innerHTML == s1 ? s2: s1;
       toggle('browserTraceback', 'pastebinTraceback');
       return false;
     }
diff --git a/docs/conf.py b/docs/conf.py
index 90e4d69..6df8dd8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -200,10 +200,7 @@ html_additional_pages = {}
 #html_split_index = False
 
 # If true, links to the reST sources are added to the pages.
-html_show_sourcelink = False
-
-# Do not ship a copy of the sources
-html_copy_source = False
+#html_show_sourcelink = True
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
 #html_show_sphinx = True
diff --git a/docs/man/django-admin.1 b/docs/man/django-admin.1
index bdb6438..c9932ac 100644
--- a/docs/man/django-admin.1
+++ b/docs/man/django-admin.1
@@ -1,8 +1,8 @@
-.TH "django-admin" "1" "March 2008" "Django Project" ""
+.TH "django-admin.py" "1" "March 2008" "Django Project" ""
 .SH "NAME"
-django\-admin \- Utility script for the Django Web framework
+django\-admin.py \- Utility script for the Django Web framework
 .SH "SYNOPSIS"
-.B django\-admin
+.B django\-admin.py
 .I <action>
 .B [options]
 .sp
diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt
index 00964cf..280405f 100644
--- a/docs/topics/auth/passwords.txt
+++ b/docs/topics/auth/passwords.txt
@@ -197,125 +197,12 @@ unmentioned algorithms won't be able to upgrade.
 
     Passwords will be upgraded when changing the PBKDF2 iteration count.
 
-Be aware that if all the passwords in your database aren't encoded in the
-default hasher's algorithm, you may be vulnerable to a user enumeration timing
-attack due to a difference between the duration of a login request for a user
-with a password encoded in a non-default algorithm and the duration of a login
-request for a nonexistent user (which runs the default hasher). You may be able
-to mitigate this by :ref:`upgrading older password hashes
-<wrapping-password-hashers>`.
-
-.. _wrapping-password-hashers:
-
-Password upgrading without requiring a login
---------------------------------------------
-
-If you have an existing database with an older, weak hash such as MD5 or SHA1,
-you might want to upgrade those hashes yourself instead of waiting for the
-upgrade to happen when a user logs in (which may never happen if a user doesn't
-return to your site). In this case, you can use a "wrapped" password hasher.
-
-For this example, we'll migrate a collection of SHA1 hashes to use
-PBKDF2(SHA1(password)) and add the corresponding password hasher for checking
-if a user entered the correct password on login. We assume we're using the
-built-in ``User`` model and that our project has an ``accounts`` app. You can
-modify the pattern to work with any algorithm or with a custom user model.
-
-First, we'll add the custom hasher:
-
-.. snippet::
-    :filename: accounts/hashers.py
-
-    from django.contrib.auth.hashers import (
-        PBKDF2PasswordHasher, SHA1PasswordHasher,
-    )
-
-
-    class PBKDF2WrappedSHA1PasswordHasher(PBKDF2PasswordHasher):
-        algorithm = 'pbkdf2_wrapped_sha1'
-
-        def encode_sha1_hash(self, sha1_hash, salt, iterations=None):
-            return super(PBKDF2WrappedSHA1PasswordHasher, self).encode(sha1_hash, salt, iterations)
-
-        def encode(self, password, salt, iterations=None):
-            _, _, sha1_hash = SHA1PasswordHasher().encode(password, salt).split('$', 2)
-            return self.encode_sha1_hash(sha1_hash, salt, iterations)
-
-The data migration might look something like:
-
-.. snippet::
-    :filename: accounts/migrations/0002_migrate_sha1_passwords.py
-
-    from django.db import migrations
-
-    from ..hashers import PBKDF2WrappedSHA1PasswordHasher
-
-
-    def forwards_func(apps, schema_editor):
-        User = apps.get_model('auth', 'User')
-        users = User.objects.filter(password__startswith='sha1$')
-        hasher = PBKDF2WrappedSHA1PasswordHasher()
-        for user in users:
-            algorithm, salt, sha1_hash = user.password.split('$', 2)
-            user.password = hasher.encode_sha1_hash(sha1_hash, salt)
-            user.save(update_fields=['password'])
-
-
-    class Migration(migrations.Migration):
-
-        dependencies = [
-            ('accounts', '0001_initial'),
-            # replace this with the latest migration in contrib.auth
-            ('auth', '####_migration_name'),
-        ]
-
-        operations = [
-            migrations.RunPython(forwards_func),
-        ]
-
-Be aware that this migration will take on the order of several minutes for
-several thousand users, depending on the speed of your hardware.
-
-Finally, we'll add a :setting:`PASSWORD_HASHERS` setting:
-
-.. snippet::
-    :filename: mysite/settings.py
-
-    PASSWORD_HASHERS = [
-        'django.contrib.auth.hashers.PBKDF2PasswordHasher',
-        'accounts.hashers.PBKDF2WrappedSHA1PasswordHasher',
-    ]
-
-Include any other hashers that your site uses in this list.
-
 .. _sha1: http://en.wikipedia.org/wiki/SHA1
 .. _pbkdf2: http://en.wikipedia.org/wiki/PBKDF2
 .. _nist: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
 .. _bcrypt: http://en.wikipedia.org/wiki/Bcrypt
 .. _`bcrypt library`: https://pypi.python.org/pypi/bcrypt/
 
-.. _write-your-own-password-hasher:
-
-Writing your own hasher
------------------------
-
-.. versionadded:: 1.8.10
-
-If you write your own password hasher that contains a work factor such as a
-number of iterations, you should implement a
-``harden_runtime(self, password, encoded)`` method to bridge the runtime gap
-between the work factor supplied in the ``encoded`` password and the default
-work factor of the hasher. This prevents a user enumeration timing attack due
-to  difference between a login request for a user with a password encoded in an
-older number of iterations and a nonexistent user (which runs the default
-hasher's default number of iterations).
-
-Taking PBKDF2 as example, if ``encoded`` contains 20,000 iterations and the
-hasher's default ``iterations`` is 30,000, the method should run ``password``
-through another 10,000 iterations of PBKDF2.
-
-If your hasher doesn't have a work factor, implement the method as a no-op
-(``pass``).
 
 Manually managing a user's password
 ===================================
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 36187af..15c1384 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -83,8 +83,7 @@ class ChapterXtra1Admin(admin.ModelAdmin):
 
 class ArticleAdmin(admin.ModelAdmin):
     list_display = ('content', 'date', callable_year, 'model_year',
-                    'modeladmin_year', 'model_year_reversed', 'section')
-    list_editable = ('section',)
+                    'modeladmin_year', 'model_year_reversed')
     list_filter = ('date', 'section')
     view_on_site = False
     fieldsets = (
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index 79dd56c..f41b4de 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -15,7 +15,6 @@ from django.db import models
 from django.utils.encoding import python_2_unicode_compatible
 
 
- at python_2_unicode_compatible
 class Section(models.Model):
     """
     A simple section that links to articles, to test linking to related items
@@ -23,9 +22,6 @@ class Section(models.Model):
     """
     name = models.CharField(max_length=100)
 
-    def __str__(self):
-        return self.name
-
     @property
     def name_property(self):
         """
diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py
index 25a9127..7881f2f 100644
--- a/tests/httpwrappers/tests.py
+++ b/tests/httpwrappers/tests.py
@@ -19,7 +19,7 @@ from django.http import (QueryDict, HttpResponse, HttpResponseRedirect,
                          parse_cookie)
 from django.test import TestCase
 from django.utils.deprecation import RemovedInDjango18Warning
-from django.utils.encoding import smart_str, force_text, force_str
+from django.utils.encoding import smart_str, force_text
 from django.utils.functional import lazy
 from django.utils._os import upath
 from django.utils import six
@@ -632,8 +632,6 @@ class CookieTests(unittest.TestCase):
         c2 = SimpleCookie()
         c2.load(c.output())
         self.assertEqual(c['test'].value, c2['test'].value)
-        c3 = parse_cookie(c.output()[12:])
-        self.assertEqual(c['test'].value, c3['test'])
 
     def test_nonstandard_keys(self):
         """
@@ -647,52 +645,6 @@ class CookieTests(unittest.TestCase):
         """
         self.assertTrue('good_cookie' in parse_cookie('a:=b; a:=c; good_cookie=yes').keys())
 
-    def test_python_cookies(self):
-        """
-        Test cases copied from Python's Lib/test/test_http_cookies.py
-        """
-        self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'})
-        # Here parse_cookie() differs from Python's cookie parsing in that it
-        # treats all semicolons as delimiters, even within quotes.
-        self.assertEqual(
-            parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'),
-            {'keebler': '"E=mc2', 'L': '\\"Loves\\"', 'fudge': '\\012', '': '"'}
-        )
-        # Illegal cookies that have an '=' char in an unquoted value.
-        self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'})
-        # Cookies with ':' character in their name.
-        self.assertEqual(parse_cookie('key:term=value:term'), {'key:term': 'value:term'})
-        # Cookies with '[' and ']'.
-        self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'})
-
-    def test_cookie_edgecases(self):
-        # Cookies that RFC6265 allows.
-        self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'})
-        # parse_cookie() has historically kept only the last cookie with the
-        # same name.
-        self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'})
-
-    def test_invalid_cookies(self):
-        """
-        Cookie strings that go against RFC6265 but browsers will send if set
-        via document.cookie.
-        """
-        # Chunks without an equals sign appear as unnamed values per
-        # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
-        self.assertIn('django_language', parse_cookie('abc=def; unnamed; django_language=en').keys())
-        # Even a double quote may be an unamed value.
-        self.assertEqual(parse_cookie('a=b; "; c=d'), {'a': 'b', '': '"', 'c': 'd'})
-        # Spaces in names and values, and an equals sign in values.
-        self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c': 'd e = f', 'gh': 'i'})
-        # More characters the spec forbids.
-        self.assertEqual(parse_cookie('a   b,c<>@:/[]?{}=d  "  =e,f g'), {'a   b,c<>@:/[]?{}': 'd  "  =e,f g'})
-        # Unicode characters. The spec only allows ASCII.
-        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': force_str('André Bessette')})
-        # Browsers don't send extra whitespace or semicolons in Cookie headers,
-        # but parse_cookie() should parse whitespace the same way
-        # document.cookie parses whitespace.
-        self.assertEqual(parse_cookie('  =  b  ;  ;  =  ;   c  =  ;  '), {'': 'b', 'c': ''})
-
     def test_httponly_after_load(self):
         """
         Test that we can use httponly attribute on cookies that we load
diff --git a/tests/requests/tests.py b/tests/requests/tests.py
index 6364ab1..55b37bb 100644
--- a/tests/requests/tests.py
+++ b/tests/requests/tests.py
@@ -11,7 +11,7 @@ from django.db import connection, connections
 from django.core import signals
 from django.core.exceptions import SuspiciousOperation
 from django.core.handlers.wsgi import WSGIRequest, LimitedStream
-from django.http import (HttpRequest, HttpResponse,
+from django.http import (HttpRequest, HttpResponse, parse_cookie,
     build_request_repr, UnreadablePostError, RawPostDataException)
 from django.test import SimpleTestCase, TransactionTestCase, override_settings
 from django.test.client import FakePayload
@@ -128,6 +128,9 @@ class RequestsTests(SimpleTestCase):
         request = WSGIRequest({'PATH_INFO': wsgi_str("/سلام/"), 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
         self.assertEqual(request.path, "/سلام/")
 
+    def test_parse_cookie(self):
+        self.assertEqual(parse_cookie('invalid at key=true'), {})
+
     def test_httprequest_location(self):
         request = HttpRequest()
         self.assertEqual(request.build_absolute_uri(location="https://www.example.com/asdf"),
diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py
index 769f163..3b367a4 100644
--- a/tests/utils_tests/test_http.py
+++ b/tests/utils_tests/test_http.py
@@ -1,5 +1,3 @@
-# -*- encoding: utf-8 -*-
-from __future__ import unicode_literals
 from datetime import datetime
 import sys
 import unittest
@@ -112,11 +110,6 @@ class TestUtilsHttp(unittest.TestCase):
                         'javascript:alert("XSS")',
                         '\njavascript:alert(x)',
                         '\x08//example.com',
-                        r'http://otherserver\@example.com',
-                        r'http:\\testserver\@example.com',
-                        r'http://testserver\me:pass@example.com',
-                        r'http://testserver\@example.com',
-                        r'http:\\testserver\confirm\me at example.com',
                         '\n'):
             self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url)
         for good_url in ('/view/?param=http://example.com',
@@ -126,27 +119,9 @@ class TestUtilsHttp(unittest.TestCase):
                      'https://testserver/',
                      'HTTPS://testserver/',
                      '//testserver/',
-                     'http://testserver/confirm?email=me@example.com',
                      '/url%20with%20spaces/'):
             self.assertTrue(http.is_safe_url(good_url, host='testserver'), "%s should be allowed" % good_url)
 
-        if six.PY2:
-            # Check binary URLs, regression tests for #26308
-            self.assertTrue(
-                http.is_safe_url(b'https://testserver/', host='testserver'),
-                "binary URLs should be allowed on Python 2"
-            )
-            self.assertFalse(http.is_safe_url(b'\x08//example.com', host='testserver'))
-            self.assertTrue(http.is_safe_url('àview/'.encode('utf-8'), host='testserver'))
-            self.assertFalse(http.is_safe_url('àview'.encode('latin-1'), host='testserver'))
-
-        # Valid basic auth credentials are allowed.
-        self.assertTrue(http.is_safe_url(r'http://user:pass@testserver/', host='user:pass at testserver'))
-        # A path without host is allowed.
-        self.assertTrue(http.is_safe_url('/confirm/me at example.com'))
-        # Basic auth without host is not allowed.
-        self.assertFalse(http.is_safe_url(r'http://testserver\@example.com'))
-
     def test_urlsafe_base64_roundtrip(self):
         bytestring = b'foo'
         encoded = http.urlsafe_base64_encode(bytestring)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git



More information about the Python-modules-commits mailing list