diff --git a/.travis.yml b/.travis.yml index 7d513b8..c0fcbbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python dist: xenial cache: pip python: -- '3.5' - '3.6' - '3.7' - '3.8' diff --git a/README.rst b/README.rst index 7921768..01b956f 100644 --- a/README.rst +++ b/README.rst @@ -10,6 +10,10 @@ django-defender :alt: Supported Python versions :target: https://pypi.org/project/django-defender/ +.. image:: https://img.shields.io/pypi/djversions/django-defender.svg + :target: https://pypi.org/project/django-defender/ + :alt: Supported Django versions + .. image:: https://travis-ci.org/jazzband/django-defender.svg :target: https://travis-ci.org/jazzband/django-defender :alt: Build Status @@ -104,8 +108,8 @@ Admin pages Requirements ------------ -* Python: 3.5, 3.6, 3.7, 3.8, PyPy -* Django: 1.11, 2.1, 2.2, 3.x +* Python: 3.6, 3.7, 3.8, PyPy +* Django: 2.2, 3.x * Redis @@ -165,8 +169,8 @@ following to your ``urls.py`` .. code-block:: python urlpatterns = [ - url(r'^admin/', include(admin.site.urls)), # normal admin - url(r'^admin/defender/', include('defender.urls')), # defender admin + path('admin/', include(admin.site.urls)), # normal admin + path('admin/defender/', include('defender.urls')), # defender admin # your own patterns follow... ] @@ -674,13 +678,13 @@ like: .. code-block:: bash - PYTHONPATH=$PYTHONPATH:$PWD django-admin.py test defender --settings=defender.test_settings + PYTHONPATH=$PYTHONPATH:$PWD django-admin test defender --settings=defender.test_settings With Code coverage: .. code-block:: bash - PYTHONPATH=$PYTHONPATH:$PWD coverage run --source=defender $(which django-admin.py) test defender --settings=defender.test_settings + PYTHONPATH=$PYTHONPATH:$PWD coverage run --source=defender $(which django-admin) test defender --settings=defender.test_settings Releasing diff --git a/defender/middleware.py b/defender/middleware.py index 914c5af..5f244b0 100644 --- a/defender/middleware.py +++ b/defender/middleware.py @@ -1,33 +1,27 @@ -try: - from django.utils.deprecation import MiddlewareMixin as MIDDLEWARE_BASE_CLASS -except ImportError: - MIDDLEWARE_BASE_CLASS = object -from django.contrib.auth import views as auth_views +from django.contrib.auth.views import LoginView from django.utils.decorators import method_decorator from .decorators import watch_login -class FailedLoginMiddleware(MIDDLEWARE_BASE_CLASS): +class FailedLoginMiddleware: """ Failed login middleware """ patched = False - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, get_response): + self.get_response = get_response + # Watch the auth login. # Monkey-patch only once - otherwise we would be recording # failed attempts multiple times! if not FailedLoginMiddleware.patched: - # Django 1.11 turned the `login` function view into the - # `LoginView` class-based view - try: - from django.contrib.auth.views import LoginView - - our_decorator = watch_login() - watch_login_method = method_decorator(our_decorator) - LoginView.dispatch = watch_login_method(LoginView.dispatch) - except ImportError: # Django < 1.11 - auth_views.login = watch_login()(auth_views.login) + our_decorator = watch_login() + watch_login_method = method_decorator(our_decorator) + LoginView.dispatch = watch_login_method(LoginView.dispatch) FailedLoginMiddleware.patched = True + + def __call__(self, request): + response = self.get_response(request) + return response \ No newline at end of file diff --git a/defender/south_migrations/0001_initial.py b/defender/south_migrations/0001_initial.py deleted file mode 100644 index d491445..0000000 --- a/defender/south_migrations/0001_initial.py +++ /dev/null @@ -1,100 +0,0 @@ -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - """Initial Migration for Defender""" - - def forwards(self, orm): - """ Adding model 'AccessAttempt' """ - db.create_table( - "defender_accessattempt", - ( - ("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)), - ( - "user_agent", - self.gf("django.db.models.fields.CharField")(max_length=255), - ), - ( - "ip_address", - self.gf("django.db.models.fields.GenericIPAddressField")( - max_length=39, null=True - ), - ), - ( - "username", - self.gf("django.db.models.fields.CharField")( - max_length=255, null=True - ), - ), - ( - "http_accept", - self.gf("django.db.models.fields.CharField")(max_length=1025), - ), - ( - "path_info", - self.gf("django.db.models.fields.CharField")(max_length=255), - ), - ( - "attempt_time", - self.gf("django.db.models.fields.DateTimeField")( - auto_now_add=True, blank=True - ), - ), - ( - "login_valid", - self.gf("django.db.models.fields.BooleanField")(default=False), - ), - ), - ) - db.send_create_signal("defender", ["AccessAttempt"]) - - def backwards(self, orm): - # Deleting model 'AccessAttempt' - db.delete_table("defender_accessattempt") - - models = { - "defender.accessattempt": { - "Meta": {"ordering": "[u'-attempt_time']", "object_name": "AccessAttempt"}, - "attempt_time": ( - "django.db.models.fields.DateTimeField", - [], - {"auto_now_add": "True", "blank": "True"}, - ), - "http_accept": ( - "django.db.models.fields.CharField", - [], - {"max_length": "1025"}, - ), - "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), - "ip_address": ( - "django.db.models.fields.GenericIPAddressField", - [], - {"max_length": "39", "null": "True"}, - ), - "login_valid": ( - "django.db.models.fields.BooleanField", - [], - {"default": "False"}, - ), - "path_info": ( - "django.db.models.fields.CharField", - [], - {"max_length": "255"}, - ), - "user_agent": ( - "django.db.models.fields.CharField", - [], - {"max_length": "255"}, - ), - "username": ( - "django.db.models.fields.CharField", - [], - {"max_length": "255", "null": "True"}, - ), - } - } - - complete_apps = ["defender"] diff --git a/defender/south_migrations/__init__.py b/defender/south_migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/defender/test_urls.py b/defender/test_urls.py index 1776d41..6c9135c 100644 --- a/defender/test_urls.py +++ b/defender/test_urls.py @@ -1,6 +1,6 @@ -from django.conf.urls import url, include +from django.urls import path from django.contrib import admin from .urls import urlpatterns as original_urlpatterns -urlpatterns = [url(r"^admin/", admin.site.urls),] + original_urlpatterns +urlpatterns = [path("admin/", admin.site.urls),] + original_urlpatterns diff --git a/defender/tests.py b/defender/tests.py index 99b4528..491df36 100644 --- a/defender/tests.py +++ b/defender/tests.py @@ -1,21 +1,15 @@ import random import string import time -from distutils.version import StrictVersion from unittest.mock import patch -from django import get_version from django.contrib.auth.models import User from django.contrib.auth.models import AnonymousUser from django.contrib.sessions.backends.db import SessionStore from django.http import HttpRequest, HttpResponse from django.test.client import RequestFactory from redis.client import Redis - -try: - from django.urls import reverse -except ImportError: - from django.core.urlresolvers import reverse +from django.urls import reverse from . import utils from . import config @@ -33,8 +27,6 @@ from .test import DefenderTestCase, DefenderTransactionTestCase LOGIN_FORM_KEY = '