From de9644588b4949553d9fe284cfb17eb94e114489 Mon Sep 17 00:00:00 2001 From: Paul Kilgo Date: Thu, 16 Jun 2016 17:13:34 -0400 Subject: [PATCH 01/13] Update release notes and upgrading instructions --- README.upgrading.rst | 2 ++ RELEASE-NOTES.rst | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.upgrading.rst b/README.upgrading.rst index 4aeae85..a521390 100644 --- a/README.upgrading.rst +++ b/README.upgrading.rst @@ -20,6 +20,8 @@ The following table maps django-sshkey version to migration labels: +---------+---------------+-------+------------------------------------------+ | 2.4 | django_sshkey | 0001 | Django native migrations started. | +---------+---------------+-------+------------------------------------------+ +| 2.5 | django_sshkey | 0002 | | ++---------+---------------+-------+------------------------------------------+ To upgrade, install the new version of django-sshkey and then migrate your project to its corresponding label from the table above using the following diff --git a/RELEASE-NOTES.rst b/RELEASE-NOTES.rst index 2d5db3e..2239059 100644 --- a/RELEASE-NOTES.rst +++ b/RELEASE-NOTES.rst @@ -2,6 +2,20 @@ Release Notes for django-sshkey =============================== +2.5.0 (2016-06-16) +------------------ + +Migration label: 0002 + +* Stop testing against Django 1.4 through 1.7. +* Start testing against Django 1.9. +* Support for Python 3.3 and 3.4 (issue #6). +* Support OpenSSH 6.8+ MD5 and SHA256 fingerprints (issue #5). Also makes + django-sshkey compatible with fingerprints of unpatched OpenSSH 6.9+ + ``AuthorizedKeysCommand`` (issue #3). Add ``SSHKEY_DEFAULT_HASH`` setting. +* Add ``import_sshkey`` and ``normalize_sshkeys`` management commands. +* Code formatting cleanup. + 2.4.0 (2015-09-21) ------------------ From 20582287bfabadda4a00e386072f492747449a10 Mon Sep 17 00:00:00 2001 From: Paul Kilgo Date: Fri, 17 Jun 2016 09:39:36 -0400 Subject: [PATCH 02/13] Remove django16 from tox's default targets --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5b88777..aabc460 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = django16,django18,django19,flake8 +envlist = django18,django19,flake8 [testenv] commands = {envpython} manage.py test django_sshkey.tests [] From 9a20614e483e866d2f34cb5e12409f304afe6a06 Mon Sep 17 00:00:00 2001 From: Paul Kilgo Date: Fri, 17 Jun 2016 09:41:00 -0400 Subject: [PATCH 03/13] Bump version --- django_sshkey/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_sshkey/__init__.py b/django_sshkey/__init__.py index 39cd305..7afd9d7 100644 --- a/django_sshkey/__init__.py +++ b/django_sshkey/__init__.py @@ -27,4 +27,4 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -__version__ = '2.4.0' +__version__ = '2.5.0' From 59f08575933276d424d86365ac0419d33c7b17c8 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:09:30 +0200 Subject: [PATCH 04/13] Remove obsolete django.conf.urls.defaults It has been deprecated in Django 1.3 and removed in Django 1.6 --- django_sshkey/urls.py | 6 ++---- testproject/urls.py | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/django_sshkey/urls.py b/django_sshkey/urls.py index 26d0dfa..31825fa 100644 --- a/django_sshkey/urls.py +++ b/django_sshkey/urls.py @@ -1,4 +1,5 @@ # Copyright (c) 2014-2016, Clemson University +# Copyright (c) 2017, Baptiste Jonglez # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,10 +28,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -try: - from django.conf.urls.defaults import patterns, url -except ImportError: - from django.conf.urls import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns('django_sshkey.views', url(r'^lookup$', 'lookup'), # noqa diff --git a/testproject/urls.py b/testproject/urls.py index d697339..4d51bef 100644 --- a/testproject/urls.py +++ b/testproject/urls.py @@ -1,7 +1,4 @@ -try: - from django.conf.urls import patterns, include, url -except ImportError: - from django.conf.urls.defaults import patterns, include, url +from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() From d4a638ceb9bf3cca98cc76e3c601d896896a8f8a Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:10:25 +0200 Subject: [PATCH 05/13] Remove django.conf.urls.patterns It has been deprecated in Django 1.8 and removed in Django 1.11 See https://docs.djangoproject.com/en/1.11/releases/1.8/#django-conf-urls-patterns --- django_sshkey/urls.py | 18 ++++++++++-------- testproject/urls.py | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/django_sshkey/urls.py b/django_sshkey/urls.py index 31825fa..20cbfdb 100644 --- a/django_sshkey/urls.py +++ b/django_sshkey/urls.py @@ -28,12 +28,14 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from django.conf.urls import patterns, url +from django.conf.urls import url -urlpatterns = patterns('django_sshkey.views', - url(r'^lookup$', 'lookup'), # noqa - url(r'^$', 'userkey_list'), - url(r'^add$', 'userkey_add'), - url(r'^(?P\d+)$', 'userkey_edit'), - url(r'^(?P\d+)/delete$', 'userkey_delete'), -) +from . import views + +urlpatterns = [ + url(r'^lookup$', views.lookup), # noqa + url(r'^$', views.userkey_list), + url(r'^add$', views.userkey_add), + url(r'^(?P\d+)$', views.userkey_edit), + url(r'^(?P\d+)/delete$', views.userkey_delete), +] diff --git a/testproject/urls.py b/testproject/urls.py index 4d51bef..039d099 100644 --- a/testproject/urls.py +++ b/testproject/urls.py @@ -1,9 +1,9 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url from django.contrib import admin admin.autodiscover() -urlpatterns = patterns('', +urlpatterns = [ url(r'^', include('django_sshkey.urls')), url(r'^admin/', include(admin.site.urls)), -) +] From a57a9fedd81b0d501798b00bc5fe30820105b99e Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:16:11 +0200 Subject: [PATCH 06/13] testproject: use TEMPLATES variable introduced in Django 1.8 --- testproject/settings.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/testproject/settings.py b/testproject/settings.py index f27545d..4bf6348 100644 --- a/testproject/settings.py +++ b/testproject/settings.py @@ -23,8 +23,6 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -TEMPLATE_DEBUG = True - ALLOWED_HOSTS = [] @@ -85,9 +83,26 @@ STATIC_URL = '/static/' -TEMPLATE_DIRS = ( - os.path.join(BASE_DIR, 'testproject', 'templates'), -) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'testproject', 'templates'), + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] import getpass import socket From 80f02ddae26f91f96cd8c7211be872b17fef7df0 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:40:28 +0200 Subject: [PATCH 07/13] Remove usage of dotted path in reverse() This has been deprecated in Django 1.8 and removed in Django 1.10 See https://docs.djangoproject.com/en/1.11/releases/1.8/#passing-a-dotted-path-to-reverse-and-url --- django_sshkey/models.py | 2 +- .../templates.example/sshkey/userkey_list.html | 6 +++--- django_sshkey/tests.py | 12 ++++++------ django_sshkey/urls.py | 11 ++++++----- django_sshkey/views.py | 6 +++--- testproject/urls.py | 2 +- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/django_sshkey/models.py b/django_sshkey/models.py index e2ca36b..c548961 100644 --- a/django_sshkey/models.py +++ b/django_sshkey/models.py @@ -134,7 +134,7 @@ def send_email_add_key(sender, instance, **kwargs): if request: context_dict['request'] = request context_dict['userkey_list_uri'] = request.build_absolute_uri( - reverse('django_sshkey.views.userkey_list')) + reverse('django_sshkey:userkey_list')) text_content = render_to_string('sshkey/add_key.txt', context_dict) msg = EmailMultiAlternatives( settings.SSHKEY_EMAIL_ADD_KEY_SUBJECT, diff --git a/django_sshkey/templates.example/sshkey/userkey_list.html b/django_sshkey/templates.example/sshkey/userkey_list.html index dd5898a..facd244 100644 --- a/django_sshkey/templates.example/sshkey/userkey_list.html +++ b/django_sshkey/templates.example/sshkey/userkey_list.html @@ -7,7 +7,7 @@

My Keys

{% endfor %} {% endif %} -

Add Key

+

Add Key

@@ -30,9 +30,9 @@

My Keys

{% endfor %} diff --git a/django_sshkey/tests.py b/django_sshkey/tests.py index 91a2302..2d20c0e 100644 --- a/django_sshkey/tests.py +++ b/django_sshkey/tests.py @@ -524,7 +524,7 @@ def assertHasKeys(self, response, keys): self.assertEqual(actual, expected) def test_lookup_all(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') response = self.client.get(url) self.assertHasKeys(response, [ 'command="user1 %s" %s' % ( @@ -542,7 +542,7 @@ def test_lookup_all(self): ]) def test_lookup_by_fingerprint(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') fingerprint = ssh_fingerprint(self.key1_path + '.pub', hash='legacy') response = self.client.get(url, {'fingerprint': fingerprint}) self.assertHasKeys(response, [ @@ -553,7 +553,7 @@ def test_lookup_by_fingerprint(self): ]) def test_lookup_by_username_single_result(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') username = self.user2.username response = self.client.get(url, {'username': username}) self.assertHasKeys(response, [ @@ -564,7 +564,7 @@ def test_lookup_by_username_single_result(self): ]) def test_lookup_by_username_multiple_results(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') response = self.client.get(url, {'username': self.user1.username}) self.assertHasKeys(response, [ 'command="user1 %s" %s' % ( @@ -578,13 +578,13 @@ def test_lookup_by_username_multiple_results(self): ]) def test_lookup_nonexist_fingerprint(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') fingerprint = ':'.join(['ff'] * 16) response = self.client.get(url, {'fingerprint': fingerprint}) self.assertHasKeys(response, []) def test_lookup_nonexist_username(self): - url = reverse('django_sshkey.views.lookup') + url = reverse('django_sshkey:lookup') response = self.client.get(url, {'username': 'batman'}) self.assertHasKeys(response, []) diff --git a/django_sshkey/urls.py b/django_sshkey/urls.py index 20cbfdb..95c4186 100644 --- a/django_sshkey/urls.py +++ b/django_sshkey/urls.py @@ -32,10 +32,11 @@ from . import views +app_name = "django_sshkey" urlpatterns = [ - url(r'^lookup$', views.lookup), # noqa - url(r'^$', views.userkey_list), - url(r'^add$', views.userkey_add), - url(r'^(?P\d+)$', views.userkey_edit), - url(r'^(?P\d+)/delete$', views.userkey_delete), + url(r'^lookup$', views.lookup, name='lookup'), # noqa + url(r'^$', views.userkey_list, name='userkey_list'), + url(r'^add$', views.userkey_add, name='userkey_add'), + url(r'^(?P\d+)$', views.userkey_edit, name='userkey_edit'), + url(r'^(?P\d+)/delete$', views.userkey_delete, name='userkey_delete'), ] diff --git a/django_sshkey/views.py b/django_sshkey/views.py index fa0b2ac..5556155 100644 --- a/django_sshkey/views.py +++ b/django_sshkey/views.py @@ -92,7 +92,7 @@ def userkey_add(request): form = UserKeyForm(request.POST, instance=userkey) if form.is_valid(): form.save() - default_redirect = reverse('django_sshkey.views.userkey_list') + default_redirect = reverse('django_sshkey:userkey_list') url = request.GET.get('next', default_redirect) if not is_safe_url(url=url, host=request.get_host()): url = default_redirect @@ -120,7 +120,7 @@ def userkey_edit(request, pk): form = UserKeyForm(request.POST, instance=userkey) if form.is_valid(): form.save() - default_redirect = reverse('django_sshkey.views.userkey_list') + default_redirect = reverse('django_sshkey:userkey_list') url = request.GET.get('next', default_redirect) if not is_safe_url(url=url, host=request.get_host()): url = default_redirect @@ -145,4 +145,4 @@ def userkey_delete(request, pk): userkey.delete() message = 'SSH public key %s was deleted.' % userkey.name messages.success(request, message, fail_silently=True) - return HttpResponseRedirect(reverse('django_sshkey.views.userkey_list')) + return HttpResponseRedirect(reverse('django_sshkey:userkey_list')) diff --git a/testproject/urls.py b/testproject/urls.py index 039d099..a197779 100644 --- a/testproject/urls.py +++ b/testproject/urls.py @@ -4,6 +4,6 @@ admin.autodiscover() urlpatterns = [ - url(r'^', include('django_sshkey.urls')), + url(r'^', include('django_sshkey.urls', namespace='django_sshkey')), url(r'^admin/', include(admin.site.urls)), ] From 2eaae5ddbb86849af53f1c61e9b37507dc2d0173 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:42:37 +0200 Subject: [PATCH 08/13] Test against Django 1.10 and Django 1.11 --- .travis.yml | 2 ++ tox.ini | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b014915..20bc9a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: python env: - TOX_ENV=django18 - TOX_ENV=django19 + - TOX_ENV=django110 + - TOX_ENV=django111 - TOX_ENV=py33 - TOX_ENV=py34 - TOX_ENV=flake8 diff --git a/tox.ini b/tox.ini index aabc460..a65f48e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = django18,django19,flake8 +envlist = django18,django19,django110,django111,flake8 [testenv] commands = {envpython} manage.py test django_sshkey.tests [] @@ -12,7 +12,15 @@ deps = [testenv:django19] deps = - Django < 2.0 + Django < 1.10 + +[testenv:django110] +deps = + Django < 1.11 + +[testenv:django111] +deps = + Django < 1.12 [testenv:flake8] commands = flake8 lookup.py manage.py setup.py django_sshkey From 5522c42082d62e82d9da9f20d9f651cb8154ded2 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 11:47:33 +0200 Subject: [PATCH 09/13] setup: advertise compatibility with Python 3.5 and 3.6 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 493bb64..dc41303 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,8 @@ 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', ], From 17447323896ae301a139897f0183b7ca029f87f4 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 23:49:44 +0200 Subject: [PATCH 10/13] Use more modern render() syntax The old syntax has been deprecated in Django 1.8 and does not work anymore with Django 1.11. See https://docs.djangoproject.com/en/1.11/releases/1.8/#dictionary-and-context-instance-arguments-of-rendering-functions --- django_sshkey/views.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/django_sshkey/views.py b/django_sshkey/views.py index 5556155..42b8345 100644 --- a/django_sshkey/views.py +++ b/django_sshkey/views.py @@ -30,7 +30,7 @@ from django.http import HttpResponse, HttpResponseRedirect from django.views.decorators.http import require_http_methods, require_GET from django.views.decorators.csrf import csrf_exempt -from django.shortcuts import get_object_or_404, render_to_response +from django.shortcuts import get_object_or_404, render from django.template import RequestContext from django.contrib import messages from django.contrib.auth.decorators import login_required @@ -76,10 +76,8 @@ def lookup(request): @require_GET def userkey_list(request): userkey_list = UserKey.objects.filter(user=request.user) - return render_to_response( - 'sshkey/userkey_list.html', - {'userkey_list': userkey_list, 'allow_edit': settings.SSHKEY_ALLOW_EDIT}, - context_instance=RequestContext(request), + return render(request, 'sshkey/userkey_list.html', + context={'userkey_list': userkey_list, 'allow_edit': settings.SSHKEY_ALLOW_EDIT} ) @@ -101,11 +99,8 @@ def userkey_add(request): return HttpResponseRedirect(url) else: form = UserKeyForm() - return render_to_response( - 'sshkey/userkey_detail.html', - {'form': form, 'action': 'add'}, - context_instance=RequestContext(request), - ) + return render(request, 'sshkey/userkey_detail.html', + context={'form': form, 'action': 'add'}) @login_required @@ -129,11 +124,8 @@ def userkey_edit(request, pk): return HttpResponseRedirect(url) else: form = UserKeyForm(instance=userkey) - return render_to_response( - 'sshkey/userkey_detail.html', - {'form': form, 'action': 'edit'}, - context_instance=RequestContext(request), - ) + return render(request, 'sshkey/userkey_detail.html', + context={'form': form, 'action': 'edit'}) @login_required From cf9e814c8f6a387e1ecfb4aaaea1a4564a3286df Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 22 May 2017 23:53:09 +0200 Subject: [PATCH 11/13] Remove obsolete template tag loading It has been deprecated in Django 1.7 and removed in Django 1.9 See https://docs.djangoproject.com/en/1.11/releases/1.7/#loading-ssi-and-url-template-tags-from-future-library --- django_sshkey/templates.example/sshkey/userkey_list.html | 1 - 1 file changed, 1 deletion(-) diff --git a/django_sshkey/templates.example/sshkey/userkey_list.html b/django_sshkey/templates.example/sshkey/userkey_list.html index facd244..7f84775 100644 --- a/django_sshkey/templates.example/sshkey/userkey_list.html +++ b/django_sshkey/templates.example/sshkey/userkey_list.html @@ -1,4 +1,3 @@ -{% load url from future %}

My Keys

{% if messages %}
    From 3b3a1d59311a5613884d666f32d04cf570297a1d Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Sat, 27 May 2017 16:53:20 +0200 Subject: [PATCH 12/13] Use a ForeignKey to settings.AUTH_USER_MODEL instead of hard-coding Django's User model This is better, because it allows django_sshkey to be used in projects that use a custom User model: https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#referencing-the-user-model Note that there is no migration needed with this change, since the first migration apparently already references settings.AUTH_USER_MODEL. --- django_sshkey/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_sshkey/models.py b/django_sshkey/models.py index c548961..2b982ba 100644 --- a/django_sshkey/models.py +++ b/django_sshkey/models.py @@ -28,7 +28,7 @@ # POSSIBILITY OF SUCH DAMAGE. from django.db import models -from django.contrib.auth.models import User +from django.conf import settings as django_settings from django.core.exceptions import ValidationError from django.db.models.signals import pre_save from django.dispatch import receiver @@ -42,7 +42,7 @@ class UserKey(models.Model): - user = models.ForeignKey(User, db_index=True) + user = models.ForeignKey(django_settings.AUTH_USER_MODEL, db_index=True) name = models.CharField(max_length=50, blank=True) key = models.TextField(max_length=2000) fingerprint = models.CharField(max_length=128, blank=True, db_index=True) From 8deba35e172c916b76e7b31886872a8b84a5cdbb Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Sat, 27 May 2017 16:57:05 +0200 Subject: [PATCH 13/13] Explicitly set on_delete=CASCADE for the ForeignKey to User on_delete currently defaults to CASCADE (so, there is no functional change), but this will become a required argument in Django 2.0. See https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.ForeignKey.on_delete Again, no migration is necessary here, because this is the default value. --- django_sshkey/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/django_sshkey/models.py b/django_sshkey/models.py index 2b982ba..245cd80 100644 --- a/django_sshkey/models.py +++ b/django_sshkey/models.py @@ -42,7 +42,8 @@ class UserKey(models.Model): - user = models.ForeignKey(django_settings.AUTH_USER_MODEL, db_index=True) + user = models.ForeignKey(django_settings.AUTH_USER_MODEL, db_index=True, + on_delete=models.CASCADE) name = models.CharField(max_length=50, blank=True) key = models.TextField(max_length=2000) fingerprint = models.CharField(max_length=128, blank=True, db_index=True)
Key {{ userkey.last_used|default:"never" }} {% if allow_edit %} - Edit + Edit {% endif %} - Delete + Delete