From 3f7035eb686d48efee3e0070c0d55c89023e78b8 Mon Sep 17 00:00:00 2001 From: Antoine d'Otreppe Date: Tue, 14 Feb 2017 13:28:42 +0100 Subject: [PATCH 001/216] Added French translations --- rest_auth/locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 2334 bytes rest_auth/locale/fr/LC_MESSAGES/django.po | 98 ++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 rest_auth/locale/fr/LC_MESSAGES/django.mo create mode 100644 rest_auth/locale/fr/LC_MESSAGES/django.po diff --git a/rest_auth/locale/fr/LC_MESSAGES/django.mo b/rest_auth/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..510118c2e838172b018f6331e0c9a9000d29eb66 GIT binary patch literal 2334 zcma)7OK)366ds_365a&~P(eBvN`dyev0K`ZDymA8K%|6*l2$B=s>!`$dz$MRcOFi{ zs(aQTA%S37BO$S@5Ie8ffy5Rh@(0+l<~wt3*$F~rr15uW=9_cQoR|MNdgyb3@f_w$ zm_K2@jCtb${9yb7JO}(0$md5M6yg~0_y{inpU3(WU=tXDPXX@&UjyC)o&f$1d)llK<0f0d;$0a@Hp^i;7Q?4Rw<1zf=8R7}dXVZ=lPXnLCgt#P+ZH6nv zGnnH66=~qf;&IFwUR|Q-l_Tv*mQKlHmz-*AACyxCZR^mX(7~a~x>A=Ui^3`I>ta#0 zv{6{g9;i3-QhHC?P+zO<@nJ5@a#QA8H=`^6byjL+!hw5Bl@h2kHc($V-O{S4ixrbw z=Tsgbr58h;WS+x{o55}=L)KAl3&l@x>UPvHeELdXmQjhd==pYDMlfrNA5$Y~3aa&B z`L=aMt$u*SelfDE?!!~?5gb^X&|%PjY4|{G(^w&Oq^C`V7kJrco7YE{Ob*~{6~<9e zWTtLU(JR&{LKC6zZ(V#8ldD>>EO)82?KYxn;X<*|Q53fA#2UD|EIbvuFed_aWym{q zam~oh5=6^)Iff}Cdd~KB0ZBQ04K-SpNQrBlM~IA#2CimFo-gBJ*O3&w!%;0#;uNQn zV$y-&1c?Bepmq>*=`>#wc1x@~dkZnoR*LMpa$Z|APcv6l&$^JU`L-^ycVpXU8y4H^ zS2nWCNZ$ZfwkU&|r{-+qT-Io2%_cP(^JmUyvvaevAZAxpU$e9c4`gu>8^v&-xF($J4(|q(1Xp|2HGG{`N@~d%(i^6F2P?CYce#UL zH7#KxKrC9gGIbB9n4P@CmrDyht zk2F9v8)TR@q*^VMa71jXB=cxT!@Fn}s|Zk`;tt!yUzNdV5sEx&D}}cNr#t+vtH4LW zjYR5h&w8)9Ev39=mNqR^P%_X{%SLB3U&51f+r=N${@jOCkoaEaL06uU>~(HZ93xII g_8TV{Xq^74>Q<-$q&oWbxJ!-OR#YWg)|D;s4@F(t%>V!Z literal 0 HcmV?d00001 diff --git a/rest_auth/locale/fr/LC_MESSAGES/django.po b/rest_auth/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..b1e97d3 --- /dev/null +++ b/rest_auth/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,98 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-12-22 11:37-0800\n" +"PO-Revision-Date: 2017-02-14 13:27+0100\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: \n" +"Language-Team: \n" +"X-Generator: Poedit 1.8.11\n" + +#: registration/serializers.py:53 +msgid "View is not defined, pass it as a context variable" +msgstr "La “View” n’est pas définie, passez la en variable contextuelle" + +#: registration/serializers.py:58 +msgid "Define adapter_class in view" +msgstr "Définissez “adapter_class” dans la vue" + +#: registration/serializers.py:77 +msgid "Define callback_url in view" +msgstr "Définissez “callback_url” dans la vue" + +#: registration/serializers.py:81 +msgid "Define client_class in view" +msgstr "Définissez “client_class” dans la vue" + +#: registration/serializers.py:102 +msgid "Incorrect input. access_token or code is required." +msgstr "Paramètres incorrects. Il faut “access_token” ou “code”." + +#: registration/serializers.py:111 +msgid "Incorrect value" +msgstr "Paramètre incorrect" + +#: registration/serializers.py:140 +msgid "A user is already registered with this e-mail address." +msgstr "Un utilisateur existe déjà avec cette adresse email." + +#: registration/serializers.py:148 +msgid "The two password fields didn't match." +msgstr "Les deux mots de passes ne sont pas les mêmes." + +#: registration/views.py:82 +msgid "ok" +msgstr "Ok" + +#: serializers.py:30 +msgid "Must include \"email\" and \"password\"." +msgstr "Doit inclure “email” et “password”." + +#: serializers.py:41 +msgid "Must include \"username\" and \"password\"." +msgstr "Doit inclure “username” et “password”." + +#: serializers.py:54 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Doit inclure un “username” ou “email”, et un “password”." + +#: serializers.py:95 +msgid "User account is disabled." +msgstr "Le compte utilisateur est désactivé." + +#: serializers.py:98 +msgid "Unable to log in with provided credentials." +msgstr "Connexion impossible avec les informations fournies." + +#: serializers.py:107 +msgid "E-mail is not verified." +msgstr "L’adresse email n’a pas été vérifiée." + +#: views.py:114 +msgid "Successfully logged out." +msgstr "Déconnexion effectuée avec succès." + +#: views.py:162 +msgid "Password reset e-mail has been sent." +msgstr "L’email de réinitialisation du mot de passe a été envoyé." + +#: views.py:184 +msgid "Password has been reset with the new password." +msgstr "Le mot de passe a été réinitialisé." + +#: views.py:202 +msgid "New password has been saved." +msgstr "Le nouveau mot de passe est sauvé." + +#~ msgid "Error" +#~ msgstr "Fehler" From 6da0703b0daefcc1d569027b5d5862bda86c5ee0 Mon Sep 17 00:00:00 2001 From: Grigoriy Beziuk Date: Fri, 30 Jun 2017 13:59:10 +0300 Subject: [PATCH 002/216] LoginView.get_response modified in order to respect rest_framework_jwt.JWT_AUTH_COOKIE setting --- rest_auth/views.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 0493a76..290c837 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -84,7 +84,17 @@ class LoginView(GenericAPIView): serializer = serializer_class(instance=self.token, context={'request': self.request}) - return Response(serializer.data, status=status.HTTP_200_OK) + response = Response(serializer.data, status=status.HTTP_200_OK) + if getattr(settings, 'REST_USE_JWT', False): + from rest_framework_jwt.settings import api_settings as jwt_settings + if jwt_settings.JWT_AUTH_COOKIE: + from datetime import datetime + expiration = (datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA) + response.set_cookie(jwt_settings.JWT_AUTH_COOKIE, + self.token, + expires=expiration, + httponly=True) + return response def post(self, request, *args, **kwargs): self.request = request From 46fd16700a9e64fc23d843a9c3ff8c1798d60cd0 Mon Sep 17 00:00:00 2001 From: Grigoriy Beziuk Date: Fri, 30 Jun 2017 14:23:56 +0300 Subject: [PATCH 003/216] also for cookie deletion --- rest_auth/views.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 290c837..20175b0 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -133,8 +133,13 @@ class LogoutView(APIView): django_logout(request) - return Response({"detail": _("Successfully logged out.")}, - status=status.HTTP_200_OK) + response = Response({"detail": _("Successfully logged out.")}, + status=status.HTTP_200_OK) + if getattr(settings, 'REST_USE_JWT', False): + from rest_framework_jwt.settings import api_settings as jwt_settings + if jwt_settings.JWT_AUTH_COOKIE: + response.delete_cookie(jwt_settings.JWT_AUTH_COOKIE) + return response class UserDetailsView(RetrieveUpdateAPIView): From 801bad7c6134e84016d4d1d6ade85c416ce442a5 Mon Sep 17 00:00:00 2001 From: Maxim Kukhtenkov Date: Wed, 6 Jun 2018 15:01:22 -0400 Subject: [PATCH 004/216] Update copyright and version number in Docs config --- docs/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index faba401..c8ecb3b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,16 +44,16 @@ master_doc = 'index' # General information about the project. project = u'django-rest-auth' -copyright = u'2014, Tivix Inc.' +copyright = u'2018, Tivix Inc.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.3.0' +version = '0.9.3' # The full version, including alpha/beta/rc tags. -release = '0.3.0' +release = '0.9.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 95fafe5e0f6716296a1c664c2b870876a6b4e0cc Mon Sep 17 00:00:00 2001 From: Maxim Kukhtenkov Date: Wed, 6 Jun 2018 17:10:43 -0400 Subject: [PATCH 005/216] Remove Django 1.8 from Travis config --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b05a3f7..c296c2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ python: - "3.5" - "3.6" env: - - DJANGO=1.8.* DRF=3.6.* - DJANGO=1.11.* DRF=3.7.* - DJANGO=2.0.* DRF=3.7.* install: From 90760548f6905c5f251a3df6c9f00057b954bac3 Mon Sep 17 00:00:00 2001 From: Daniel <33256939+dgilge@users.noreply.github.com> Date: Mon, 11 Jun 2018 08:46:59 +0200 Subject: [PATCH 006/216] Add DRF 3.8 to Travis config --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c296c2b..5ca0bf6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ python: - "3.6" env: - DJANGO=1.11.* DRF=3.7.* + - DJANGO=1.11.* DRF=3.8.* - DJANGO=2.0.* DRF=3.7.* + - DJANGO=2.0.* DRF=3.8.* install: - pip install -q Django==$DJANGO djangorestframework==$DRF - pip install coveralls @@ -20,3 +22,4 @@ matrix: exclude: - python: "2.7" env: DJANGO=2.0.* DRF=3.7.* + env: DJANGO=2.0.* DRF=3.8.* From db60e433974018d30baf72e224c94463822c387f Mon Sep 17 00:00:00 2001 From: Daniel <33256939+dgilge@users.noreply.github.com> Date: Mon, 11 Jun 2018 09:02:02 +0200 Subject: [PATCH 007/216] Exclude Python 2.7 for Django 2.0 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5ca0bf6..b059c1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,5 @@ matrix: exclude: - python: "2.7" env: DJANGO=2.0.* DRF=3.7.* + - python: "2.7" env: DJANGO=2.0.* DRF=3.8.* From a1845aef434c788561b88616bb151abaa7e9c67b Mon Sep 17 00:00:00 2001 From: Daniel <33256939+dgilge@users.noreply.github.com> Date: Thu, 14 Jun 2018 00:06:20 +0200 Subject: [PATCH 008/216] Pass request to authenticate --- rest_auth/serializers.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index 45729b2..2ea6550 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -21,11 +21,14 @@ class LoginSerializer(serializers.Serializer): email = serializers.EmailField(required=False, allow_blank=True) password = serializers.CharField(style={'input_type': 'password'}) + def authenticate(self, **kwargs): + return authenticate(self.context['request'], **kwargs) + def _validate_email(self, email, password): user = None if email and password: - user = authenticate(email=email, password=password) + user = self.authenticate(email=email, password=password) else: msg = _('Must include "email" and "password".') raise exceptions.ValidationError(msg) @@ -36,7 +39,7 @@ class LoginSerializer(serializers.Serializer): user = None if username and password: - user = authenticate(username=username, password=password) + user = self.authenticate(username=username, password=password) else: msg = _('Must include "username" and "password".') raise exceptions.ValidationError(msg) @@ -47,9 +50,9 @@ class LoginSerializer(serializers.Serializer): user = None if email and password: - user = authenticate(email=email, password=password) + user = self.authenticate(email=email, password=password) elif username and password: - user = authenticate(username=username, password=password) + user = self.authenticate(username=username, password=password) else: msg = _('Must include either "username" or "email" and "password".') raise exceptions.ValidationError(msg) From b9fd4aba96a99f329c71dfe9a68ccf289d7d020a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Dohnal?= Date: Wed, 27 Jun 2018 23:06:34 +0200 Subject: [PATCH 009/216] add czech (cs) translations stub --- rest_auth/locale/cs/LC_MESSAGES/django.po | 103 ++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 rest_auth/locale/cs/LC_MESSAGES/django.po diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000..3ac6d98 --- /dev/null +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,103 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-27 23:05+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: .\registration\serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "" + +#: .\registration\serializers.py:72 +msgid "Define adapter_class in view" +msgstr "" + +#: .\registration\serializers.py:91 +msgid "Define callback_url in view" +msgstr "" + +#: .\registration\serializers.py:95 +msgid "Define client_class in view" +msgstr "" + +#: .\registration\serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "" + +#: .\registration\serializers.py:125 +msgid "Incorrect value" +msgstr "" + +#: .\registration\serializers.py:139 +msgid "User is already registered with this e-mail address." +msgstr "" + +#: .\registration\serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "" + +#: .\registration\serializers.py:193 +msgid "The two password fields didn't match." +msgstr "" + +#: .\registration\views.py:51 +msgid "Verification e-mail sent." +msgstr "" + +#: .\registration\views.py:98 +msgid "ok" +msgstr "" + +#: .\serializers.py:30 +msgid "Must include \"email\" and \"password\"." +msgstr "" + +#: .\serializers.py:41 +msgid "Must include \"username\" and \"password\"." +msgstr "" + +#: .\serializers.py:54 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "" + +#: .\serializers.py:95 +msgid "User account is disabled." +msgstr "" + +#: .\serializers.py:98 +msgid "Unable to log in with provided credentials." +msgstr "" + +#: .\serializers.py:107 +msgid "E-mail is not verified." +msgstr "" + +#: .\views.py:127 +msgid "Successfully logged out." +msgstr "" + +#: .\views.py:175 +msgid "Password reset e-mail has been sent." +msgstr "" + +#: .\views.py:201 +msgid "Password has been reset with the new password." +msgstr "" + +#: .\views.py:223 +msgid "New password has been saved." +msgstr "" From fa3000e8bd5b1c7c3622056d25badb953fbc5cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Dohnal?= Date: Wed, 27 Jun 2018 23:18:39 +0200 Subject: [PATCH 010/216] add cs translations --- rest_auth/locale/cs/LC_MESSAGES/django.mo | Bin 0 -> 2376 bytes rest_auth/locale/cs/LC_MESSAGES/django.po | 63 +++++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) create mode 100644 rest_auth/locale/cs/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.mo b/rest_auth/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..38857f9a881619301ecd04a57fd1aa8bd0febe2f GIT binary patch literal 2376 zcmbW2O>7%Q6vqcB1of%MvC{bG*?IHcoBupN z|GanCb%y6@j2AJ!!*~hf+CBKd^DB4~{0;Q$Blj})0yvqIgU?|80aymFgL}Yl!TsP* z;34o2@D1?5eSJR*V2JrO(A#|mJ`4T;9sqvod0iFQo^Z7@hkM}7E*X&1d z5joxhk70ghH)F4WSHYLTPjY?<`Z(W%N5R|RliZc!5Fyx87!PCM zSnN@ZeHcF9$1xtmfZOc+{{A2tdjezdAVl`ukIzRi3VwEmQYS1)M_gIK<7KjV z>2Q?_Hk~@ZJ5nhui^3nKNLd&{`yeTM(qT?A~JDx5{s5=oI>f?42}|YB5!6nUty3aH|Fq zvbnmTWXTM(fz&E?6w6p2N~pz?s2;L;&8rHA#_#oam{mmEnvRU&DT3ArBe_CJ%={D?uV*jK1?TW<@UesQ zJQ3qmE{%=_rISJVbt)epFTHl8R4$cZ7+e+|>Ame}H=5gBfE9RD)Vy}g0Z2U<=QO@8%*Mt5ldYgr?IL`3bQJ; zTm=`5ZMkvM?QH5Q$0w-&wKAeBmC?g=no2ZIBl=XOOa~8=ezS7IzZ}KO@M#e8%3_S8Lv{^#Hc&&dxdvdb-ZqHUi{*-=7nZK#kz3H^!v%(Ht9ed z*X*uQqt#v0=Kt)_qH1=GI0IGJD2q?kWo0N;rne!q3E36iTNPWEvbK@k0#2t|#1hv% literal 0 HcmV?d00001 diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po index 3ac6d98..43ab5e5 100644 --- a/rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -1,103 +1,102 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# Czech translations of django-rest-auth +# +# This file is distributed under the same license as the django-model-utils package. # -#, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" +"Project-Id-Version: django-rest-auth\n" +"Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n" "POT-Creation-Date: 2018-06-27 23:05+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"PO-Revision-Date: 2018-06-27 23:15+0200\n" +"Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Last-Translator: Václav Dohnal \n" +"Language-Team: N/A\n" +"X-Generator: Poedit 2.0.8\n" #: .\registration\serializers.py:67 msgid "View is not defined, pass it as a context variable" -msgstr "" +msgstr "View není definováno, předejte jej jako proměnnou kontextu" #: .\registration\serializers.py:72 msgid "Define adapter_class in view" -msgstr "" +msgstr "Definujte adapter_class ve view" #: .\registration\serializers.py:91 msgid "Define callback_url in view" -msgstr "" +msgstr "Definujte callback_url ve view" #: .\registration\serializers.py:95 msgid "Define client_class in view" -msgstr "" +msgstr "Definujte client_class ve view" #: .\registration\serializers.py:116 msgid "Incorrect input. access_token or code is required." -msgstr "" +msgstr "Nesprávný vstup. access_token je povinný." #: .\registration\serializers.py:125 msgid "Incorrect value" -msgstr "" +msgstr "Nesprávná hodnota" #: .\registration\serializers.py:139 msgid "User is already registered with this e-mail address." -msgstr "" +msgstr "Uživatel s touto adresou je již registrován." #: .\registration\serializers.py:185 msgid "A user is already registered with this e-mail address." -msgstr "" +msgstr "Uživatel s touto adresou je již registrován." #: .\registration\serializers.py:193 msgid "The two password fields didn't match." -msgstr "" +msgstr "Zadaná hesla se neshodují." #: .\registration\views.py:51 msgid "Verification e-mail sent." -msgstr "" +msgstr "Ověřovací e-mail odeslán." #: .\registration\views.py:98 msgid "ok" -msgstr "" +msgstr "ok" #: .\serializers.py:30 msgid "Must include \"email\" and \"password\"." -msgstr "" +msgstr "Musí obsahovat \"e-mail\" a \"heslo\"." #: .\serializers.py:41 msgid "Must include \"username\" and \"password\"." -msgstr "" +msgstr "Musí obsahovat \"uživatelské jméno\" a \"heslo\"." #: .\serializers.py:54 msgid "Must include either \"username\" or \"email\" and \"password\"." -msgstr "" +msgstr "Musí obsahovat \"uživatelské jméno\" nebo \"e-mail\" a \"heslo\"." #: .\serializers.py:95 msgid "User account is disabled." -msgstr "" +msgstr "Uživatelský účet je zakázán." #: .\serializers.py:98 msgid "Unable to log in with provided credentials." -msgstr "" +msgstr "Pomocí zadaných údajů se nelze přihlásit." #: .\serializers.py:107 msgid "E-mail is not verified." -msgstr "" +msgstr "E-mail není ověřený." #: .\views.py:127 msgid "Successfully logged out." -msgstr "" +msgstr "Byli jste úspěšně odhlášení." #: .\views.py:175 msgid "Password reset e-mail has been sent." -msgstr "" +msgstr "E-mail pro resetování hesla byl odeslán." #: .\views.py:201 msgid "Password has been reset with the new password." -msgstr "" +msgstr "Vaše heslo bylo resetováno." #: .\views.py:223 msgid "New password has been saved." -msgstr "" +msgstr "Nové heslo bylo uloženo." From 98212a83f5ddacd78b11ea975bbdebc4f15a1fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=C5=A1ek=20Dohnal?= Date: Wed, 27 Jun 2018 23:19:48 +0200 Subject: [PATCH 011/216] fix typo --- rest_auth/locale/cs/LC_MESSAGES/django.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po index 43ab5e5..d09df89 100644 --- a/rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -1,10 +1,10 @@ # Czech translations of django-rest-auth # -# This file is distributed under the same license as the django-model-utils package. +# This file is distributed under the same license as the Tivix/django-rest-auth package. # msgid "" msgstr "" -"Project-Id-Version: django-rest-auth\n" +"Project-Id-Version: Tivix/django-rest-auth\n" "Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n" "POT-Creation-Date: 2018-06-27 23:05+0200\n" "PO-Revision-Date: 2018-06-27 23:15+0200\n" From b778a5085b5086527edf706e110ea03f980e77d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=C5=A1ek=20Dohnal?= Date: Wed, 27 Jun 2018 23:20:10 +0200 Subject: [PATCH 012/216] add full project name --- rest_auth/locale/cs/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po index d09df89..57291c7 100644 --- a/rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -1,4 +1,4 @@ -# Czech translations of django-rest-auth +# Czech translations of Tivix/django-rest-auth # # This file is distributed under the same license as the Tivix/django-rest-auth package. # From 3af4f1a3438bd7add61c549669c8bd35a68b68db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=C5=A1ek=20Dohnal?= Date: Wed, 27 Jun 2018 23:21:56 +0200 Subject: [PATCH 013/216] fix typo --- rest_auth/locale/cs/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po index 57291c7..7a7b25f 100644 --- a/rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -87,7 +87,7 @@ msgstr "E-mail není ověřený." #: .\views.py:127 msgid "Successfully logged out." -msgstr "Byli jste úspěšně odhlášení." +msgstr "Byli jste úspěšně odhlášeni." #: .\views.py:175 msgid "Password reset e-mail has been sent." From 53f901b3c887d4f12219aca64bb6b5ea633b0681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Dohnal?= Date: Wed, 27 Jun 2018 23:22:38 +0200 Subject: [PATCH 014/216] refresh .mo file --- rest_auth/locale/cs/LC_MESSAGES/django.mo | Bin 2376 -> 2488 bytes rest_auth/locale/cs/LC_MESSAGES/django.po | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.mo b/rest_auth/locale/cs/LC_MESSAGES/django.mo index 38857f9a881619301ecd04a57fd1aa8bd0febe2f..3dd71df01d655839aef82270b73b43c1d635de87 100644 GIT binary patch delta 345 zcmX>hv_p8pnfmLD3=Fqe7#Q>!7#KFOF)+vj=|@0X4oEYxLuf@HEdk^^0BIc{9SNj` zfpi;?RtD0ufV3fy-Up=Zf%FF;Ed`_vI2agYfwVV})&|ma(=EpcGdcs#l@wm#gkcCy_k%QCI_+}u?{=DFgYi& zOu;2TBQG&W!KN$`#MMgya~;xi6Ekx_2HJ7?04**}Oi$GfNlnbPQt;Dv+^otb&%~Iy J*^PsV5dbjTOX2_k delta 251 zcmdlXd_ri#nff$F28LTK3=H}V3=EEJ3=Hx>x)4aq0qKcQdIOM_0P@cRX&oT_0!Rx3 zX;F3t24x_v38W2yv@ejh2h#OGS_(+-2hy@Y`WBGZ2GT!(G)TP)2Lpo)koMqU&;whX z3KUQR3QPskAcyP#(jbj5fV3TuX5(aFU;@&vn=2VhnZ>z+QVa5nN_2gT(=$_aol4V- zbwl#46efGKdNCQAPM*$sM1adDF)zI|F+Ei`BsDSDN@4RfHhCtd!)rHh<6vS007B|1 Ap8x;= diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/rest_auth/locale/cs/LC_MESSAGES/django.po index 7a7b25f..eb8c60c 100644 --- a/rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/rest_auth/locale/cs/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Tivix/django-rest-auth\n" "Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n" "POT-Creation-Date: 2018-06-27 23:05+0200\n" -"PO-Revision-Date: 2018-06-27 23:15+0200\n" +"PO-Revision-Date: 2018-06-27 23:22+0200\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 033ee8f483e7c552ed5382120dbd00481fe80ac1 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 21 Aug 2018 21:12:28 -0700 Subject: [PATCH 015/216] Remove deprecated EZ setup --- setup.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 2c9dad4..66c4c04 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,8 @@ #!/usr/bin/env python -try: - from setuptools import setup, find_packages -except ImportError: - from ez_setup import use_setuptools - use_setuptools() - from setuptools import setup, find_packages - - import os +from setuptools import setup, find_packages + here = os.path.dirname(os.path.abspath(__file__)) f = open(os.path.join(here, 'README.rst')) From f0941b4cc2d23e81c75660a9b032dbab785456ff Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 21 Aug 2018 21:16:52 -0700 Subject: [PATCH 016/216] Merge tools configs into setup.cfg --- flake8 | 4 ---- .coveragerc => setup.cfg | 15 ++++++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 flake8 rename .coveragerc => setup.cfg (77%) diff --git a/flake8 b/flake8 deleted file mode 100644 index 401fdf4..0000000 --- a/flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-line-length = 120 -exclude = docs/*,demo/* -ignore = F403 \ No newline at end of file diff --git a/.coveragerc b/setup.cfg similarity index 77% rename from .coveragerc rename to setup.cfg index 70d6d0d..3ba7986 100644 --- a/.coveragerc +++ b/setup.cfg @@ -1,8 +1,13 @@ -# .coveragerc to control coverage.py -[run] +[flake8] +max-line-length = 120 +exclude = docs/*,demo/* +ignore = F403 + + +[coverage:run] omit=*site-packages*,*distutils*,*migrations* -[report] +[coverage:report] # Regexes for lines to exclude from consideration exclude_lines = # Have to re-enable the standard pragma @@ -22,5 +27,5 @@ exclude_lines = ignore_errors = True -[html] -directory = coverage_html \ No newline at end of file +[coverage:html] +directory = coverage_html From 691c73d5569834d82c7e1df03e74bbdbc089ade3 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 21 Aug 2018 21:18:41 -0700 Subject: [PATCH 017/216] Update .gitignore from GH --- .gitignore | 77 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 7d8d699..894a44c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,35 @@ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] +*$py.class # C extensions *.so # Distribution / packaging .Python -env/ -bin/ build/ develop-eggs/ dist/ +downloads/ eggs/ +.eggs/ lib/ lib64/ parts/ sdist/ var/ +wheels/ *.egg-info/ .installed.cfg *.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec # Installer logs pip-log.txt @@ -30,28 +39,66 @@ pip-delete-this-directory.txt htmlcov/ .tox/ .coverage +.coverage.* .cache nosetests.xml coverage.xml -coverage_html +*.cover +.hypothesis/ +.pytest_cache/ -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Rope -.ropeproject +# Translations +*.mo +*.pot # Django stuff: *.log -*.pot +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy # Sphinx documentation docs/_build/ -.DS_Store -db.sqlite3 +# PyBuilder +target/ -# IntelliJ IDE files -.idea +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ From 4b07c3ca92d64927d0b8ea454bc44ef0d9691000 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 21 Aug 2018 21:29:15 -0700 Subject: [PATCH 018/216] Add wheel & metdata config --- setup.cfg | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/setup.cfg b/setup.cfg index 3ba7986..8d915a7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,11 @@ +[bdist_wheel] +universal = 1 + + +[metadata] +license_file = LICENSE + + [flake8] max-line-length = 120 exclude = docs/*,demo/* From 5d318b3a4ba3572755a631a272594f2342ab04ae Mon Sep 17 00:00:00 2001 From: erdtsksn Date: Sat, 13 Oct 2018 20:15:09 +0300 Subject: [PATCH 019/216] feat: Add Turkish(tr) translation oth: There is no .mo file because there is a .gitignore entry for that. --- rest_auth/locale/tr/LC_MESSAGES/django.po | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 rest_auth/locale/tr/LC_MESSAGES/django.po diff --git a/rest_auth/locale/tr/LC_MESSAGES/django.po b/rest_auth/locale/tr/LC_MESSAGES/django.po new file mode 100644 index 0000000..f02af80 --- /dev/null +++ b/rest_auth/locale/tr/LC_MESSAGES/django.po @@ -0,0 +1,95 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-03-05 21:56-0800\n" +"PO-Revision-Date: 2018-10-13 19:37+0300\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: \n" +"Language-Team: \n" +"X-Generator: Poedit 2.2\n" + +#: registration/serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "“View” tanımlanmadı, “context” değişkeni olarak tanımla" + +#: registration/serializers.py:72 +msgid "Define adapter_class in view" +msgstr "“view” içerisinde “adapter_class” tanımla" + +#: registration/serializers.py:91 +msgid "Define callback_url in view" +msgstr "“view” içerisinde “callback_url” tanımla" + +#: registration/serializers.py:95 +msgid "Define client_class in view" +msgstr "“view” içerisinde “client_class” tanımla" + +#: registration/serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "Geçersiz girdi. “access_token” veya “code” gerekli." + +#: registration/serializers.py:125 +msgid "Incorrect value" +msgstr "Geçersiz değer" + +#: registration/serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "Bu e-posta adresi ile bir kullanıcı zaten kayıt olmuştu." + +#: registration/serializers.py:193 +msgid "The two password fields didn't match." +msgstr "İki şifre alanı eşleşmiyor." + +#: registration/views.py:98 +msgid "ok" +msgstr "tamam" + +#: serializers.py:33 +msgid "Must include \"email\" and \"password\"." +msgstr "\"email\" ve \"password\" içermelidir." + +#: serializers.py:44 +msgid "Must include \"username\" and \"password\"." +msgstr "“username\" und \"password\" içermelidir." + +#: serializers.py:57 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Ya ”username\" yada \"email\" ve \"password\" içermelidir." + +#: serializers.py:98 +msgid "User account is disabled." +msgstr "Kullanıcı hesap pasiftir." + +#: serializers.py:101 +msgid "Unable to log in with provided credentials." +msgstr "Sağlanan kimlik bilgileri ile giriş yapılamıyor." + +#: serializers.py:110 +msgid "E-mail is not verified." +msgstr "E-posta adresi doğrulanmadı." + +#: views.py:127 +msgid "Successfully logged out." +msgstr "Başarılı bir şekilde çıkış yapıldı." + +#: views.py:175 +msgid "Password reset e-mail has been sent." +msgstr "Şifre sıfırlama e-postası gönderildi." + +#: views.py:201 +msgid "Password has been reset with the new password." +msgstr "Yeni şifre ile şifre sıfırlandı." + +#: views.py:223 +msgid "New password has been saved." +msgstr "Yeni şifre kaydedildi." From f5fe62ce913f52a41fec7c0aef1b50a2d422e523 Mon Sep 17 00:00:00 2001 From: Kurt Neufeld Date: Thu, 25 Oct 2018 11:28:24 -0600 Subject: [PATCH 020/216] expand JWT acronym in docs --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index fa512c5..647a131 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -205,8 +205,8 @@ You can also use the following views to check all social accounts attached to th ] -JWT Support (optional) ----------------------- +JSON Web Token (JWT) Support (optional) +--------------------------------------- By default ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps: From ca39ba7ea99c7c6716fc0da9695da2a839808525 Mon Sep 17 00:00:00 2001 From: Magnun Leno Date: Sat, 27 Oct 2018 02:14:25 -0300 Subject: [PATCH 021/216] Adds django-allauth to dev-requirements.txt --- dev-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-requirements.txt b/dev-requirements.txt index b0a8d61..0a2a9e4 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,4 @@ --editable . responses>=0.5.0 djangorestframework-jwt +django-allauth From 9913f8eb03ec42bdae16100744b227f3ea52d2a6 Mon Sep 17 00:00:00 2001 From: yihuang Date: Sun, 28 Oct 2018 11:46:19 +0800 Subject: [PATCH 022/216] add translation for Chinese --- .../locale/zh_Hans/LC_MESSAGES/django.mo | Bin 0 -> 2284 bytes .../locale/zh_Hans/LC_MESSAGES/django.po | 104 ++++++++++++++++++ .../locale/zh_Hant/LC_MESSAGES/django.mo | Bin 0 -> 414 bytes .../locale/zh_Hant/LC_MESSAGES/django.po | 103 +++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo create mode 100644 rest_auth/locale/zh_Hans/LC_MESSAGES/django.po create mode 100644 rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo create mode 100644 rest_auth/locale/zh_Hant/LC_MESSAGES/django.po diff --git a/rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo b/rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f6f549e1eb09745256ceda6da662ebc745c57fe GIT binary patch literal 2284 zcmb7^TWl0n7{`x_w^c;(9&aZVtO?AzOOTW;AQcK}Y)bRf7r4F=NYUQvA)N832Xm7_`&lBxCZn66GWG)4Sf&7*+&k#6viOb_|1Jk&#kU{7H^f`zi! zVl2wxNvy}Q9>ap0pnf_(w2VE0Re2sR|G6Ke8bc&EaL=L#Xd!Fwk=*UGs@b5`hURch*UVa%Cxol^gjt6vx(pavw3p5>n24lp_39ct zspvJr=)%BAbkH2(WGv4_tI3l?n^9Px!JGdzVLOB4SB0xvW@Y@Gpr)OeF$zFKq6KrP ztqkhmy35g1fq5`pxfdfOY@Kpo)*jYoTe~qrN|UC*wF9p)-qx_`orbNAd}rhK9ZlO> zL)&H2vR$RciR+s3wikDlb}Pn1ZQI(FP53w{6=kzyDdz|5Uyp%cvmgw>x7oj&5e8ahE*%Ep%zAF+!JxB zv`dkQ@#costsRu?y5{DMh90);_=b5KB-zr`(par58jgfEQ5Q@E+LuJe)Q~rlhS1G= zuJ#BUleNC1eT!08wWEZ(rL8pLd((6?9^-Xgx*KXUJX;vb7RydJF>WRU(ODm@=cT{v zBlV$O^W{iQ>2QM0+HO=}DYk`BuHcdIS|r5^>GQ<{Q~9Yc{Zp6x&r<&MSB0~axyu** zgG0Zj4nRHapSnm#oXvdUPmN`-et6R*Q#PP`X5L`oMRQyIg3E@Lg6B?66eorX>HZ+* z^-uhP^Tnel3h6ZDg||!Y&@sAPa>vvD+<-qmSscGgJ4&|su@C&z49lgD`WFuPLj(TE zWckDQKOU-HEVSV!oB6BaKbrkMGgS6V|0?%KjX!V&Ey!k4*~~-`JNWZOa*;`Q1XyJam^q6hWunR=W?Hq7lMXS z`9ZvF=1Bfz#vd7CxlhmJE{|qs=kiA{=7vYI*H6MIJ2#%|Pm_b^$BTo**_ksqXy%`vMOy41 DJlZ(X literal 0 HcmV?d00001 diff --git a/rest_auth/locale/zh_Hans/LC_MESSAGES/django.po b/rest_auth/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 0000000..1c7ff82 --- /dev/null +++ b/rest_auth/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-28 11:41+0800\n" +"PO-Revision-Date: 2018-10-28 11:45+0806\n" +"Last-Translator: b' '\n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Translated-Using: django-rosetta 0.9.0\n" + +#: registration/serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "View未定义,请通过context变量传入" + +#: registration/serializers.py:72 +msgid "Define adapter_class in view" +msgstr "请在View中定义adapter_class" + +#: registration/serializers.py:91 +msgid "Define callback_url in view" +msgstr "请在view中定义callback_url" + +#: registration/serializers.py:95 +msgid "Define client_class in view" +msgstr "请在view中定义client_class" + +#: registration/serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "输入错误。access_token或code是必填项。" + +#: registration/serializers.py:125 +msgid "Incorrect value" +msgstr "错误的值" + +#: registration/serializers.py:139 +msgid "User is already registered with this e-mail address." +msgstr "该邮箱地址已被注册。" + +#: registration/serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "该邮箱地址已被注册。" + +#: registration/serializers.py:193 +msgid "The two password fields didn't match." +msgstr "两次输入的密码不相同" + +#: registration/views.py:51 +msgid "Verification e-mail sent." +msgstr "验证邮件已发送。" + +#: registration/views.py:98 +msgid "ok" +msgstr "好的" + +#: serializers.py:33 +msgid "Must include \"email\" and \"password\"." +msgstr "比如包含\"email\"和\"password\"。" + +#: serializers.py:44 +msgid "Must include \"username\" and \"password\"." +msgstr "比如包含\"username\"和\"password\"。" + +#: serializers.py:57 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "比如包含\"username\",\"email\",\"password\"其中一个。" + +#: serializers.py:98 +msgid "User account is disabled." +msgstr "用户账号已被禁用。" + +#: serializers.py:101 +msgid "Unable to log in with provided credentials." +msgstr "无法使用提供的信息登录。" + +#: serializers.py:110 +msgid "E-mail is not verified." +msgstr "邮箱未验证。" + +#: views.py:127 +msgid "Successfully logged out." +msgstr "已成功登出。" + +#: views.py:175 +msgid "Password reset e-mail has been sent." +msgstr "密码重置邮件已发送。" + +#: views.py:201 +msgid "Password has been reset with the new password." +msgstr "密码重置成功。" + +#: views.py:223 +msgid "New password has been saved." +msgstr "新密码已设置成功。" diff --git a/rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo b/rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..20e5d8dbda6a94eed8fbbe7c2b79f0f6fab611c8 GIT binary patch literal 414 zcmYL^Pfx=j9ENA~)T3t)9K6lnY!?reZDzRA+1P*Sx+QwU6>Cig4KSl0#INUPk*aZT z@&pJE@bYzf@;R_MvYc7YEytD%OCR4-+0AP^_RfEDC13g0KvcnoE8R$eQBD^3WJ%G6 z7ON;roq~5#8Ax>9RB*emHIxz~C(lY)D9(&M1OYP~qp|Dx;JGmNk>}wnZ|M52Yegvd zThm|u=RHtTK$1Z~&|QX;X!w|=)QOokP%0*L%ZyYQh3hy*DM=`r(u73uoCHBZSF0PV zih9p#4kc$hjAD{5*L~$_9M9WkBvpNIY}F)6=;43f$aNM{7%uE{AD!)O_`A96TGogO z+P*NQxtXoY5d4GJ*Lvm(sMyM?5j95sQ)8UG-7D5YDAi75B)Xrao_Q1WJDs@`XYdX3 CzjEdP literal 0 HcmV?d00001 diff --git a/rest_auth/locale/zh_Hant/LC_MESSAGES/django.po b/rest_auth/locale/zh_Hant/LC_MESSAGES/django.po new file mode 100644 index 0000000..b99489a --- /dev/null +++ b/rest_auth/locale/zh_Hant/LC_MESSAGES/django.po @@ -0,0 +1,103 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-28 11:41+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: registration/serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "" + +#: registration/serializers.py:72 +msgid "Define adapter_class in view" +msgstr "" + +#: registration/serializers.py:91 +msgid "Define callback_url in view" +msgstr "" + +#: registration/serializers.py:95 +msgid "Define client_class in view" +msgstr "" + +#: registration/serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "" + +#: registration/serializers.py:125 +msgid "Incorrect value" +msgstr "" + +#: registration/serializers.py:139 +msgid "User is already registered with this e-mail address." +msgstr "" + +#: registration/serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "" + +#: registration/serializers.py:193 +msgid "The two password fields didn't match." +msgstr "" + +#: registration/views.py:51 +msgid "Verification e-mail sent." +msgstr "" + +#: registration/views.py:98 +msgid "ok" +msgstr "" + +#: serializers.py:33 +msgid "Must include \"email\" and \"password\"." +msgstr "" + +#: serializers.py:44 +msgid "Must include \"username\" and \"password\"." +msgstr "" + +#: serializers.py:57 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "" + +#: serializers.py:98 +msgid "User account is disabled." +msgstr "" + +#: serializers.py:101 +msgid "Unable to log in with provided credentials." +msgstr "" + +#: serializers.py:110 +msgid "E-mail is not verified." +msgstr "" + +#: views.py:127 +msgid "Successfully logged out." +msgstr "" + +#: views.py:175 +msgid "Password reset e-mail has been sent." +msgstr "" + +#: views.py:201 +msgid "Password has been reset with the new password." +msgstr "" + +#: views.py:223 +msgid "New password has been saved." +msgstr "" From c437ca22ff2e37838f78253c5320c89f8282f5ba Mon Sep 17 00:00:00 2001 From: Oskar Persson Date: Fri, 9 Nov 2018 15:58:09 +0100 Subject: [PATCH 023/216] Translate msg when providing incorrect old password --- rest_auth/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index 2ea6550..b645231 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -256,7 +256,8 @@ class PasswordChangeSerializer(serializers.Serializer): ) if all(invalid_password_conditions): - raise serializers.ValidationError('Invalid password') + err_msg = _("Your old password was entered incorrectly. Please enter it again.") + raise serializers.ValidationError(err_msg) return value def validate(self, attrs): From 25b94db0cc4022df2bd80240dc10e06c28e09ac1 Mon Sep 17 00:00:00 2001 From: vthorey Date: Mon, 12 Nov 2018 16:49:36 +0100 Subject: [PATCH 024/216] Update installation.rst --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index fa512c5..e1a07bf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -131,7 +131,7 @@ Twitter If you are using Twitter for your social authentication, it is a bit different since Twitter uses OAuth 1.0. -3. Create new view as a subclass of ``rest_auth.views.LoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute: +3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute: .. code-block:: python From e891a76c3f7426a047afa6e2cb988eeecc699612 Mon Sep 17 00:00:00 2001 From: Valentino Date: Mon, 12 Nov 2018 16:58:07 +0100 Subject: [PATCH 025/216] Add example of github API in installation doc. --- docs/installation.rst | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/installation.rst b/docs/installation.rst index e1a07bf..1bd63ea 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -154,6 +154,34 @@ If you are using Twitter for your social authentication, it is a bit different s .. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details. + +GitHub +###### + +If you are using GitHub for your social authentication, it uses code and not AccessToken directly. + +3. Create new view as a subclass of ``rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes: + +.. code-block:: python + + from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter + from allauth.socialaccount.providers.oauth2.client import OAuth2Client + from rest_auth.registration.views import SocialLoginView + + class GithubLogin(SocialLoginView): + adapter_class = GitHubOAuth2Adapter + callback_url = CALLBACK_URL_YOU_SET_ON_GITHUB + client_class = OAuth2Client + +4. Create url for GitHubLogin view: + +.. code-block:: python + + urlpatterns += [ + ..., + url(r'^rest-auth/github/$', GitHubLogin.as_view(), name='github_login') + ] + Additional Social Connect Views ############################### @@ -162,6 +190,9 @@ If you want to allow connecting existing accounts in addition to login, you can .. code-block:: python from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter + from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter + from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter + from allauth.socialaccount.providers.oauth2.client import OAuth2Client from rest_auth.registration.views import SocialConnectView from rest_auth.social_serializers import TwitterConnectSerializer @@ -172,6 +203,12 @@ If you want to allow connecting existing accounts in addition to login, you can serializer_class = TwitterConnectSerializer adapter_class = TwitterOAuthAdapter + class GithubConnect(SocialConnectView): + adapter_class = GitHubOAuth2Adapter + callback_url = CALLBACK_URL_YOU_SET_ON_GITHUB + client_class = OAuth2Client + + In urls.py: .. code-block:: python @@ -180,6 +217,7 @@ In urls.py: ..., url(r'^rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect') url(r'^rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect') + url(r'^rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect') ] You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts: From a3d38f4c59a9b9dbe1ca8c3408b103f307d47e81 Mon Sep 17 00:00:00 2001 From: Jasper Wan Date: Sun, 3 Feb 2019 11:42:24 +0800 Subject: [PATCH 026/216] disable django_logout if REST_SESSION_LOGIN is False --- rest_auth/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 8efcdd5..3c1a164 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -121,8 +121,8 @@ class LogoutView(APIView): request.user.auth_token.delete() except (AttributeError, ObjectDoesNotExist): pass - - django_logout(request) + if getattr(settings, 'REST_SESSION_LOGIN', True): + django_logout(request) return Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) From 64b5572172ea664dd2354a78787a06d0a5f39943 Mon Sep 17 00:00:00 2001 From: Jeongsoo Park Date: Wed, 20 Mar 2019 17:44:18 +0900 Subject: [PATCH 027/216] add a korean translation --- rest_auth/locale/ko/LC_MESSAGES/django.po | 99 +++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 rest_auth/locale/ko/LC_MESSAGES/django.po diff --git a/rest_auth/locale/ko/LC_MESSAGES/django.po b/rest_auth/locale/ko/LC_MESSAGES/django.po new file mode 100644 index 0000000..8eb3bef --- /dev/null +++ b/rest_auth/locale/ko/LC_MESSAGES/django.po @@ -0,0 +1,99 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-03-05 21:56-0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Jeonsgoo Park \n" +"Language-Team: LANGUAGE \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: registration/serializers.py:53 +msgid "View is not defined, pass it as a context variable" +msgstr "View가 정의되지 않았습니다. 컨텍스트 변수에 포함해주세요" + +#: registration/serializers.py:58 +msgid "Define adapter_class in view" +msgstr "view에 adapter_class를 정의하세요" + +#: registration/serializers.py:77 +msgid "Define callback_url in view" +msgstr "view에 callback_url을 정의하세요" + +#: registration/serializers.py:81 +msgid "Define client_class in view" +msgstr "view에 client_class를 정의하세요" + +#: registration/serializers.py:102 +msgid "Incorrect input. access_token or code is required." +msgstr "올바르지 않은 입력입니다. access_token이나 code가 필요합니다." + +#: registration/serializers.py:111 +msgid "Incorrect value" +msgstr "올바르지 않은 값" + +#: registration/serializers.py:140 +msgid "A user is already registered with this e-mail address." +msgstr "이미 이 이메일 주소로 등록된 사용자가 있습니다." + +#: registration/serializers.py:148 +msgid "The two password fields didn't match." +msgstr "두 개의 패스워드 필드가 서로 맞지 않습니다." + +#: registration/views.py:44 +msgid "Verification e-mail sent." +msgstr "확인 이메일을 발송했습니다." + +#: registration/views.py:91 +msgid "ok" +msgstr "ok" + +#: serializers.py:30 +msgid "Must include \"email\" and \"password\"." +msgstr "\"email\"과 \"password\"를 반드시 포함해야 합니다." + +#: serializers.py:41 +msgid "Must include \"username\" and \"password\"." +msgstr "\"username\"과 \"password\"를 반드시 포함해야 합니다." + +#: serializers.py:54 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "\"username\"이나 \"email\", 그리고 \"password\"를 반드시 포함해야 합니다." + +#: serializers.py:95 +msgid "User account is disabled." +msgstr "사용자 계정이 비활성화 되어있습니다." + +#: serializers.py:98 +msgid "Unable to log in with provided credentials." +msgstr "주어진 자격 증명으로 로그인이 불가능합니다." + +#: serializers.py:107 +msgid "E-mail is not verified." +msgstr "이메일 주소가 확인되지 않았습니다." + +#: views.py:126 +msgid "Successfully logged out." +msgstr "로그아웃되었습니다." + +#: views.py:174 +msgid "Password reset e-mail has been sent." +msgstr "패스워드 초기화 이메일이 발송되었습니다." + +#: views.py:200 +msgid "Password has been reset with the new password." +msgstr "새로운 패스워드로 패스워드가 초기화 되었습니다." + +#: views.py:222 +msgid "New password has been saved." +msgstr "새로운 패스워드가 저장되었습니다." From 11e877ba50771892782fb9a2213812a03a259030 Mon Sep 17 00:00:00 2001 From: Jeongsoo Park Date: Wed, 20 Mar 2019 17:51:09 +0900 Subject: [PATCH 028/216] add a korean translation mo file --- rest_auth/locale/ko/LC_MESSAGES/django.mo | Bin 0 -> 2562 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 rest_auth/locale/ko/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/ko/LC_MESSAGES/django.mo b/rest_auth/locale/ko/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..79c07cf696cab7db9cbcda362aadac3c3580eefc GIT binary patch literal 2562 zcmbu9-)|IE6vszJ(e*b-#Hh)!QNh5hK-Azu36(BbZM(I!B>K|a&fIRt&d#j!qm>5} z0$Xef#tL27!fq{*0yRx2w(1)D;DZmo`rv~vMt$75`#0eC&hB=%w8R)Ex%-*fdw!pD z?;o2sWEDJHu%5&E8S8m0^B(-*`4fBt{0o%(TklnrXTjI2d=GpY-zjhpI0`-v7Qq+6 zU%+i(8GIAma$m(x0*vC@1f|?%a4Yx|_!9U#xC6WmJ_GL9P+=UDe)>R|RL+6zh%E~q z!uQ|zE6R58Eo+DC2J0s3hm3Q&7Ns+ z%ezA_UU33mp>rti6(rm}!ng=Us--{B{G(^$o*+bkS+ab-?xlF;~ANd9X zZ&Vp(rq7iQ-<8^$=|i%K%Ve5}SvobP5&4Mi=uOc(gk)VTmg4^+$5A5`u&FMNfbQm@ zlaEl%Aq_H@`Z+Ri*|3bcs~Smt1GVN}tqYv22JHs%id3~jb)%?nR5|L0r5f-}^EjDy zGKsF*D526b$jKYA>(QXprtXq%=+-umQq0o^qe`#E`b`MhQdjmcoQSkz4;wlxX{a^a z7|g^-^vXFxXKdd>sih@XDkHIDVJ9`_8MalMBsUE27{*1)%6{wNNa;JnkjU@|ZT-ACIJosn*ywjEFHaFd3v zzU3!fwa1Q8q${Cz^I=2ksIAQ7F?v7V(yewR)YcYyI}z(>+wno7GahMYuBY}m%yLcU z*-nh!;kM-_ZJWB7GerCGAJa^JFexV~s@bUnP_dFeOLDb`vs8@QTRM;Q%82&2w;wc( zsO=={GBFymBOPrW@p=Ngqq`!9WU>|S!nLgnGZvh=8dc<} z7Z)d1UkAY~?960EAy>}kM5ZV%O|A$wUJaslrL9oKvb- zKxuKg;f|3x1Pi&~d|sT%Q~C4xa`r|!yCky9)L^oHm;68NYUtHSc2ep4VsLG~v^evh zBNC^^Fbv|-5|z*15aUKDBo9iwP=0uaH|64O)p-#I-{3^{B`%hbk4vg<=@ocVnngFh1MR+?8WQrNvBmK9Ix@netR#WNy{U z0Q;*BSY@W`2UMP!O6KJYjb)ejX{9Uj+{wh(IRhkqyip$g3~elr7b#dgA;!?XiH31R KhL!V*%l03*mkKNZ literal 0 HcmV?d00001 From d2cd31a5603c0a65b05cc9d817542d3349fc0c8d Mon Sep 17 00:00:00 2001 From: Jeongsoo Park Date: Wed, 20 Mar 2019 17:52:51 +0900 Subject: [PATCH 029/216] update revision date --- rest_auth/locale/ko/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_auth/locale/ko/LC_MESSAGES/django.po b/rest_auth/locale/ko/LC_MESSAGES/django.po index 8eb3bef..777a2bf 100644 --- a/rest_auth/locale/ko/LC_MESSAGES/django.po +++ b/rest_auth/locale/ko/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-03-05 21:56-0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2018-03-20 17:52+0900\n" "Last-Translator: Jeonsgoo Park \n" "Language-Team: LANGUAGE \n" "Language: ko\n" From f39d93042e89912e28d73c4d9e82f60ff0bfe5f4 Mon Sep 17 00:00:00 2001 From: Gaurav Sheni Date: Tue, 26 Mar 2019 11:07:27 -0400 Subject: [PATCH 030/216] Update installation.rst --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index fa512c5..b9247fa 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -210,8 +210,8 @@ JWT Support (optional) By default ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps: -1. Install `django-rest-framework-jwt `_ - - ``django-rest-framework-jwt`` is currently the only supported JWT library. +1. Install `djangorestframework-jwt `_ + - ``djangorestframework-jwt`` is currently the only supported JWT library. 2. The ``JWT_PAYLOAD_HANDLER`` and ``JWT_ENCODE_HANDLER`` settings are imported from the ``django-rest-framework-jwt`` settings object. - Refer to `the library's documentation `_ for information on using different encoders. From c7ff94ced701a9134630682a1ace7a279bddcbc5 Mon Sep 17 00:00:00 2001 From: mario Date: Mon, 1 Apr 2019 07:51:51 +0200 Subject: [PATCH 031/216] feat: prep for new release (0.9.4) --- demo/requirements.pip | 2 +- docs/changelog.rst | 8 ++++++++ docs/conf.py | 4 ++-- setup.py | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index 7480482..a74495b 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ django>=1.9.0 -django-rest-auth==0.9.3 +django-rest-auth==0.9.4 djangorestframework>=3.7.0 django-allauth>=0.24.1 six==1.9.0 diff --git a/docs/changelog.rst b/docs/changelog.rst index fa79dbc..65fa7b7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,14 @@ Changelog ========= +0.9.4 +----- +- Compatibility fixes (#437, #506) +- JWT auth cookie fix (#345) +- config & packaging fixes +- updated docs +- added new translations (Czech, Chinese, Turkish, Korean) + 0.9.3 ----- - added social connect views diff --git a/docs/conf.py b/docs/conf.py index c8ecb3b..0e988c8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ copyright = u'2018, Tivix Inc.' # built documents. # # The short X.Y version. -version = '0.9.3' +version = '0.9.4' # The full version, including alpha/beta/rc tags. -release = '0.9.3' +release = '0.9.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 66c4c04..f71f293 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='django-rest-auth', - version='0.9.3', + version='0.9.4', author='Sumit Chachra', author_email='chachra@tivix.com', url='http://github.com/Tivix/django-rest-auth', From 998b2b1fbc883f929cf23d50b867b68913ed6dfa Mon Sep 17 00:00:00 2001 From: mario Date: Mon, 1 Apr 2019 09:51:08 +0200 Subject: [PATCH 032/216] feat: prep for new release (0.9.5) --- demo/requirements.pip | 2 +- docs/changelog.rst | 4 ++++ docs/conf.py | 4 ++-- setup.py | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index a74495b..40b4820 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ django>=1.9.0 -django-rest-auth==0.9.4 +django-rest-auth==0.9.5 djangorestframework>=3.7.0 django-allauth>=0.24.1 six==1.9.0 diff --git a/docs/changelog.rst b/docs/changelog.rst index 65fa7b7..e7beb5d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,10 @@ Changelog ========= +0.9.5 +----- +- fixed package distribution issue + 0.9.4 ----- - Compatibility fixes (#437, #506) diff --git a/docs/conf.py b/docs/conf.py index 0e988c8..1c825cc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ copyright = u'2018, Tivix Inc.' # built documents. # # The short X.Y version. -version = '0.9.4' +version = '0.9.5' # The full version, including alpha/beta/rc tags. -release = '0.9.4' +release = '0.9.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index f71f293..675b99d 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='django-rest-auth', - version='0.9.4', + version='0.9.5', author='Sumit Chachra', author_email='chachra@tivix.com', url='http://github.com/Tivix/django-rest-auth', From 07d2bd5c5629e5bfff6ecdd605c29027d7380559 Mon Sep 17 00:00:00 2001 From: Bruno Barreto Freitas Date: Tue, 16 Apr 2019 10:27:43 -0300 Subject: [PATCH 033/216] Brazilian Portuguese Translation - django.po file --- rest_auth/locale/pt_BR/LC_MESSAGES/django.po | 99 ++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 rest_auth/locale/pt_BR/LC_MESSAGES/django.po diff --git a/rest_auth/locale/pt_BR/LC_MESSAGES/django.po b/rest_auth/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..d816a54 --- /dev/null +++ b/rest_auth/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,99 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Bruno Barreto Freitas , 2019. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-04-16 09:48-0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Bruno Barreto Freitas \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: registration/serializers.py:53 +msgid "View is not defined, pass it as a context variable" +msgstr "\"View\" não está definida, passe-a como uma variável de contexto" + +#: registration/serializers.py:58 +msgid "Define adapter_class in view" +msgstr "Defina \"adapter_class\" na view" + +#: registration/serializers.py:77 +msgid "Define callback_url in view" +msgstr "Defina \"callback_url\" na view" + +#: registration/serializers.py:81 +msgid "Define client_class in view" +msgstr "Defina \"client_class\" na view" + +#: registration/serializers.py:102 +msgid "Incorrect input. access_token or code is required." +msgstr "Entrada incorreta. \"access_token\" ou \"code\" são obrigatórios." + +#: registration/serializers.py:111 +msgid "Incorrect value" +msgstr "Valor incorreto" + +#: registration/serializers.py:140 +msgid "A user is already registered with this e-mail address." +msgstr "Já existe um usuário cadastrado com este endereço de e-mail." + +#: registration/serializers.py:148 +msgid "The two password fields didn't match." +msgstr "Os dois campos de senha não correspondem." + +#: registration/views.py:44 +msgid "Verification e-mail sent." +msgstr "E-mail de verificação enviado." + +#: registration/views.py:91 +msgid "ok" +msgstr "Ok" + +#: serializers.py:30 +msgid "Must include \"email\" and \"password\"." +msgstr "Deve-se incluir \"email\" e \"password\"." + +#: serializers.py:41 +msgid "Must include \"username\" and \"password\"." +msgstr "Deve-se incluir \"username\" e \"password\"." + +#: serializers.py:54 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Deve-se incluir \"username\" ou \"email\" e \"password\"." + +#: serializers.py:95 +msgid "User account is disabled." +msgstr "Conta de usuário está desativada" + +#: serializers.py:98 +msgid "Unable to log in with provided credentials." +msgstr "Não foi possível realizar o login com as credenciais fornecidas." + +#: serializers.py:107 +msgid "E-mail is not verified." +msgstr "E-mail não foi verificado." + +#: views.py:126 +msgid "Successfully logged out." +msgstr "Logout realizado com sucesso." + +#: views.py:174 +msgid "Password reset e-mail has been sent." +msgstr "E-mail de redefinição de senha foi enviado." + +#: views.py:200 +msgid "Password has been reset with the new password." +msgstr "Senha foi redefinida com a nova senha." + +#: views.py:222 +msgid "New password has been saved." +msgstr "Nova senha foi salva com sucesso." From 596cbee153b7eeaeebcd66a6a56088d842a4822a Mon Sep 17 00:00:00 2001 From: Steve Recio Date: Fri, 10 Jan 2020 17:47:54 -0500 Subject: [PATCH 034/216] add DRF throttle scopes to relevant rest auth views --- rest_auth/registration/views.py | 1 + rest_auth/views.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 0e0ab0d..1c28c16 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -40,6 +40,7 @@ class RegisterView(CreateAPIView): serializer_class = RegisterSerializer permission_classes = register_permission_classes() token_model = TokenModel + throttle_scope = 'rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): diff --git a/rest_auth/views.py b/rest_auth/views.py index 0a0a982..bbeab8a 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -43,6 +43,7 @@ class LoginView(GenericAPIView): permission_classes = (AllowAny,) serializer_class = LoginSerializer token_model = TokenModel + throttle_scope = 'rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): @@ -114,6 +115,7 @@ class LogoutView(APIView): Accepts/Returns nothing. """ permission_classes = (AllowAny,) + throttle_scope = 'rest_auth' def get(self, request, *args, **kwargs): if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False): @@ -178,6 +180,7 @@ class PasswordResetView(GenericAPIView): """ serializer_class = PasswordResetSerializer permission_classes = (AllowAny,) + throttle_scope = 'rest_auth' def post(self, request, *args, **kwargs): # Create a serializer with request.data @@ -203,6 +206,7 @@ class PasswordResetConfirmView(GenericAPIView): """ serializer_class = PasswordResetConfirmSerializer permission_classes = (AllowAny,) + throttle_scope = 'rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): @@ -226,6 +230,7 @@ class PasswordChangeView(GenericAPIView): """ serializer_class = PasswordChangeSerializer permission_classes = (IsAuthenticated,) + throttle_scope = 'rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): From 10eb4be9cd4b403d78cebbaed75e8e42a54e5ce9 Mon Sep 17 00:00:00 2001 From: Steve Recio Date: Mon, 10 Feb 2020 13:02:20 -0500 Subject: [PATCH 035/216] dont delete auth token on logout --- rest_auth/views.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index bbeab8a..6e94a4c 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -129,10 +129,6 @@ class LogoutView(APIView): return self.logout(request) def logout(self, request): - try: - request.user.auth_token.delete() - except (AttributeError, ObjectDoesNotExist): - pass if getattr(settings, 'REST_SESSION_LOGIN', True): django_logout(request) From 92cc9c18ecaccdf509ef5ff2917ff64f7f81dd94 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 17:59:38 -0600 Subject: [PATCH 036/216] Renames project to dj-rest-auth --- .travis.yml | 4 +- AUTHORS | 2 +- LICENSE | 4 +- MANIFEST.in | 2 +- README.rst | 22 ++++----- demo/demo/settings.py | 4 +- demo/demo/urls.py | 4 +- demo/requirements.pip | 2 +- demo/templates/base.html | 12 ++--- demo/templates/home.html | 4 +- {rest_auth => dj_rest_auth}/__init__.py | 0 {rest_auth => dj_rest_auth}/admin.py | 0 {rest_auth => dj_rest_auth}/app_settings.py | 2 +- .../locale/cs/LC_MESSAGES/django.mo | Bin .../locale/cs/LC_MESSAGES/django.po | 0 .../locale/de/LC_MESSAGES/django.mo | Bin .../locale/de/LC_MESSAGES/django.po | 0 .../locale/es/LC_MESSAGES/django.mo | Bin .../locale/es/LC_MESSAGES/django.po | 0 .../locale/fr/LC_MESSAGES/django.mo | Bin .../locale/fr/LC_MESSAGES/django.po | 0 .../locale/ko/LC_MESSAGES/django.mo | Bin .../locale/ko/LC_MESSAGES/django.po | 0 .../locale/pl/LC_MESSAGES/django.mo | Bin .../locale/pl/LC_MESSAGES/django.po | 0 .../locale/pt_BR/LC_MESSAGES/django.po | 0 .../locale/ru/LC_MESSAGES/django.mo | Bin .../locale/ru/LC_MESSAGES/django.po | 0 .../locale/tr/LC_MESSAGES/django.po | 0 .../locale/zh_Hans/LC_MESSAGES/django.mo | Bin .../locale/zh_Hans/LC_MESSAGES/django.po | 0 .../locale/zh_Hant/LC_MESSAGES/django.mo | Bin .../locale/zh_Hant/LC_MESSAGES/django.po | 0 {rest_auth => dj_rest_auth}/models.py | 0 .../registration/__init__.py | 0 .../registration/app_settings.py | 0 .../registration/serializers.py | 0 .../registration/urls.py | 0 .../registration/views.py | 0 {rest_auth => dj_rest_auth}/serializers.py | 0 .../social_serializers.py | 0 {rest_auth => dj_rest_auth}/tests/__init__.py | 0 .../tests/django_urls.py | 0 {rest_auth => dj_rest_auth}/tests/mixins.py | 0 .../tests/requirements.pip | 0 {rest_auth => dj_rest_auth}/tests/settings.py | 0 {rest_auth => dj_rest_auth}/tests/test_api.py | 0 .../tests/test_social.py | 0 {rest_auth => dj_rest_auth}/tests/urls.py | 0 {rest_auth => dj_rest_auth}/urls.py | 0 {rest_auth => dj_rest_auth}/utils.py | 0 {rest_auth => dj_rest_auth}/views.py | 0 docs/api_endpoints.rst | 2 +- docs/changelog.rst | 4 +- docs/configuration.rst | 18 ++++---- docs/faq.rst | 6 +-- docs/installation.rst | 42 +++++++++--------- docs/introduction.rst | 4 +- 58 files changed, 69 insertions(+), 69 deletions(-) rename {rest_auth => dj_rest_auth}/__init__.py (100%) rename {rest_auth => dj_rest_auth}/admin.py (100%) rename {rest_auth => dj_rest_auth}/app_settings.py (97%) rename {rest_auth => dj_rest_auth}/locale/cs/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/cs/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/de/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/de/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/es/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/es/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/fr/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/fr/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/ko/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/ko/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/pl/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/pl/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/pt_BR/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/ru/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/ru/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/tr/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/zh_Hans/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/zh_Hans/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/locale/zh_Hant/LC_MESSAGES/django.mo (100%) rename {rest_auth => dj_rest_auth}/locale/zh_Hant/LC_MESSAGES/django.po (100%) rename {rest_auth => dj_rest_auth}/models.py (100%) rename {rest_auth => dj_rest_auth}/registration/__init__.py (100%) rename {rest_auth => dj_rest_auth}/registration/app_settings.py (100%) rename {rest_auth => dj_rest_auth}/registration/serializers.py (100%) rename {rest_auth => dj_rest_auth}/registration/urls.py (100%) rename {rest_auth => dj_rest_auth}/registration/views.py (100%) rename {rest_auth => dj_rest_auth}/serializers.py (100%) rename {rest_auth => dj_rest_auth}/social_serializers.py (100%) rename {rest_auth => dj_rest_auth}/tests/__init__.py (100%) rename {rest_auth => dj_rest_auth}/tests/django_urls.py (100%) rename {rest_auth => dj_rest_auth}/tests/mixins.py (100%) rename {rest_auth => dj_rest_auth}/tests/requirements.pip (100%) rename {rest_auth => dj_rest_auth}/tests/settings.py (100%) rename {rest_auth => dj_rest_auth}/tests/test_api.py (100%) rename {rest_auth => dj_rest_auth}/tests/test_social.py (100%) rename {rest_auth => dj_rest_auth}/tests/urls.py (100%) rename {rest_auth => dj_rest_auth}/urls.py (100%) rename {rest_auth => dj_rest_auth}/utils.py (100%) rename {rest_auth => dj_rest_auth}/views.py (100%) diff --git a/.travis.yml b/.travis.yml index b059c1e..33f42ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ env: install: - pip install -q Django==$DJANGO djangorestframework==$DRF - pip install coveralls - - pip install -r rest_auth/tests/requirements.pip + - pip install -r dj_rest_auth/tests/requirements.pip script: - - coverage run --source=rest_auth setup.py test + - coverage run --source=dj_rest_auth setup.py test after_success: - coveralls before_script: diff --git a/AUTHORS b/AUTHORS index 21906da..c5ba2ed 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1 @@ -http://github.com/Tivix/django-rest-auth/contributors +http://github.com/iMerica/dj-rest-auth/contributors diff --git a/LICENSE b/LICENSE index 1e3b853..f868a2a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Tivix +Copyright (c) 2014 iMerica Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index 01a589f..c2d4208 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,4 @@ include AUTHORS include LICENSE include MANIFEST.in include README.md -graft rest_auth +graft dj_rest_auth diff --git a/README.rst b/README.rst index ac7f19e..f79511f 100644 --- a/README.rst +++ b/README.rst @@ -1,31 +1,31 @@ -Welcome to django-rest-auth +Welcome to dj-rest-auth =========================== -.. image:: https://travis-ci.org/Tivix/django-rest-auth.svg - :target: https://travis-ci.org/Tivix/django-rest-auth +.. image:: https://travis-ci.org/iMerica/dj-rest-auth.svg + :target: https://travis-ci.org/iMerica/dj-rest-auth -.. image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.svg - :target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master +.. image:: https://coveralls.io/repos/iMerica/dj-rest-auth/badge.svg + :target: https://coveralls.io/r/iMerica/dj-rest-auth?branch=master -.. image:: https://readthedocs.org/projects/django-rest-auth/badge/?version=latest - :target: https://readthedocs.org/projects/django-rest-auth/?badge=latest +.. image:: https://readthedocs.org/projects/dj-rest-auth/badge/?version=latest + :target: https://readthedocs.org/projects/dj-rest-auth/?badge=latest -Django-rest-auth provides a set of REST API endpoints for Authentication and Registration +Django-dj-rest-auth provides a set of REST API endpoints for Authentication and Registration Documentation ------------- -http://django-rest-auth.readthedocs.org/en/latest/ +http://dj-rest-auth.readthedocs.org/en/latest/ Source code ----------- -https://github.com/Tivix/django-rest-auth +https://github.com/iMerica/dj-rest-auth Stack Overflow ----------- -http://stackoverflow.com/questions/tagged/django-rest-auth +http://stackoverflow.com/questions/tagged/dj-rest-auth diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 514a8fb..df6807a 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -37,11 +37,11 @@ INSTALLED_APPS = ( 'rest_framework', 'rest_framework.authtoken', - 'rest_auth', + 'dj_rest_auth', 'allauth', 'allauth.account', - 'rest_auth.registration', + 'dj_rest_auth.registration', 'allauth.socialaccount', 'allauth.socialaccount.providers.facebook', 'rest_framework_swagger', diff --git a/demo/demo/urls.py b/demo/demo/urls.py index af7d38b..787c6e9 100644 --- a/demo/demo/urls.py +++ b/demo/demo/urls.py @@ -35,8 +35,8 @@ urlpatterns = [ TemplateView.as_view(template_name="password_reset_confirm.html"), name='password_reset_confirm'), - url(r'^rest-auth/', include('rest_auth.urls')), - url(r'^rest-auth/registration/', include('rest_auth.registration.urls')), + url(r'^dj-rest-auth/', include('dj_rest_auth.urls')), + url(r'^dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')), url(r'^account/', include('allauth.urls')), url(r'^admin/', admin.site.urls), url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'), diff --git a/demo/requirements.pip b/demo/requirements.pip index 40b4820..c6f5f42 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ django>=1.9.0 -django-rest-auth==0.9.5 +dj-rest-auth==0.9.5 djangorestframework>=3.7.0 django-allauth>=0.24.1 six==1.9.0 diff --git a/demo/templates/base.html b/demo/templates/base.html index cbf02b6..47e4e64 100644 --- a/demo/templates/base.html +++ b/demo/templates/base.html @@ -4,10 +4,10 @@ - - + + - django-rest-auth demo + dj-rest-auth demo @@ -53,13 +53,13 @@ - django-rest-auth demo + dj-rest-auth demo diff --git a/demo/templates/home.html b/demo/templates/home.html index 134198a..ecc6f7c 100644 --- a/demo/templates/home.html +++ b/demo/templates/home.html @@ -3,7 +3,7 @@ {% block content %}
-

django-rest-auth demo

-

Welcome in django-rest-auth demo project!

+

dj-rest-auth demo

+

Welcome in dj-rest-auth demo project!

{% endblock %} diff --git a/rest_auth/__init__.py b/dj_rest_auth/__init__.py similarity index 100% rename from rest_auth/__init__.py rename to dj_rest_auth/__init__.py diff --git a/rest_auth/admin.py b/dj_rest_auth/admin.py similarity index 100% rename from rest_auth/admin.py rename to dj_rest_auth/admin.py diff --git a/rest_auth/app_settings.py b/dj_rest_auth/app_settings.py similarity index 97% rename from rest_auth/app_settings.py rename to dj_rest_auth/app_settings.py index 1b75fe6..9974c2d 100644 --- a/rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -1,6 +1,6 @@ from django.conf import settings -from rest_auth.serializers import ( +from dj_rest_auth.serializers import ( TokenSerializer as DefaultTokenSerializer, JWTSerializer as DefaultJWTSerializer, UserDetailsSerializer as DefaultUserDetailsSerializer, diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.mo b/dj_rest_auth/locale/cs/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/cs/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/cs/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/cs/LC_MESSAGES/django.po b/dj_rest_auth/locale/cs/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/cs/LC_MESSAGES/django.po rename to dj_rest_auth/locale/cs/LC_MESSAGES/django.po diff --git a/rest_auth/locale/de/LC_MESSAGES/django.mo b/dj_rest_auth/locale/de/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/de/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/de/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/de/LC_MESSAGES/django.po b/dj_rest_auth/locale/de/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/de/LC_MESSAGES/django.po rename to dj_rest_auth/locale/de/LC_MESSAGES/django.po diff --git a/rest_auth/locale/es/LC_MESSAGES/django.mo b/dj_rest_auth/locale/es/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/es/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/es/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/es/LC_MESSAGES/django.po b/dj_rest_auth/locale/es/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/es/LC_MESSAGES/django.po rename to dj_rest_auth/locale/es/LC_MESSAGES/django.po diff --git a/rest_auth/locale/fr/LC_MESSAGES/django.mo b/dj_rest_auth/locale/fr/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/fr/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/fr/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/fr/LC_MESSAGES/django.po b/dj_rest_auth/locale/fr/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/fr/LC_MESSAGES/django.po rename to dj_rest_auth/locale/fr/LC_MESSAGES/django.po diff --git a/rest_auth/locale/ko/LC_MESSAGES/django.mo b/dj_rest_auth/locale/ko/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/ko/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/ko/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/ko/LC_MESSAGES/django.po b/dj_rest_auth/locale/ko/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/ko/LC_MESSAGES/django.po rename to dj_rest_auth/locale/ko/LC_MESSAGES/django.po diff --git a/rest_auth/locale/pl/LC_MESSAGES/django.mo b/dj_rest_auth/locale/pl/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/pl/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/pl/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/pl/LC_MESSAGES/django.po b/dj_rest_auth/locale/pl/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/pl/LC_MESSAGES/django.po rename to dj_rest_auth/locale/pl/LC_MESSAGES/django.po diff --git a/rest_auth/locale/pt_BR/LC_MESSAGES/django.po b/dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/pt_BR/LC_MESSAGES/django.po rename to dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.po diff --git a/rest_auth/locale/ru/LC_MESSAGES/django.mo b/dj_rest_auth/locale/ru/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/ru/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/ru/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/ru/LC_MESSAGES/django.po b/dj_rest_auth/locale/ru/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/ru/LC_MESSAGES/django.po rename to dj_rest_auth/locale/ru/LC_MESSAGES/django.po diff --git a/rest_auth/locale/tr/LC_MESSAGES/django.po b/dj_rest_auth/locale/tr/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/tr/LC_MESSAGES/django.po rename to dj_rest_auth/locale/tr/LC_MESSAGES/django.po diff --git a/rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo b/dj_rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/zh_Hans/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/zh_Hans/LC_MESSAGES/django.po b/dj_rest_auth/locale/zh_Hans/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/zh_Hans/LC_MESSAGES/django.po rename to dj_rest_auth/locale/zh_Hans/LC_MESSAGES/django.po diff --git a/rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo b/dj_rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo similarity index 100% rename from rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo rename to dj_rest_auth/locale/zh_Hant/LC_MESSAGES/django.mo diff --git a/rest_auth/locale/zh_Hant/LC_MESSAGES/django.po b/dj_rest_auth/locale/zh_Hant/LC_MESSAGES/django.po similarity index 100% rename from rest_auth/locale/zh_Hant/LC_MESSAGES/django.po rename to dj_rest_auth/locale/zh_Hant/LC_MESSAGES/django.po diff --git a/rest_auth/models.py b/dj_rest_auth/models.py similarity index 100% rename from rest_auth/models.py rename to dj_rest_auth/models.py diff --git a/rest_auth/registration/__init__.py b/dj_rest_auth/registration/__init__.py similarity index 100% rename from rest_auth/registration/__init__.py rename to dj_rest_auth/registration/__init__.py diff --git a/rest_auth/registration/app_settings.py b/dj_rest_auth/registration/app_settings.py similarity index 100% rename from rest_auth/registration/app_settings.py rename to dj_rest_auth/registration/app_settings.py diff --git a/rest_auth/registration/serializers.py b/dj_rest_auth/registration/serializers.py similarity index 100% rename from rest_auth/registration/serializers.py rename to dj_rest_auth/registration/serializers.py diff --git a/rest_auth/registration/urls.py b/dj_rest_auth/registration/urls.py similarity index 100% rename from rest_auth/registration/urls.py rename to dj_rest_auth/registration/urls.py diff --git a/rest_auth/registration/views.py b/dj_rest_auth/registration/views.py similarity index 100% rename from rest_auth/registration/views.py rename to dj_rest_auth/registration/views.py diff --git a/rest_auth/serializers.py b/dj_rest_auth/serializers.py similarity index 100% rename from rest_auth/serializers.py rename to dj_rest_auth/serializers.py diff --git a/rest_auth/social_serializers.py b/dj_rest_auth/social_serializers.py similarity index 100% rename from rest_auth/social_serializers.py rename to dj_rest_auth/social_serializers.py diff --git a/rest_auth/tests/__init__.py b/dj_rest_auth/tests/__init__.py similarity index 100% rename from rest_auth/tests/__init__.py rename to dj_rest_auth/tests/__init__.py diff --git a/rest_auth/tests/django_urls.py b/dj_rest_auth/tests/django_urls.py similarity index 100% rename from rest_auth/tests/django_urls.py rename to dj_rest_auth/tests/django_urls.py diff --git a/rest_auth/tests/mixins.py b/dj_rest_auth/tests/mixins.py similarity index 100% rename from rest_auth/tests/mixins.py rename to dj_rest_auth/tests/mixins.py diff --git a/rest_auth/tests/requirements.pip b/dj_rest_auth/tests/requirements.pip similarity index 100% rename from rest_auth/tests/requirements.pip rename to dj_rest_auth/tests/requirements.pip diff --git a/rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py similarity index 100% rename from rest_auth/tests/settings.py rename to dj_rest_auth/tests/settings.py diff --git a/rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py similarity index 100% rename from rest_auth/tests/test_api.py rename to dj_rest_auth/tests/test_api.py diff --git a/rest_auth/tests/test_social.py b/dj_rest_auth/tests/test_social.py similarity index 100% rename from rest_auth/tests/test_social.py rename to dj_rest_auth/tests/test_social.py diff --git a/rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py similarity index 100% rename from rest_auth/tests/urls.py rename to dj_rest_auth/tests/urls.py diff --git a/rest_auth/urls.py b/dj_rest_auth/urls.py similarity index 100% rename from rest_auth/urls.py rename to dj_rest_auth/urls.py diff --git a/rest_auth/utils.py b/dj_rest_auth/utils.py similarity index 100% rename from rest_auth/utils.py rename to dj_rest_auth/utils.py diff --git a/rest_auth/views.py b/dj_rest_auth/views.py similarity index 100% rename from rest_auth/views.py rename to dj_rest_auth/views.py diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index 46d2a05..a2a4c7d 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -72,7 +72,7 @@ Basing on example from installation section :doc:`Installation ` - access_token - code - .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/Tivix/django-rest-auth/blob/master/rest_auth/registration/views.py + .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/Tivix/django-rest-auth/blob/master/dj_rest_auth/registration/views.py - /rest-auth/twitter/ (POST) diff --git a/docs/changelog.rst b/docs/changelog.rst index e7beb5d..2bb3f4c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -28,7 +28,7 @@ Changelog 0.9.1 ----- -- fixed import error when extending rest_auth serializers +- fixed import error when extending dj_rest_auth serializers - added sensitive fields decorator - added Spanish translations @@ -109,7 +109,7 @@ Changelog ----- - replaced ``django-registration`` with ``django-allauth`` -- moved registration logic to separated django application (``rest_auth.registration``) +- moved registration logic to separated django application (``dj_rest_auth.registration``) - added serializers customization in django settings - added social media authentication view - changed request method from GET to POST in logout endpoint diff --git a/docs/configuration.rst b/docs/configuration.rst index 59b301f..b988a76 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -6,19 +6,19 @@ Configuration You can define your custom serializers for each endpoint without overriding urls and views by adding ``REST_AUTH_SERIALIZERS`` dictionary in your django settings. Possible key values: - - LOGIN_SERIALIZER - serializer class in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.LoginSerializer`` + - LOGIN_SERIALIZER - serializer class in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.LoginSerializer`` - - TOKEN_SERIALIZER - response for successful authentication in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.TokenSerializer`` + - TOKEN_SERIALIZER - response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.TokenSerializer`` - - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.JWTSerializer`` + - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.JWTSerializer`` - - USER_DETAILS_SERIALIZER - serializer class in ``rest_auth.views.UserDetailsView``, default value ``rest_auth.serializers.UserDetailsSerializer`` + - USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``rest_auth.serializers.UserDetailsSerializer`` - - PASSWORD_RESET_SERIALIZER - serializer class in ``rest_auth.views.PasswordResetView``, default value ``rest_auth.serializers.PasswordResetSerializer`` + - PASSWORD_RESET_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetView``, default value ``rest_auth.serializers.PasswordResetSerializer`` - - PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``rest_auth.views.PasswordResetConfirmView``, default value ``rest_auth.serializers.PasswordResetConfirmSerializer`` + - PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetConfirmView``, default value ``rest_auth.serializers.PasswordResetConfirmSerializer`` - - PASSWORD_CHANGE_SERIALIZER - serializer class in ``rest_auth.views.PasswordChangeView``, default value ``rest_auth.serializers.PasswordChangeSerializer`` + - PASSWORD_CHANGE_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordChangeView``, default value ``rest_auth.serializers.PasswordChangeSerializer`` Example configuration: @@ -36,13 +36,13 @@ Configuration You can define your custom serializers for registration endpoint. Possible key values: - - REGISTER_SERIALIZER - serializer class in ``rest_auth.registration.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer`` + - REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer`` .. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance - **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models`` -- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``rest_auth.utils.default_create_token``. +- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``dj_rest_auth.utils.default_create_token``. - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) diff --git a/docs/faq.rst b/docs/faq.rst index d15566a..4a38211 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -3,7 +3,7 @@ FAQ 1. Why account_confirm_email url is defined but it is not usable? - In /rest_auth/registration/urls.py we can find something like this: + In /dj_rest_auth/registration/urls.py we can find something like this: .. code-block:: python @@ -36,12 +36,12 @@ FAQ # custom fields for user company_name = models.CharField(max_length=100) - To allow update user details within one request send to rest_auth.views.UserDetailsView view, create serializer like this: + To allow update user details within one request send to dj_rest_auth.views.UserDetailsView view, create serializer like this: .. code-block:: python from rest_framework import serializers - from rest_auth.serializers import UserDetailsSerializer + from dj_rest_auth.serializers import UserDetailsSerializer class UserSerializer(UserDetailsSerializer): diff --git a/docs/installation.rst b/docs/installation.rst index b382d43..d506727 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -7,7 +7,7 @@ Installation pip install django-rest-auth -2. Add ``rest_auth`` app to INSTALLED_APPS in your django settings.py: +2. Add ``dj_rest_auth`` app to INSTALLED_APPS in your django settings.py: .. code-block:: python @@ -16,19 +16,19 @@ Installation 'rest_framework', 'rest_framework.authtoken', ..., - 'rest_auth' + 'dj_rest_auth' ) .. note:: This project depends on ``django-rest-framework`` library, so install it if you haven't done yet. Make sure also you have installed ``rest_framework`` and ``rest_framework.authtoken`` apps -3. Add rest_auth urls: +3. Add dj_rest_auth urls: .. code-block:: python urlpatterns = [ ..., - url(r'^rest-auth/', include('rest_auth.urls')) + url(r'^rest-auth/', include('dj_rest_auth.urls')) ] 4. Migrate your database @@ -46,7 +46,7 @@ Registration (optional) 1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install django-rest-auth[with_social]``. -2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: +2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: 3. Add ``SITE_ID = 1`` to your django settings.py @@ -57,19 +57,19 @@ Registration (optional) 'django.contrib.sites', 'allauth', 'allauth.account', - 'rest_auth.registration', + 'dj_rest_auth.registration', ) SITE_ID = 1 -3. Add rest_auth.registration urls: +3. Add dj_rest_auth.registration urls: .. code-block:: python urlpatterns = [ ..., - url(r'^rest-auth/', include('rest_auth.urls')), - url(r'^rest-auth/registration/', include('rest_auth.registration.urls')) + url(r'^rest-auth/', include('dj_rest_auth.urls')), + url(r'^rest-auth/registration/', include('dj_rest_auth.registration.urls')) ] @@ -88,12 +88,12 @@ Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creati ..., 'rest_framework', 'rest_framework.authtoken', - 'rest_auth' + 'dj_rest_auth' ..., 'django.contrib.sites', 'allauth', 'allauth.account', - 'rest_auth.registration', + 'dj_rest_auth.registration', ..., 'allauth.socialaccount', 'allauth.socialaccount.providers.facebook', @@ -106,12 +106,12 @@ Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creati Facebook ######## -3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``FacebookOAuth2Adapter`` adapter as an attribute: +3. Create new view as a subclass of ``dj_rest_auth.registration.views.SocialLoginView`` with ``FacebookOAuth2Adapter`` adapter as an attribute: .. code-block:: python from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter - from rest_auth.registration.views import SocialLoginView + from dj_rest_auth.registration.views import SocialLoginView class FacebookLogin(SocialLoginView): adapter_class = FacebookOAuth2Adapter @@ -131,13 +131,13 @@ Twitter If you are using Twitter for your social authentication, it is a bit different since Twitter uses OAuth 1.0. -3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute: +3. Create new view as a subclass of ``dj_rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute: .. code-block:: python from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter - from rest_auth.registration.views import SocialLoginView - from rest_auth.social_serializers import TwitterLoginSerializer + from dj_rest_auth.registration.views import SocialLoginView + from dj_rest_auth.social_serializers import TwitterLoginSerializer class TwitterLogin(SocialLoginView): serializer_class = TwitterLoginSerializer @@ -160,13 +160,13 @@ GitHub If you are using GitHub for your social authentication, it uses code and not AccessToken directly. -3. Create new view as a subclass of ``rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes: +3. Create new view as a subclass of ``dj_rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes: .. code-block:: python from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter from allauth.socialaccount.providers.oauth2.client import OAuth2Client - from rest_auth.registration.views import SocialLoginView + from dj_rest_auth.registration.views import SocialLoginView class GithubLogin(SocialLoginView): adapter_class = GitHubOAuth2Adapter @@ -193,8 +193,8 @@ If you want to allow connecting existing accounts in addition to login, you can from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter from allauth.socialaccount.providers.oauth2.client import OAuth2Client - from rest_auth.registration.views import SocialConnectView - from rest_auth.social_serializers import TwitterConnectSerializer + from dj_rest_auth.registration.views import SocialConnectView + from dj_rest_auth.social_serializers import TwitterConnectSerializer class FacebookConnect(SocialConnectView): adapter_class = FacebookOAuth2Adapter @@ -224,7 +224,7 @@ You can also use the following views to check all social accounts attached to th .. code-block:: python - from rest_auth.registration.views import ( + from dj_rest_auth.registration.views import ( SocialAccountListView, SocialAccountDisconnectView ) diff --git a/docs/introduction.rst b/docs/introduction.rst index 191abb5..25cc914 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -18,8 +18,8 @@ Features Apps structure -------------- -* ``rest_auth`` has basic auth functionality like login, logout, password reset and password change -* ``rest_auth.registration`` has logic related with registration and social media authentication +* ``dj_rest_auth`` has basic auth functionality like login, logout, password reset and password change +* ``dj_rest_auth.registration`` has logic related with registration and social media authentication Angular app From f7da276bd2277576625f111d6732e70670b9a7c8 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 18:10:25 -0600 Subject: [PATCH 037/216] Updates names --- README.rst | 31 -------------------- dj_rest_auth/locale/cs/LC_MESSAGES/django.po | 8 ++--- dj_rest_auth/views.py | 2 +- docs/Makefile | 8 ++--- docs/api_endpoints.rst | 24 +++++++-------- docs/conf.py | 20 ++++++------- docs/demo.rst | 6 ++-- docs/index.rst | 24 +++++++-------- docs/installation.rst | 8 ++--- docs/introduction.rst | 4 +-- docs/make.bat | 4 +-- setup.py | 4 +-- 12 files changed, 56 insertions(+), 87 deletions(-) delete mode 100644 README.rst diff --git a/README.rst b/README.rst deleted file mode 100644 index f79511f..0000000 --- a/README.rst +++ /dev/null @@ -1,31 +0,0 @@ -Welcome to dj-rest-auth -=========================== - -.. image:: https://travis-ci.org/iMerica/dj-rest-auth.svg - :target: https://travis-ci.org/iMerica/dj-rest-auth - - -.. image:: https://coveralls.io/repos/iMerica/dj-rest-auth/badge.svg - :target: https://coveralls.io/r/iMerica/dj-rest-auth?branch=master - - -.. image:: https://readthedocs.org/projects/dj-rest-auth/badge/?version=latest - :target: https://readthedocs.org/projects/dj-rest-auth/?badge=latest - - -Django-dj-rest-auth provides a set of REST API endpoints for Authentication and Registration - - -Documentation -------------- -http://dj-rest-auth.readthedocs.org/en/latest/ - - -Source code ------------ -https://github.com/iMerica/dj-rest-auth - - -Stack Overflow ------------ -http://stackoverflow.com/questions/tagged/dj-rest-auth diff --git a/dj_rest_auth/locale/cs/LC_MESSAGES/django.po b/dj_rest_auth/locale/cs/LC_MESSAGES/django.po index eb8c60c..e6acf92 100644 --- a/dj_rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/dj_rest_auth/locale/cs/LC_MESSAGES/django.po @@ -1,11 +1,11 @@ -# Czech translations of Tivix/django-rest-auth +# Czech translations of iMerica/dj-rest-auth # -# This file is distributed under the same license as the Tivix/django-rest-auth package. +# This file is distributed under the same license as the iMerica/dj-rest-auth package. # msgid "" msgstr "" -"Project-Id-Version: Tivix/django-rest-auth\n" -"Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n" +"Project-Id-Version: iMerica/dj-rest-auth\n" +"Report-Msgid-Bugs-To: https://github.com/iMerica/dj-rest-auth/issues\n" "POT-Creation-Date: 2018-06-27 23:05+0200\n" "PO-Revision-Date: 2018-06-27 23:22+0200\n" "Language: cs\n" diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 0a0a982..0a27f8e 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -164,7 +164,7 @@ class UserDetailsView(RetrieveUpdateAPIView): """ Adding this method since it is sometimes called when using django-rest-swagger - https://github.com/Tivix/django-rest-auth/issues/275 + https://github.com/iMerica/dj-rest-auth/issues/275 """ return get_user_model().objects.none() diff --git a/docs/Makefile b/docs/Makefile index cf09288..e71af70 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -85,17 +85,17 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-rest-auth.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/dj-rest-auth.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-rest-auth.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/dj-rest-auth.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/django-rest-auth" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-rest-auth" + @echo "# mkdir -p $$HOME/.local/share/devhelp/dj-rest-auth" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/dj-rest-auth" @echo "# devhelp" epub: diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index a2a4c7d..f23dabd 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -4,7 +4,7 @@ API endpoints Basic ----- -- /rest-auth/login/ (POST) +- /dj-rest-auth/login/ (POST) - username - email @@ -12,24 +12,24 @@ Basic Returns Token key -- /rest-auth/logout/ (POST) +- /dj-rest-auth/logout/ (POST) .. note:: ``ACCOUNT_LOGOUT_ON_GET = True`` to allow logout using GET - this is the exact same configuration from allauth. NOT recommended, see: http://django-allauth.readthedocs.io/en/latest/views.html#logout -- /rest-auth/password/reset/ (POST) +- /dj-rest-auth/password/reset/ (POST) - email -- /rest-auth/password/reset/confirm/ (POST) +- /dj-rest-auth/password/reset/confirm/ (POST) - uid - token - new_password1 - new_password2 - .. note:: uid and token are sent in email after calling /rest-auth/password/reset/ + .. note:: uid and token are sent in email after calling /dj-rest-auth/password/reset/ -- /rest-auth/password/change/ (POST) +- /dj-rest-auth/password/change/ (POST) - new_password1 - new_password2 @@ -38,7 +38,7 @@ Basic .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. .. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change -- /rest-auth/user/ (GET, PUT, PATCH) +- /dj-rest-auth/user/ (GET, PUT, PATCH) - username - first_name @@ -50,14 +50,14 @@ Basic Registration ------------ -- /rest-auth/registration/ (POST) +- /dj-rest-auth/registration/ (POST) - username - password1 - password2 - email -- /rest-auth/registration/verify-email/ (POST) +- /dj-rest-auth/registration/verify-email/ (POST) - key @@ -67,14 +67,14 @@ Social Media Authentication Basing on example from installation section :doc:`Installation ` -- /rest-auth/facebook/ (POST) +- /dj-rest-auth/facebook/ (POST) - access_token - code - .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/Tivix/django-rest-auth/blob/master/dj_rest_auth/registration/views.py + .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/iMerica/dj-rest-auth/blob/master/dj_rest_auth/registration/views.py -- /rest-auth/twitter/ (POST) +- /dj-rest-auth/twitter/ (POST) - access_token - token_secret diff --git a/docs/conf.py b/docs/conf.py index 1c825cc..dd54bb6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# django-rest-auth documentation build configuration file, created by +# dj-rest-auth documentation build configuration file, created by # sphinx-quickstart on Wed Oct 8 15:59:37 2014. # # This file is execfile()d with the current directory set to its @@ -43,8 +43,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'django-rest-auth' -copyright = u'2018, Tivix Inc.' +project = u'dj-rest-auth' +copyright = u'2018, iMerica Inc.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -176,7 +176,7 @@ html_static_path = ['_static'] #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'django-rest-authdoc' +htmlhelp_basename = 'dj-rest-authdoc' # -- Options for LaTeX output --------------------------------------------- @@ -196,8 +196,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'django-rest-auth.tex', u'django-rest-auth Documentation', - u'Tivix Inc.', 'manual'), + ('index', 'dj-rest-auth.tex', u'dj-rest-auth Documentation', + u'iMerica Inc.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -226,8 +226,8 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-rest-auth', u'django-rest-auth Documentation', - [u'Tivix Inc.'], 1) + ('index', 'dj-rest-auth', u'dj-rest-auth Documentation', + [u'iMerica Inc.'], 1) ] # If true, show URL addresses after external links. @@ -240,8 +240,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'django-rest-auth', u'django-rest-auth Documentation', - u'Tivix Inc.', 'django-rest-auth', 'One line description of project.', + ('index', 'dj-rest-auth', u'dj-rest-auth Documentation', + u'iMerica Inc.', 'dj-rest-auth', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/demo.rst b/docs/demo.rst index 877ca33..22620f8 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -2,14 +2,14 @@ Demo project ============ The idea of creating demo project was to show how you can potentially use -django-rest-auth app with jQuery on frontend. +dj-rest-auth app with jQuery on frontend. Do these steps to make it running (ideally in virtualenv). .. code-block:: python cd /tmp - git clone https://github.com/Tivix/django-rest-auth.git - cd django-rest-auth/demo/ + git clone https://github.com/iMerica/dj-rest-auth.git + cd dj-rest-auth/demo/ pip install -r requirements.pip python manage.py migrate --settings=demo.settings --noinput python manage.py runserver --settings=demo.settings diff --git a/docs/index.rst b/docs/index.rst index dc25e83..8be210a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,14 +1,14 @@ -.. django-rest-auth documentation master file, created by +.. dj-rest-auth documentation master file, created by sphinx-quickstart on Wed Oct 8 15:59:37 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to django-rest-auth's documentation! +Welcome to dj-rest-auth's documentation! ============================================ -.. warning:: Updating django-rest-auth from version **0.3.3** is highly recommended because of a security issue in PasswordResetConfirmation validation method. +.. warning:: Updating dj-rest-auth from version **0.3.3** is highly recommended because of a security issue in PasswordResetConfirmation validation method. -.. note:: django-rest-auth from v0.3.3 supports django-rest-framework v3.0 +.. note:: dj-rest-auth from v0.3.3 supports django-rest-framework v3.0 |build-status| |coverage-status| |requirements-status| |docs| @@ -28,25 +28,25 @@ Contents Changelog -.. |build-status| image:: https://travis-ci.org/Tivix/django-rest-auth.svg?branch=master +.. |build-status| image:: https://travis-ci.org/iMerica/dj-rest-auth.svg?branch=master :alt: build status :scale: 100% - :target: https://travis-ci.org/Tivix/django-rest-auth + :target: https://travis-ci.org/iMerica/dj-rest-auth -.. |coverage-status| image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.png?branch=master +.. |coverage-status| image:: https://coveralls.io/repos/iMerica/dj-rest-auth/badge.png?branch=master :alt: coverage status :scale: 100% - :target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master + :target: https://coveralls.io/r/iMerica/dj-rest-auth?branch=master -.. |requirements-status| image:: https://requires.io/github/Tivix/django-rest-auth/requirements.png?branch=master +.. |requirements-status| image:: https://requires.io/github/iMerica/dj-rest-auth/requirements.png?branch=master :alt: requirements status :scale: 100% - :target: https://requires.io/github/Tivix/django-rest-auth/requirements/?branch=master + :target: https://requires.io/github/iMerica/dj-rest-auth/requirements/?branch=master -.. |docs| image:: https://readthedocs.org/projects/django-rest-auth/badge/?version=latest +.. |docs| image:: https://readthedocs.org/projects/dj-rest-auth/badge/?version=latest :scale: 100% - :target: https://readthedocs.org/projects/django-rest-auth/?badge=latest + :target: https://readthedocs.org/projects/dj-rest-auth/?badge=latest :alt: Documentation Status diff --git a/docs/installation.rst b/docs/installation.rst index d506727..395299a 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -5,7 +5,7 @@ Installation .. code-block:: python - pip install django-rest-auth + pip install dj-rest-auth 2. Add ``dj_rest_auth`` app to INSTALLED_APPS in your django settings.py: @@ -44,7 +44,7 @@ You're good to go now! Registration (optional) ----------------------- -1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install django-rest-auth[with_social]``. +1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install dj-rest-auth[with_social]``. 2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: @@ -76,7 +76,7 @@ Registration (optional) Social Authentication (optional) -------------------------------- -Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creating social media authentication view. +Using ``django-allauth``, ``dj-rest-auth`` provides helpful class for creating social media authentication view. .. note:: Points 1 and 2 are related to ``django-allauth`` configuration, so if you have already configured social authentication, then please go to step 3. See ``django-allauth`` documentation for more details. @@ -246,7 +246,7 @@ You can also use the following views to check all social accounts attached to th JSON Web Token (JWT) Support (optional) --------------------------------------- -By default ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps: +By default ``dj-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps: 1. Install `djangorestframework-jwt `_ - ``djangorestframework-jwt`` is currently the only supported JWT library. diff --git a/docs/introduction.rst b/docs/introduction.rst index 25cc914..6f4d354 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -2,7 +2,7 @@ Introduction ============ -Since the introduction of django-rest-framework, Django apps have been able to serve up app-level REST API endpoints. As a result, we saw a lot of instances where developers implemented their own REST registration API endpoints here and there, snippets, and so on. We aim to solve this demand by providing django-rest-auth, a set of REST API endpoints to handle User Registration and Authentication tasks. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for User Management. Of course, we'll add more API endpoints as we see the demand. +Since the introduction of django-rest-framework, Django apps have been able to serve up app-level REST API endpoints. As a result, we saw a lot of instances where developers implemented their own REST registration API endpoints here and there, snippets, and so on. We aim to solve this demand by providing dj-rest-auth, a set of REST API endpoints to handle User Registration and Authentication tasks. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for User Management. Of course, we'll add more API endpoints as we see the demand. Features -------- @@ -25,7 +25,7 @@ Apps structure Angular app ----------- -- Tivix has also created angular module which uses API endpoints from this app - `angular-django-registration-auth `_ +- iMerica has also created angular module which uses API endpoints from this app - `angular-django-registration-auth `_ Demo project diff --git a/docs/make.bat b/docs/make.bat index db1383d..3aff4bb 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -115,9 +115,9 @@ if "%1" == "qthelp" ( echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-rest-auth.qhcp + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\dj-rest-auth.qhcp echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-rest-auth.ghc + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\dj-rest-auth.ghc goto end ) diff --git a/setup.py b/setup.py index 675b99d..30ee681 100644 --- a/setup.py +++ b/setup.py @@ -11,11 +11,11 @@ f.close() setup( - name='django-rest-auth', + name='dj-rest-auth', version='0.9.5', author='Sumit Chachra', author_email='chachra@tivix.com', - url='http://github.com/Tivix/django-rest-auth', + url='http://github.com/iMerica/dj-rest-auth', description='Create a set of REST API endpoints for Authentication and Registration', packages=find_packages(), long_description=long_description, From 082497429255c2d752e8ca0b797fb8a62141e267 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 18:58:59 -0600 Subject: [PATCH 038/216] Adds circle CI --- LICENSE | 2 +- config.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 config.yml diff --git a/LICENSE b/LICENSE index f868a2a..42a0292 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 iMerica +Copyright (c) 2014 iMerica https://github.com/iMerica/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..3210e8c --- /dev/null +++ b/config.yml @@ -0,0 +1,32 @@ +version: 2.1 +orbs: + python: circleci/python@0.2.1 + +jobs: + build-latest: &template + environment: + DJANGO_VERSION: 3.0.* + DRF: 3.9.* + executor: python/default + steps: + - checkout + - python/load-cache + - run: + - echo -n $DJANGO_VERSION > requirements.txt + - echo -n $DRF >> requirements.txt + - pip install -r requirements.txt + - python/save-cache + - run: + command: ./manage.py test + name: Test + build-django-2: + <<: *template + environment: + DJANGO_VERSION: 2.0.* + DRF: 3.9.* + +workflows: + main: + jobs: + - build-latest + - build-django-2 \ No newline at end of file From 2e5df3b3e70c32ad1286bf3b97c30e704b44d9a9 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:00:25 -0600 Subject: [PATCH 039/216] Fixes Circle location --- config.yml => .circleci/config.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config.yml => .circleci/config.yml (100%) diff --git a/config.yml b/.circleci/config.yml similarity index 100% rename from config.yml rename to .circleci/config.yml From 5c50d0cb7f8f007f032f36a7fec712f0ccf2e8fc Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:03:43 -0600 Subject: [PATCH 040/216] Fixes YAML schema --- .circleci/config.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3210e8c..f270c2e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,10 +11,9 @@ jobs: steps: - checkout - python/load-cache - - run: - - echo -n $DJANGO_VERSION > requirements.txt - - echo -n $DRF >> requirements.txt - - pip install -r requirements.txt + - run: echo -n $DJANGO_VERSION > requirements.txt + - run: echo -n $DRF >> requirements.txt + - run: pip install -r requirements.txt - python/save-cache - run: command: ./manage.py test From 0797ce257f72d8f8c11eb20dc01356cc9c42793f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:06:43 -0600 Subject: [PATCH 041/216] Remove cache --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f270c2e..68175a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,9 @@ jobs: executor: python/default steps: - checkout - - python/load-cache - run: echo -n $DJANGO_VERSION > requirements.txt - run: echo -n $DRF >> requirements.txt - run: pip install -r requirements.txt - - python/save-cache - run: command: ./manage.py test name: Test From 03925f46e40eae7585f390a3d39ff481523e54bf Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:07:45 -0600 Subject: [PATCH 042/216] Removes echo flag --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 68175a1..a3da36b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,8 +10,8 @@ jobs: executor: python/default steps: - checkout - - run: echo -n $DJANGO_VERSION > requirements.txt - - run: echo -n $DRF >> requirements.txt + - run: echo $DJANGO_VERSION > requirements.txt + - run: echo $DRF >> requirements.txt - run: pip install -r requirements.txt - run: command: ./manage.py test From 5faeda0c3a95a7ebfe7a6532bb341b00e3936625 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:11:49 -0600 Subject: [PATCH 043/216] Updates yaml --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a3da36b..7aca92f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,13 +5,13 @@ orbs: jobs: build-latest: &template environment: - DJANGO_VERSION: 3.0.* - DRF: 3.9.* + DJANGO_VERSION: 3.0 + DRF: 3.9 executor: python/default steps: - checkout - - run: echo $DJANGO_VERSION > requirements.txt - - run: echo $DRF >> requirements.txt + - run: echo "Django==$DJANGO_VERSION" > requirements.txt + - run: echo "djangorestframework==$DRF" >> requirements.txt - run: pip install -r requirements.txt - run: command: ./manage.py test @@ -19,8 +19,8 @@ jobs: build-django-2: <<: *template environment: - DJANGO_VERSION: 2.0.* - DRF: 3.9.* + DJANGO_VERSION: 2.0 + DRF: 3.9 workflows: main: From a7025c1146424ef48eba3e89bf36d3c686746462 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:13:28 -0600 Subject: [PATCH 044/216] Runs tests --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7aca92f..0ab50c5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ jobs: - run: echo "djangorestframework==$DRF" >> requirements.txt - run: pip install -r requirements.txt - run: - command: ./manage.py test + command: ./runtest.py name: Test build-django-2: <<: *template From b2300a4981c711906584ef80dd5323a96250388f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:15:56 -0600 Subject: [PATCH 045/216] Fixes test command --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0ab50c5..771be20 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,9 +12,10 @@ jobs: - checkout - run: echo "Django==$DJANGO_VERSION" > requirements.txt - run: echo "djangorestframework==$DRF" >> requirements.txt + - run: pip install coveralls - run: pip install -r requirements.txt - run: - command: ./runtest.py + command: coverage run --source=dj_rest_auth setup.py test name: Test build-django-2: <<: *template From 41dce8885a3b010ba95b4f732ed12d7003814763 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:46:32 -0600 Subject: [PATCH 046/216] Fixes tests --- README.md | 0 dj_rest_auth/tests/django_urls.py | 45 ++++++++++++++++++++----------- dj_rest_auth/tests/settings.py | 4 ++- runtests.py | 4 +-- setup.py | 7 ++--- 5 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/dj_rest_auth/tests/django_urls.py b/dj_rest_auth/tests/django_urls.py index c1fb050..57f9d7d 100644 --- a/dj_rest_auth/tests/django_urls.py +++ b/dj_rest_auth/tests/django_urls.py @@ -1,30 +1,45 @@ # Moved in Django 1.8 from django to tests/auth_tests/urls.py from django.conf.urls import url -from django.contrib.auth import views from django.contrib.auth.decorators import login_required from django.contrib.auth.urls import urlpatterns +try: + from django.contrib.auth.views import ( + logout, login, password_reset, + password_change, password_reset_confirm + ) +except ImportError: + from django.contrib.auth.views import ( + LoginView, LogoutView, PasswordResetView, + PasswordChangeView, PasswordResetConfirmView + ) + logout = LogoutView.as_view() + login = LoginView.as_view() + password_reset = PasswordResetView.as_view() + password_change = PasswordChangeView.as_view() + password_reset_confirm = PasswordResetConfirmView.as_view() + # special urls for auth test cases urlpatterns += [ - url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')), - url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')), - url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')), - url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')), - url(r'^password_reset/custom_redirect/$', views.password_reset, dict(post_reset_redirect='/custom/')), - url(r'^password_reset/custom_redirect/named/$', views.password_reset, dict(post_reset_redirect='password_reset')), - url(r'^password_reset/html_email_template/$', views.password_reset, + url(r'^logout/custom_query/$', logout, dict(redirect_field_name='follow')), + url(r'^logout/next_page/$', logout, dict(next_page='/somewhere/')), + url(r'^logout/next_page/named/$', logout, dict(next_page='password_reset')), + url(r'^password_reset_from_email/$', password_reset, dict(from_email='staffmember@example.com')), + url(r'^password_reset/custom_redirect/$', password_reset, dict(post_reset_redirect='/custom/')), + url(r'^password_reset/custom_redirect/named/$', password_reset, dict(post_reset_redirect='password_reset')), + url(r'^password_reset/html_email_template/$', password_reset, dict(html_email_template_name='registration/html_password_reset_email.html')), url(r'^reset/custom/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', - views.password_reset_confirm, + password_reset_confirm, dict(post_reset_redirect='/custom/')), url(r'^reset/custom/named/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', - views.password_reset_confirm, + password_reset_confirm, dict(post_reset_redirect='password_reset')), - url(r'^password_change/custom/$', views.password_change, dict(post_change_redirect='/custom/')), - url(r'^password_change/custom/named/$', views.password_change, dict(post_change_redirect='password_reset')), - url(r'^admin_password_reset/$', views.password_reset, dict(is_admin_site=True)), - url(r'^login_required/$', login_required(views.password_reset)), - url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')), + url(r'^password_change/custom/$', password_change, dict(post_change_redirect='/custom/')), + url(r'^password_change/custom/named/$', password_change, dict(post_change_redirect='password_reset')), + url(r'^admin_password_reset/$', password_reset, dict(is_admin_site=True)), + url(r'^login_required/$', login_required(password_reset)), + url(r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')), ] diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index e353fb0..16ba4b5 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -1,8 +1,11 @@ import os import sys +import logging PROJECT_ROOT = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0]) + +logging.disable(logging.CRITICAL) ROOT_URLCONF = 'urls' STATIC_URL = '/static/' STATIC_ROOT = '%s/staticserve' % PROJECT_ROOT @@ -70,7 +73,6 @@ REST_FRAMEWORK = { } INSTALLED_APPS = [ - 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.humanize', 'django.contrib.contenttypes', diff --git a/runtests.py b/runtests.py index 8b7ede2..cabaf9c 100644 --- a/runtests.py +++ b/runtests.py @@ -3,8 +3,8 @@ import os import sys -os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' -test_dir = os.path.join(os.path.dirname(__file__), 'rest_auth') +os.environ['DJANGO_SETTINGS_MODULE'] = 'dj_rest_auth.tests.settings' +test_dir = os.path.join(os.path.dirname(__file__), 'dj_rest_auth') sys.path.insert(0, test_dir) import django diff --git a/setup.py b/setup.py index 30ee681..472ce6b 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup, find_packages here = os.path.dirname(os.path.abspath(__file__)) -f = open(os.path.join(here, 'README.rst')) +f = open(os.path.join(here, 'README.md')) long_description = f.read().strip() f.close() @@ -13,12 +13,13 @@ f.close() setup( name='dj-rest-auth', version='0.9.5', - author='Sumit Chachra', - author_email='chachra@tivix.com', + author='iMerica', + author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', description='Create a set of REST API endpoints for Authentication and Registration', packages=find_packages(), long_description=long_description, + long_description_content_type='text/markdown', keywords='django rest auth registration rest-framework django-registration api', zip_safe=False, install_requires=[ From 331094b6a7b74681f97db43b587e899bec2d8420 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:54:53 -0600 Subject: [PATCH 047/216] Fixes Imports --- .travis.yml | 26 -------------------------- dj_rest_auth/registration/views.py | 10 +++++----- dj_rest_auth/tests/settings.py | 4 ++-- dj_rest_auth/tests/test_api.py | 4 ++-- dj_rest_auth/tests/urls.py | 6 +++--- dj_rest_auth/urls.py | 2 +- runtests.py | 2 +- 7 files changed, 14 insertions(+), 40 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 33f42ad..0000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: python -python: - - "2.7" - - "3.5" - - "3.6" -env: - - DJANGO=1.11.* DRF=3.7.* - - DJANGO=1.11.* DRF=3.8.* - - DJANGO=2.0.* DRF=3.7.* - - DJANGO=2.0.* DRF=3.8.* -install: - - pip install -q Django==$DJANGO djangorestframework==$DRF - - pip install coveralls - - pip install -r dj_rest_auth/tests/requirements.pip -script: - - coverage run --source=dj_rest_auth setup.py test -after_success: - - coveralls -before_script: - - flake8 . --config=flake8 -matrix: - exclude: - - python: "2.7" - env: DJANGO=2.0.* DRF=3.7.* - - python: "2.7" - env: DJANGO=2.0.* DRF=3.8.* diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index 0e0ab0d..f8d1120 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -19,16 +19,16 @@ from allauth.socialaccount import signals from allauth.socialaccount.adapter import get_adapter as get_social_adapter from allauth.socialaccount.models import SocialAccount -from rest_auth.app_settings import (TokenSerializer, +from dj_rest_auth.app_settings import (TokenSerializer, JWTSerializer, create_token) -from rest_auth.models import TokenModel -from rest_auth.registration.serializers import (VerifyEmailSerializer, +from dj_rest_auth.models import TokenModel +from dj_rest_auth.registration.serializers import (VerifyEmailSerializer, SocialLoginSerializer, SocialAccountSerializer, SocialConnectSerializer) -from rest_auth.utils import jwt_encode -from rest_auth.views import LoginView +from dj_rest_auth.utils import jwt_encode +from dj_rest_auth.views import LoginView from .app_settings import RegisterSerializer, register_permission_classes sensitive_post_parameters_m = method_decorator( diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index 16ba4b5..c86bfc1 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -90,8 +90,8 @@ INSTALLED_APPS = [ 'rest_framework', 'rest_framework.authtoken', - 'rest_auth', - 'rest_auth.registration', + 'dj_rest_auth', + 'dj_rest_auth.registration', 'rest_framework_jwt' ] diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 9c5fd9e..b6d84f2 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -8,8 +8,8 @@ from allauth.account import app_settings as account_app_settings from rest_framework import status from rest_framework.test import APIRequestFactory -from rest_auth.registration.views import RegisterView -from rest_auth.registration.app_settings import register_permission_classes +from dj_rest_auth.registration.views import RegisterView +from dj_rest_auth.registration.app_settings import register_permission_classes from .mixins import TestsMixin, CustomPermissionClass diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index 401f23a..ef900b9 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -7,12 +7,12 @@ from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter from rest_framework.decorators import api_view -from rest_auth.urls import urlpatterns -from rest_auth.registration.views import ( +from dj_rest_auth.urls import urlpatterns +from dj_rest_auth.registration.views import ( SocialLoginView, SocialConnectView, SocialAccountListView, SocialAccountDisconnectView ) -from rest_auth.social_serializers import ( +from dj_rest_auth.social_serializers import ( TwitterLoginSerializer, TwitterConnectSerializer ) diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 7a35e9b..6664722 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -1,6 +1,6 @@ from django.conf.urls import url -from rest_auth.views import ( +from dj_rest_auth.views import ( LoginView, LogoutView, UserDetailsView, PasswordChangeView, PasswordResetView, PasswordResetConfirmView ) diff --git a/runtests.py b/runtests.py index cabaf9c..6fab508 100644 --- a/runtests.py +++ b/runtests.py @@ -17,7 +17,7 @@ def runtests(): test_runner = TestRunner(verbosity=1, interactive=True) if hasattr(django, 'setup'): django.setup() - failures = test_runner.run_tests(['rest_auth']) + failures = test_runner.run_tests(['dj_rest_auth']) sys.exit(bool(failures)) if __name__ == '__main__': From 6ece00f6e9267ef83b1608cf00d0ca2d45fb8c5d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 19:59:44 -0600 Subject: [PATCH 048/216] Adds Docker runtime --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 771be20..2918fd5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,6 +4,8 @@ orbs: jobs: build-latest: &template + docker: + - image: circleci/python:3.8.0 environment: DJANGO_VERSION: 3.0 DRF: 3.9 From c43965b55f3d3fdd33c61b351cdf6a66e446bacc Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:03:34 -0600 Subject: [PATCH 049/216] Removes Orb --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2918fd5..16565f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,4 @@ version: 2.1 -orbs: - python: circleci/python@0.2.1 jobs: build-latest: &template From 8e7982e52b1cdb1a2a265925bf7240d75a66afbf Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:04:34 -0600 Subject: [PATCH 050/216] Uses Docker Orb --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 16565f1..17dbf10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,6 @@ version: 2.1 +orbs: + docker: circleci/docker@0.6.0 jobs: build-latest: &template From 12883f8efce4fccf93b4c38f10d21f9a1e76f767 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:05:46 -0600 Subject: [PATCH 051/216] Uses Docker Executor --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17dbf10..a5bfacb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ jobs: environment: DJANGO_VERSION: 3.0 DRF: 3.9 - executor: python/default + executor: docker/docker steps: - checkout - run: echo "Django==$DJANGO_VERSION" > requirements.txt From 3402d1f2cd9e4b4cc74e31dffaacccfc70d445b0 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:10:13 -0600 Subject: [PATCH 052/216] Uses pip install with user --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a5bfacb..0fd7227 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,8 +14,8 @@ jobs: - checkout - run: echo "Django==$DJANGO_VERSION" > requirements.txt - run: echo "djangorestframework==$DRF" >> requirements.txt - - run: pip install coveralls - - run: pip install -r requirements.txt + - run: pip install --user coveralls + - run: pip install --user -r requirements.txt - run: command: coverage run --source=dj_rest_auth setup.py test name: Test From a87a458ccfefd279ba585d4080be3f3aa4a5c1c0 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:30:21 -0600 Subject: [PATCH 053/216] Removes six --- demo/requirements.pip | 1 - dj_rest_auth/app_settings.py | 39 +++++++---------------- dj_rest_auth/models.py | 4 +-- dj_rest_auth/registration/app_settings.py | 9 +++--- dj_rest_auth/serializers.py | 5 +-- dj_rest_auth/utils.py | 12 ------- setup.py | 1 - 7 files changed, 17 insertions(+), 54 deletions(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index c6f5f42..ab0a814 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -2,5 +2,4 @@ django>=1.9.0 dj-rest-auth==0.9.5 djangorestframework>=3.7.0 django-allauth>=0.24.1 -six==1.9.0 django-rest-swagger==2.0.7 diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index 9974c2d..7f8094f 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -8,44 +8,27 @@ from dj_rest_auth.serializers import ( PasswordResetSerializer as DefaultPasswordResetSerializer, PasswordResetConfirmSerializer as DefaultPasswordResetConfirmSerializer, PasswordChangeSerializer as DefaultPasswordChangeSerializer) -from .utils import import_callable, default_create_token +from .utils import default_create_token -create_token = import_callable( - getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token)) +create_token = getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token) serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {}) -TokenSerializer = import_callable( - serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer)) +TokenSerializer = serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer) -JWTSerializer = import_callable( - serializers.get('JWT_SERIALIZER', DefaultJWTSerializer)) +JWTSerializer = serializers.get('JWT_SERIALIZER', DefaultJWTSerializer) -UserDetailsSerializer = import_callable( - serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer) -) +UserDetailsSerializer = serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer) -LoginSerializer = import_callable( - serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer) -) +LoginSerializer = serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer) -PasswordResetSerializer = import_callable( - serializers.get( +PasswordResetSerializer = serializers.get( 'PASSWORD_RESET_SERIALIZER', DefaultPasswordResetSerializer ) + +PasswordResetConfirmSerializer = serializers.get( + 'PASSWORD_RESET_CONFIRM_SERIALIZER', DefaultPasswordResetConfirmSerializer ) -PasswordResetConfirmSerializer = import_callable( - serializers.get( - 'PASSWORD_RESET_CONFIRM_SERIALIZER', - DefaultPasswordResetConfirmSerializer - ) -) - -PasswordChangeSerializer = import_callable( - serializers.get( - 'PASSWORD_CHANGE_SERIALIZER', - DefaultPasswordChangeSerializer - ) -) +PasswordChangeSerializer = serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer) diff --git a/dj_rest_auth/models.py b/dj_rest_auth/models.py index a132f9c..5f690da 100644 --- a/dj_rest_auth/models.py +++ b/dj_rest_auth/models.py @@ -2,9 +2,7 @@ from django.conf import settings from rest_framework.authtoken.models import Token as DefaultTokenModel -from .utils import import_callable # Register your models here. -TokenModel = import_callable( - getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel)) +TokenModel = getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel) diff --git a/dj_rest_auth/registration/app_settings.py b/dj_rest_auth/registration/app_settings.py index c8cd25a..3e6db53 100644 --- a/dj_rest_auth/registration/app_settings.py +++ b/dj_rest_auth/registration/app_settings.py @@ -2,18 +2,17 @@ from django.conf import settings from rest_framework.permissions import AllowAny from rest_auth.registration.serializers import ( - RegisterSerializer as DefaultRegisterSerializer) -from ..utils import import_callable + RegisterSerializer as DefaultRegisterSerializer +) serializers = getattr(settings, 'REST_AUTH_REGISTER_SERIALIZERS', {}) -RegisterSerializer = import_callable( - serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer)) +RegisterSerializer = serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer) def register_permission_classes(): permission_classes = [AllowAny, ] for klass in getattr(settings, 'REST_AUTH_REGISTER_PERMISSION_CLASSES', tuple()): - permission_classes.append(import_callable(klass)) + permission_classes.append(klass) return tuple(permission_classes) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index b645231..da8fef7 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -10,7 +10,6 @@ from rest_framework import serializers, exceptions from rest_framework.exceptions import ValidationError from .models import TokenModel -from .utils import import_callable # Get the UserModel UserModel = get_user_model() @@ -146,9 +145,7 @@ class JWTSerializer(serializers.Serializer): JWTSerializer. Defining it here to avoid circular imports """ rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {}) - JWTUserDetailsSerializer = import_callable( - rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer) - ) + JWTUserDetailsSerializer = rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer) user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data return user_data diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 800f184..b69dae0 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -1,15 +1,3 @@ -from six import string_types -from importlib import import_module - - -def import_callable(path_or_callable): - if hasattr(path_or_callable, '__call__'): - return path_or_callable - else: - assert isinstance(path_or_callable, string_types) - package, attr = path_or_callable.rsplit('.', 1) - return getattr(import_module(package), attr) - def default_create_token(token_model, user, serializer): token, _ = token_model.objects.get_or_create(user=user) diff --git a/setup.py b/setup.py index 472ce6b..a57994e 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ setup( install_requires=[ 'Django>=1.8.0', 'djangorestframework>=3.1.3', - 'six>=1.9.0', ], extras_require={ 'with_social': ['django-allauth>=0.25.0'], From 7331e63201342342b3b7c6b3a31ff219813546e3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 20:41:51 -0600 Subject: [PATCH 054/216] Fixes min reqs --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a57994e..db77e40 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.9.5', + version='0.1.0', author='iMerica', author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', @@ -23,7 +23,7 @@ setup( keywords='django rest auth registration rest-framework django-registration api', zip_safe=False, install_requires=[ - 'Django>=1.8.0', + 'Django>=1.11', 'djangorestframework>=3.1.3', ], extras_require={ From 4c3a1216767cace2e6dcccaed151850e3ba8256f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:22:37 -0600 Subject: [PATCH 055/216] WIP --- .circleci/config.yml | 2 +- dj_rest_auth/registration/app_settings.py | 2 +- dj_rest_auth/social_serializers.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0fd7227..138d8ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ jobs: - image: circleci/python:3.8.0 environment: DJANGO_VERSION: 3.0 - DRF: 3.9 + DRF: 3.11 executor: docker/docker steps: - checkout diff --git a/dj_rest_auth/registration/app_settings.py b/dj_rest_auth/registration/app_settings.py index 3e6db53..fdeae83 100644 --- a/dj_rest_auth/registration/app_settings.py +++ b/dj_rest_auth/registration/app_settings.py @@ -1,7 +1,7 @@ from django.conf import settings from rest_framework.permissions import AllowAny -from rest_auth.registration.serializers import ( +from dj_rest_auth.registration.serializers import ( RegisterSerializer as DefaultRegisterSerializer ) diff --git a/dj_rest_auth/social_serializers.py b/dj_rest_auth/social_serializers.py index 1621813..6f8a449 100644 --- a/dj_rest_auth/social_serializers.py +++ b/dj_rest_auth/social_serializers.py @@ -8,7 +8,7 @@ if 'allauth.socialaccount' in settings.INSTALLED_APPS: from allauth.socialaccount.models import SocialToken from allauth.socialaccount.providers.oauth.client import OAuthError - from rest_auth.registration.serializers import SocialConnectMixin + from dj_rest_auth.registration.serializers import SocialConnectMixin class TwitterLoginSerializer(serializers.Serializer): From cd2328cfde07f8ae5edcf75aafdf16c612993373 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:25:20 -0600 Subject: [PATCH 056/216] WIP --- dj_rest_auth/tests/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index ef900b9..5aa37c1 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -53,7 +53,7 @@ class TwitterLoginNoAdapter(SocialLoginView): urlpatterns += [ - url(r'^rest-registration/', include('rest_auth.registration.urls')), + url(r'^rest-registration/', include('dj_rest_auth.registration.urls')), url(r'^test-admin/', include(django_urls)), url(r'^account-email-verification-sent/$', TemplateView.as_view(), name='account_email_verification_sent'), From 3e89a8d32f047098e09336a5e27edc52973d3ecc Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:28:48 -0600 Subject: [PATCH 057/216] Adds dev reqs --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 138d8ad..7bdbc4b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,6 +16,7 @@ jobs: - run: echo "djangorestframework==$DRF" >> requirements.txt - run: pip install --user coveralls - run: pip install --user -r requirements.txt + - run: pip install --user -r dev-requirements.txt - run: command: coverage run --source=dj_rest_auth setup.py test name: Test From 60c1a4ad5f2097f32c83cae08c6720858f9546bf Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:34:24 -0600 Subject: [PATCH 058/216] Adds more tests coverage --- .circleci/config.yml | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7bdbc4b..a8c0ea1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,6 +25,11 @@ jobs: environment: DJANGO_VERSION: 2.0 DRF: 3.9 + build-django-11: + <<: *template + environment: + DJANGO_VERSION: 1.11 + DRF: 3.9 workflows: main: diff --git a/setup.py b/setup.py index db77e40..09ffe1c 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( author='iMerica', author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', - description='Create a set of REST API endpoints for Authentication and Registration', + description='Authentication and Registration in Django Rest Framework', packages=find_packages(), long_description=long_description, long_description_content_type='text/markdown', From 60cdae15709d2e049cb5d500049a9ae24996629d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:35:00 -0600 Subject: [PATCH 059/216] Runs 1.11 tests --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a8c0ea1..2e9a3d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,4 +35,5 @@ workflows: main: jobs: - build-latest - - build-django-2 \ No newline at end of file + - build-django-2 + - build-django-11 \ No newline at end of file From c99caac86a3309ce8e7732dc18646b2af233285a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:35:43 -0600 Subject: [PATCH 060/216] Adds tests --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e9a3d4..ee7f31d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ orbs: docker: circleci/docker@0.6.0 jobs: - build-latest: &template + test-latest: &template docker: - image: circleci/python:3.8.0 environment: @@ -20,12 +20,12 @@ jobs: - run: command: coverage run --source=dj_rest_auth setup.py test name: Test - build-django-2: + test-django-2: <<: *template environment: DJANGO_VERSION: 2.0 DRF: 3.9 - build-django-11: + test-django-11: <<: *template environment: DJANGO_VERSION: 1.11 @@ -34,6 +34,6 @@ jobs: workflows: main: jobs: - - build-latest - - build-django-2 - - build-django-11 \ No newline at end of file + - test-latest + - test-django-2 + - test-django-11 \ No newline at end of file From a757eeaf536aeb3ab4453fa69b639251c3964bbe Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:54:55 -0600 Subject: [PATCH 061/216] Install tests reqs --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ee7f31d..d05084d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,6 +17,7 @@ jobs: - run: pip install --user coveralls - run: pip install --user -r requirements.txt - run: pip install --user -r dev-requirements.txt + - run: pip install --user -r dj_rest_auth/tests/requirements.pip - run: command: coverage run --source=dj_rest_auth setup.py test name: Test From cb1e2b61b8be464f0d017c8f5d1c05bc8d34121b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 21:58:44 -0600 Subject: [PATCH 062/216] Bumps Django --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d05084d..34b5db8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ jobs: docker: - image: circleci/python:3.8.0 environment: - DJANGO_VERSION: 3.0 + DJANGO_VERSION: 3.0.3 DRF: 3.11 executor: docker/docker steps: @@ -24,7 +24,7 @@ jobs: test-django-2: <<: *template environment: - DJANGO_VERSION: 2.0 + DJANGO_VERSION: 2.2.10 DRF: 3.9 test-django-11: <<: *template From 93ed2a15282829945dbf93d262e55eca1f5894c8 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:02:36 -0600 Subject: [PATCH 063/216] DRY's up config --- .circleci/config.yml | 9 +++------ runtests.py | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 34b5db8..869f98b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,12 +12,9 @@ jobs: executor: docker/docker steps: - checkout - - run: echo "Django==$DJANGO_VERSION" > requirements.txt - - run: echo "djangorestframework==$DRF" >> requirements.txt - - run: pip install --user coveralls - - run: pip install --user -r requirements.txt - - run: pip install --user -r dev-requirements.txt - - run: pip install --user -r dj_rest_auth/tests/requirements.pip + - run: pip install -q --user coveralls djangorestframework==$DRF "Django==$DJANGO_VERSION + - run: pip install -q --user -r dev-requirements.txt + - run: pip install -q --user -r dj_rest_auth/tests/requirements.pip - run: command: coverage run --source=dj_rest_auth setup.py test name: Test diff --git a/runtests.py b/runtests.py index 6fab508..04dfa7c 100644 --- a/runtests.py +++ b/runtests.py @@ -20,5 +20,6 @@ def runtests(): failures = test_runner.run_tests(['dj_rest_auth']) sys.exit(bool(failures)) + if __name__ == '__main__': runtests() From 6b27267758561048e47d67f0d28cc5f9b7451db2 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:03:34 -0600 Subject: [PATCH 064/216] Updates Django version --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 869f98b..2f2b4a5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,9 +12,9 @@ jobs: executor: docker/docker steps: - checkout - - run: pip install -q --user coveralls djangorestframework==$DRF "Django==$DJANGO_VERSION - - run: pip install -q --user -r dev-requirements.txt - - run: pip install -q --user -r dj_rest_auth/tests/requirements.pip + - run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION + - run: pip install --user -r dev-requirements.txt + - run: pip install --user -r dj_rest_auth/tests/requirements.pip - run: command: coverage run --source=dj_rest_auth setup.py test name: Test From 455b88ed573c77de0eb1302055fbd4c47efcc84d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:06:53 -0600 Subject: [PATCH 065/216] Removes Django 11 --- .circleci/config.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2f2b4a5..75c5e48 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ orbs: docker: circleci/docker@0.6.0 jobs: - test-latest: &template + test-django-3: &template docker: - image: circleci/python:3.8.0 environment: @@ -23,15 +23,9 @@ jobs: environment: DJANGO_VERSION: 2.2.10 DRF: 3.9 - test-django-11: - <<: *template - environment: - DJANGO_VERSION: 1.11 - DRF: 3.9 workflows: main: jobs: - - test-latest - - test-django-2 - - test-django-11 \ No newline at end of file + - test-django-3 + - test-django-2 \ No newline at end of file From a639fc6ace6436f0a60a5c50e43efffdf431efe8 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:47:06 -0600 Subject: [PATCH 066/216] Fixes broken tests --- dj_rest_auth/tests/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index c86bfc1..f683ce0 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -73,6 +73,8 @@ REST_FRAMEWORK = { } INSTALLED_APPS = [ + 'django.contrib.messages', + 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.humanize', 'django.contrib.contenttypes', From 39fbc15571e73f28c572d670f9419d2c272254ad Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:51:56 -0600 Subject: [PATCH 067/216] Adds README badge --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e69de29..58f1092 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,4 @@ +# Dj-Rest-Auth +[![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)]() + + From 7f17e18e3e06c842b0bbd0a94d151a5e39dfbfee Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 22:53:34 -0600 Subject: [PATCH 068/216] Updates badge URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58f1092..076cce2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Dj-Rest-Auth -[![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)]() +[![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/iMerica/dj-rest-auth/pipelines) From aafd10fccee96a545f0b711f8dbaa52bba49c99c Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:02:01 -0600 Subject: [PATCH 069/216] Updates README --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 076cce2..79125b2 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,32 @@ [![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/iMerica/dj-rest-auth/pipelines) +Drop-in API endpoints for authentication in Django Rest Framework. + +### Requirements +- Django 2 or 3. +- Python 3 + +### Setup + +Install package + + pip install dj-rest-auth + +Add `dj_rest_auth` app to INSTALLED_APPS in your django settings.py: + + INSTALLED_APPS = ( + ..., + 'rest_framework', + 'rest_framework.authtoken', + ..., + 'rest_auth' + ) + +Add URL patterns + + + urlpatterns = [ + url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) + ] + From 8b3915e1191ca527bde1ce1f6ca5fa2b168e292d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:03:58 -0600 Subject: [PATCH 070/216] Fixes README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79125b2..6a1faa8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Add `dj_rest_auth` app to INSTALLED_APPS in your django settings.py: 'rest_framework', 'rest_framework.authtoken', ..., - 'rest_auth' + 'dj_rest_auth' ) Add URL patterns From 7d63b53a43bfa48fdc2c34c57be14050c21423b2 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:06:12 -0600 Subject: [PATCH 071/216] Updats README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6a1faa8..09a0f5a 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,7 @@ Add URL patterns url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) ] + +### Acknowledgements + +This project began as a fork of `django-rest-auth`. Big thanks to everyone who contributed to that repo! \ No newline at end of file From 9298014b3a466d8febb4e33b5e2a2359804ec4b4 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:18:19 -0600 Subject: [PATCH 072/216] Fixes docs --- docs/index.rst | 3 +-- docs/installation.rst | 18 +++++++++--------- setup.py | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 8be210a..0479561 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,9 +6,8 @@ Welcome to dj-rest-auth's documentation! ============================================ -.. warning:: Updating dj-rest-auth from version **0.3.3** is highly recommended because of a security issue in PasswordResetConfirmation validation method. -.. note:: dj-rest-auth from v0.3.3 supports django-rest-framework v3.0 +.. note:: dj-rest-auth from v0.3.3 supports django-rest-framework >= v3.0 |build-status| |coverage-status| |requirements-status| |docs| diff --git a/docs/installation.rst b/docs/installation.rst index 395299a..cba551e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -28,7 +28,7 @@ Installation urlpatterns = [ ..., - url(r'^rest-auth/', include('dj_rest_auth.urls')) + url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) ] 4. Migrate your database @@ -68,8 +68,8 @@ Registration (optional) urlpatterns = [ ..., - url(r'^rest-auth/', include('dj_rest_auth.urls')), - url(r'^rest-auth/registration/', include('dj_rest_auth.registration.urls')) + url(r'^dj-rest-auth/', include('dj_rest_auth.urls')), + url(r'^dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')) ] @@ -122,7 +122,7 @@ Facebook urlpatterns += [ ..., - url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login') + url(r'^dj-rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login') ] @@ -149,7 +149,7 @@ If you are using Twitter for your social authentication, it is a bit different s urlpatterns += [ ..., - url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login') + url(r'^dj-rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login') ] .. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details. @@ -179,7 +179,7 @@ If you are using GitHub for your social authentication, it uses code and not Acc urlpatterns += [ ..., - url(r'^rest-auth/github/$', GitHubLogin.as_view(), name='github_login') + url(r'^dj-rest-auth/github/$', GitHubLogin.as_view(), name='github_login') ] Additional Social Connect Views @@ -215,9 +215,9 @@ In urls.py: urlpatterns += [ ..., - url(r'^rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect') - url(r'^rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect') - url(r'^rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect') + url(r'^dj-rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect') + url(r'^dj-rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect') + url(r'^dj-rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect') ] You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts: diff --git a/setup.py b/setup.py index 09ffe1c..9d2b775 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.1.0', + version='0.1.1', author='iMerica', author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', From 25d0ebbfd410329231db4ffb2b17ae5b33d7ae3e Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:20:56 -0600 Subject: [PATCH 073/216] Specifies Python version --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9d2b775..b00ff9e 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.1.1', + version='0.1.2', author='iMerica', author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', @@ -36,6 +36,7 @@ setup( ], test_suite='runtests.runtests', include_package_data=True, + python_requires='>=3.5', classifiers=[ 'Framework :: Django', 'Intended Audience :: Developers', From 34d5706b78e6ad7aaa229367169b4827f95ac2f1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:23:47 -0600 Subject: [PATCH 074/216] Updates README --- README.md | 8 ++++++-- docs/index.rst | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 09a0f5a..268c56a 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ Drop-in API endpoints for authentication in Django Rest Framework. -### Requirements +## Requirements - Django 2 or 3. - Python 3 -### Setup +## Quick Setup Install package @@ -31,6 +31,10 @@ Add URL patterns url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) ] +### Documentation + +View the full documentation here: https://dj-rest-auth.readthedocs.io/en/latest/index.html + ### Acknowledgements diff --git a/docs/index.rst b/docs/index.rst index 0479561..8deb445 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,7 @@ Welcome to dj-rest-auth's documentation! ============================================ -.. note:: dj-rest-auth from v0.3.3 supports django-rest-framework >= v3.0 +.. note:: dj-rest-auth supports django-rest-framework >= v3.0 |build-status| |coverage-status| |requirements-status| |docs| From 60e0ca468da09773023ab3489631303f729bcc9a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:27:00 -0600 Subject: [PATCH 075/216] Updates Docs --- docs/index.rst | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 8deb445..c3de8ce 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,7 +10,8 @@ Welcome to dj-rest-auth's documentation! .. note:: dj-rest-auth supports django-rest-framework >= v3.0 -|build-status| |coverage-status| |requirements-status| |docs| +.. image:: https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg + :target: https://circleci.com/gh/iMerica/dj-rest-auth Contents -------- @@ -25,27 +26,3 @@ Contents Demo project FAQ Changelog - - -.. |build-status| image:: https://travis-ci.org/iMerica/dj-rest-auth.svg?branch=master - :alt: build status - :scale: 100% - :target: https://travis-ci.org/iMerica/dj-rest-auth - - -.. |coverage-status| image:: https://coveralls.io/repos/iMerica/dj-rest-auth/badge.png?branch=master - :alt: coverage status - :scale: 100% - :target: https://coveralls.io/r/iMerica/dj-rest-auth?branch=master - - -.. |requirements-status| image:: https://requires.io/github/iMerica/dj-rest-auth/requirements.png?branch=master - :alt: requirements status - :scale: 100% - :target: https://requires.io/github/iMerica/dj-rest-auth/requirements/?branch=master - - -.. |docs| image:: https://readthedocs.org/projects/dj-rest-auth/badge/?version=latest - :scale: 100% - :target: https://readthedocs.org/projects/dj-rest-auth/?badge=latest - :alt: Documentation Status From 9b78f0e3be37a9147890a2f1fe43b9fc11e055e6 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:40:44 -0600 Subject: [PATCH 076/216] Updates change log --- docs/changelog.rst | 118 +-------------------------------------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 2bb3f4c..42d36bc 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,120 +1,6 @@ Changelog ========= -0.9.5 +0.1.2 ----- -- fixed package distribution issue - -0.9.4 ------ -- Compatibility fixes (#437, #506) -- JWT auth cookie fix (#345) -- config & packaging fixes -- updated docs -- added new translations (Czech, Chinese, Turkish, Korean) - -0.9.3 ------ -- added social connect views -- added check for pre-existing accounts in social login -- prevent double-validation in LoginSerializer -- unit tests and demo project changes for Django 2.0 - -0.9.2 ------ -- added permission classes configuration for registration -- added more info to JWT docs -- added Polish translations - -0.9.1 ------ -- fixed import error when extending dj_rest_auth serializers -- added sensitive fields decorator -- added Spanish translations - -0.9.0 ------ -- allowed using custom UserDetailsSerializer with JWTSerializer -- fixed error with logout on GET -- updated api endpoints and configuration docs -- bugfixes -- minor text fixes - -0.8.2 ------ -- fixed allauth import error -- added swagger docs to demo project - -0.8.1 ------ -- added support for django-allauth hmac email confirmation pattern - -0.8.0 ------ -- added support for django-rest-framework-jwt -- bugfixes - -0.7.0 ------ -- Wrapped API returned strings in ugettext_lazy -- Fixed not using ``get_username`` which caused issues when using custom user model without username field -- Django 1.9 support -- Added ``TwitterLoginSerializer`` - -0.6.0 ------ -- dropped support for Python 2.6 -- dropped support for Django 1.6 -- fixed demo code -- added better validation support for serializers -- added optional logout after password change -- compatibility fixes -- bugfixes - -0.5.0 ------ -- replaced request.DATA with request.data for compatibility with DRF 3.2 -- authorization codes for social login -- view classes rename (appended "View" to all of them) -- bugfixes - -0.4.0 ------ -- Django 1.8 compatiblity fixes - -0.3.4 ------ -- fixed bug in PasswordResetConfirmation serializer (token field wasn't validated) -- fixed bug in Register view - -0.3.3 ------ - -- support django-rest-framework v3.0 - -0.3.2 ------ - -- fixed few minor bugs - -0.3.1 ------ - -- added old_password field in PasswordChangeSerializer -- make all endpoints browsable -- removed LoggedInRESTAPIView, LoggedOutRESTAPIView -- fixed minor bugs - -0.3.0 ------ - -- replaced ``django-registration`` with ``django-allauth`` -- moved registration logic to separated django application (``dj_rest_auth.registration``) -- added serializers customization in django settings -- added social media authentication view -- changed request method from GET to POST in logout endpoint -- changed request method from POST to PUT/PATCH for user details edition -- changed password reset confim url - uid and token should be sent in POST -- increase test coverage -- made compatibile with django 1.7 -- removed user profile support +Welcome Dj-Rest-Auth \ No newline at end of file From 8bc9ba8c8aa968fd04c4d67b46c0e8c40f46101c Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 29 Feb 2020 23:56:21 -0600 Subject: [PATCH 077/216] Fixes references to serializers + isort --- demo/demo/urls.py | 3 +- demo/demo/wsgi.py | 4 +- dj_rest_auth/app_settings.py | 40 ++++++++++---------- dj_rest_auth/models.py | 2 - dj_rest_auth/registration/app_settings.py | 11 +++--- dj_rest_auth/registration/serializers.py | 6 +-- dj_rest_auth/registration/urls.py | 2 +- dj_rest_auth/registration/views.py | 46 +++++++++++------------ dj_rest_auth/serializers.py | 7 ++-- dj_rest_auth/social_serializers.py | 1 + dj_rest_auth/tests/mixins.py | 6 +-- dj_rest_auth/tests/settings.py | 2 +- dj_rest_auth/tests/test_api.py | 14 +++---- dj_rest_auth/tests/test_social.py | 15 ++++---- dj_rest_auth/tests/urls.py | 26 ++++++------- dj_rest_auth/urls.py | 8 ++-- dj_rest_auth/utils.py | 11 ++++++ dj_rest_auth/views.py | 23 +++++------- docs/conf.py | 2 +- runtests.py | 7 ++-- setup.py | 4 +- 21 files changed, 119 insertions(+), 121 deletions(-) diff --git a/demo/demo/urls.py b/demo/demo/urls.py index 787c6e9..4f63ba1 100644 --- a/demo/demo/urls.py +++ b/demo/demo/urls.py @@ -1,7 +1,6 @@ from django.conf.urls import include, url from django.contrib import admin -from django.views.generic import TemplateView, RedirectView - +from django.views.generic import RedirectView, TemplateView from rest_framework_swagger.views import get_swagger_view urlpatterns = [ diff --git a/demo/demo/wsgi.py b/demo/demo/wsgi.py index ef48754..863501d 100644 --- a/demo/demo/wsgi.py +++ b/demo/demo/wsgi.py @@ -8,7 +8,9 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ """ import os -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") + application = get_wsgi_application() diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index 7f8094f..d89202d 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -1,34 +1,36 @@ +from dj_rest_auth.serializers import JWTSerializer as DefaultJWTSerializer +from dj_rest_auth.serializers import LoginSerializer as DefaultLoginSerializer +from dj_rest_auth.serializers import \ + PasswordChangeSerializer as DefaultPasswordChangeSerializer +from dj_rest_auth.serializers import \ + PasswordResetConfirmSerializer as DefaultPasswordResetConfirmSerializer +from dj_rest_auth.serializers import \ + PasswordResetSerializer as DefaultPasswordResetSerializer +from dj_rest_auth.serializers import TokenSerializer as DefaultTokenSerializer +from dj_rest_auth.serializers import \ + UserDetailsSerializer as DefaultUserDetailsSerializer from django.conf import settings -from dj_rest_auth.serializers import ( - TokenSerializer as DefaultTokenSerializer, - JWTSerializer as DefaultJWTSerializer, - UserDetailsSerializer as DefaultUserDetailsSerializer, - LoginSerializer as DefaultLoginSerializer, - PasswordResetSerializer as DefaultPasswordResetSerializer, - PasswordResetConfirmSerializer as DefaultPasswordResetConfirmSerializer, - PasswordChangeSerializer as DefaultPasswordChangeSerializer) -from .utils import default_create_token +from .utils import default_create_token, import_callable -create_token = getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token) +create_token = import_callable(getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token)) serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {}) -TokenSerializer = serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer) +TokenSerializer = import_callable(serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer)) -JWTSerializer = serializers.get('JWT_SERIALIZER', DefaultJWTSerializer) +JWTSerializer = import_callable(serializers.get('JWT_SERIALIZER', DefaultJWTSerializer)) -UserDetailsSerializer = serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer) +UserDetailsSerializer = import_callable(serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer)) -LoginSerializer = serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer) +LoginSerializer = import_callable(serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer)) -PasswordResetSerializer = serializers.get( - 'PASSWORD_RESET_SERIALIZER', - DefaultPasswordResetSerializer - ) +PasswordResetSerializer = import_callable(serializers.get( + 'PASSWORD_RESET_SERIALIZER', DefaultPasswordResetSerializer +)) PasswordResetConfirmSerializer = serializers.get( 'PASSWORD_RESET_CONFIRM_SERIALIZER', DefaultPasswordResetConfirmSerializer ) -PasswordChangeSerializer = serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer) +PasswordChangeSerializer = import_callable(serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)) diff --git a/dj_rest_auth/models.py b/dj_rest_auth/models.py index 5f690da..654c0ae 100644 --- a/dj_rest_auth/models.py +++ b/dj_rest_auth/models.py @@ -1,8 +1,6 @@ from django.conf import settings - from rest_framework.authtoken.models import Token as DefaultTokenModel - # Register your models here. TokenModel = getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel) diff --git a/dj_rest_auth/registration/app_settings.py b/dj_rest_auth/registration/app_settings.py index fdeae83..bbc7075 100644 --- a/dj_rest_auth/registration/app_settings.py +++ b/dj_rest_auth/registration/app_settings.py @@ -1,14 +1,13 @@ -from django.conf import settings - -from rest_framework.permissions import AllowAny -from dj_rest_auth.registration.serializers import ( +from dj_rest_auth.registration.serializers import \ RegisterSerializer as DefaultRegisterSerializer -) +from django.conf import settings +from rest_framework.permissions import AllowAny +from ..utils import import_callable serializers = getattr(settings, 'REST_AUTH_REGISTER_SERIALIZERS', {}) -RegisterSerializer = serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer) +RegisterSerializer = import_callable(serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer)) def register_permission_classes(): diff --git a/dj_rest_auth/registration/serializers.py b/dj_rest_auth/registration/serializers.py index 4f99c18..fc7c92b 100644 --- a/dj_rest_auth/registration/serializers.py +++ b/dj_rest_auth/registration/serializers.py @@ -1,6 +1,8 @@ +from django.contrib.auth import get_user_model from django.http import HttpRequest from django.utils.translation import ugettext_lazy as _ -from django.contrib.auth import get_user_model +from requests.exceptions import HTTPError +from rest_framework import serializers try: from allauth.account import app_settings as allauth_settings @@ -14,8 +16,6 @@ try: except ImportError: raise ImportError("allauth needs to be added to INSTALLED_APPS.") -from rest_framework import serializers -from requests.exceptions import HTTPError class SocialAccountSerializer(serializers.ModelSerializer): diff --git a/dj_rest_auth/registration/urls.py b/dj_rest_auth/registration/urls.py index 1004695..c42cec6 100644 --- a/dj_rest_auth/registration/urls.py +++ b/dj_rest_auth/registration/urls.py @@ -1,5 +1,5 @@ -from django.views.generic import TemplateView from django.conf.urls import url +from django.views.generic import TemplateView from .views import RegisterView, VerifyEmailView diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index f8d1120..81ed1ea 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -1,34 +1,30 @@ +from allauth.account import app_settings as allauth_settings +from allauth.account.adapter import get_adapter +from allauth.account.utils import complete_signup +from allauth.account.views import ConfirmEmailView +from allauth.socialaccount import signals +from allauth.socialaccount.adapter import get_adapter as get_social_adapter +from allauth.socialaccount.models import SocialAccount +from dj_rest_auth.app_settings import (JWTSerializer, TokenSerializer, + create_token) +from dj_rest_auth.models import TokenModel +from dj_rest_auth.registration.serializers import (SocialAccountSerializer, + SocialConnectSerializer, + SocialLoginSerializer, + VerifyEmailSerializer) +from dj_rest_auth.utils import jwt_encode +from dj_rest_auth.views import LoginView from django.conf import settings from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.decorators.debug import sensitive_post_parameters - -from rest_framework.views import APIView -from rest_framework.response import Response -from rest_framework.permissions import (AllowAny, - IsAuthenticated) -from rest_framework.generics import CreateAPIView, ListAPIView, GenericAPIView -from rest_framework.exceptions import NotFound from rest_framework import status +from rest_framework.exceptions import NotFound +from rest_framework.generics import CreateAPIView, GenericAPIView, ListAPIView +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView -from allauth.account.adapter import get_adapter -from allauth.account.views import ConfirmEmailView -from allauth.account.utils import complete_signup -from allauth.account import app_settings as allauth_settings -from allauth.socialaccount import signals -from allauth.socialaccount.adapter import get_adapter as get_social_adapter -from allauth.socialaccount.models import SocialAccount - -from dj_rest_auth.app_settings import (TokenSerializer, - JWTSerializer, - create_token) -from dj_rest_auth.models import TokenModel -from dj_rest_auth.registration.serializers import (VerifyEmailSerializer, - SocialLoginSerializer, - SocialAccountSerializer, - SocialConnectSerializer) -from dj_rest_auth.utils import jwt_encode -from dj_rest_auth.views import LoginView from .app_settings import RegisterSerializer, register_permission_classes sensitive_post_parameters_m = method_decorator( diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index da8fef7..07783da 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -1,12 +1,11 @@ -from django.contrib.auth import get_user_model, authenticate from django.conf import settings +from django.contrib.auth import authenticate, get_user_model from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm from django.contrib.auth.tokens import default_token_generator +from django.utils.encoding import force_text from django.utils.http import urlsafe_base64_decode as uid_decoder from django.utils.translation import ugettext_lazy as _ -from django.utils.encoding import force_text - -from rest_framework import serializers, exceptions +from rest_framework import exceptions, serializers from rest_framework.exceptions import ValidationError from .models import TokenModel diff --git a/dj_rest_auth/social_serializers.py b/dj_rest_auth/social_serializers.py index 6f8a449..60b0c2c 100644 --- a/dj_rest_auth/social_serializers.py +++ b/dj_rest_auth/social_serializers.py @@ -1,6 +1,7 @@ from django.conf import settings from django.http import HttpRequest from rest_framework import serializers + # Import is needed only if we are using social login, in which # case the allauth.socialaccount will be declared if 'allauth.socialaccount' in settings.INSTALLED_APPS: diff --git a/dj_rest_auth/tests/mixins.py b/dj_rest_auth/tests/mixins.py index 30b3d58..06d776d 100644 --- a/dj_rest_auth/tests/mixins.py +++ b/dj_rest_auth/tests/mixins.py @@ -1,11 +1,9 @@ import json from django.conf import settings -from django.test.client import Client, MULTIPART_CONTENT +from django.test.client import MULTIPART_CONTENT, Client from django.utils.encoding import force_text - -from rest_framework import status -from rest_framework import permissions +from rest_framework import permissions, status try: from django.urls import reverse diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index f683ce0..d18f41e 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -1,6 +1,6 @@ +import logging import os import sys -import logging PROJECT_ROOT = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0]) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index b6d84f2..585b38d 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -1,17 +1,15 @@ -from django.test import TestCase, override_settings +from allauth.account import app_settings as account_app_settings +from dj_rest_auth.registration.app_settings import register_permission_classes +from dj_rest_auth.registration.views import RegisterView +from django.conf import settings from django.contrib.auth import get_user_model from django.core import mail -from django.conf import settings +from django.test import TestCase, override_settings from django.utils.encoding import force_text - -from allauth.account import app_settings as account_app_settings from rest_framework import status from rest_framework.test import APIRequestFactory -from dj_rest_auth.registration.views import RegisterView -from dj_rest_auth.registration.app_settings import register_permission_classes - -from .mixins import TestsMixin, CustomPermissionClass +from .mixins import CustomPermissionClass, TestsMixin try: from django.urls import reverse diff --git a/dj_rest_auth/tests/test_social.py b/dj_rest_auth/tests/test_social.py index 830e631..47c8d93 100644 --- a/dj_rest_auth/tests/test_social.py +++ b/dj_rest_auth/tests/test_social.py @@ -1,22 +1,23 @@ import json -from django.test import TestCase +import responses +from allauth.socialaccount.models import SocialApp +from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL from django.contrib.auth import get_user_model -from django.test.utils import override_settings from django.contrib.sites.models import Site +from django.test import TestCase +from django.test.utils import override_settings +from rest_framework import status + +from .mixins import TestsMixin try: from django.urls import reverse except ImportError: from django.core.urlresolvers import reverse -from allauth.socialaccount.models import SocialApp -from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL -import responses -from rest_framework import status -from .mixins import TestsMixin @override_settings(ROOT_URLCONF="tests.urls") diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index 5aa37c1..be199a5 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -1,20 +1,18 @@ -from django.conf.urls import url, include -from django.views.generic import TemplateView -from . import django_urls - -from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter +from allauth.socialaccount.providers.facebook.views import \ + FacebookOAuth2Adapter from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter - +from dj_rest_auth.registration.views import (SocialAccountDisconnectView, + SocialAccountListView, + SocialConnectView, + SocialLoginView) +from dj_rest_auth.social_serializers import (TwitterConnectSerializer, + TwitterLoginSerializer) +from dj_rest_auth.urls import urlpatterns +from django.conf.urls import include, url +from django.views.generic import TemplateView from rest_framework.decorators import api_view -from dj_rest_auth.urls import urlpatterns -from dj_rest_auth.registration.views import ( - SocialLoginView, SocialConnectView, SocialAccountListView, - SocialAccountDisconnectView -) -from dj_rest_auth.social_serializers import ( - TwitterLoginSerializer, TwitterConnectSerializer -) +from . import django_urls class FacebookLogin(SocialLoginView): diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 6664722..d3bfc42 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -1,10 +1,8 @@ +from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView, + PasswordResetConfirmView, PasswordResetView, + UserDetailsView) from django.conf.urls import url -from dj_rest_auth.views import ( - LoginView, LogoutView, UserDetailsView, PasswordChangeView, - PasswordResetView, PasswordResetConfirmView -) - urlpatterns = [ # URLs that do not require a session or valid token url(r'^password/reset/$', PasswordResetView.as_view(), diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index b69dae0..b4858c8 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -1,3 +1,14 @@ +from importlib import import_module + + +def import_callable(path_or_callable): + if hasattr(path_or_callable, '__call__'): + return path_or_callable + else: + assert isinstance(path_or_callable, str) + package, attr = path_or_callable.rsplit('.', 1) + return getattr(import_module(package), attr) + def default_create_token(token_model, user, serializer): token, _ = token_model.objects.get_or_create(user=user) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 0a27f8e..b3b8f22 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -1,25 +1,22 @@ -from django.contrib.auth import ( - login as django_login, - logout as django_logout -) from django.conf import settings from django.contrib.auth import get_user_model +from django.contrib.auth import login as django_login +from django.contrib.auth import logout as django_logout from django.core.exceptions import ObjectDoesNotExist from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.decorators.debug import sensitive_post_parameters - from rest_framework import status -from rest_framework.views import APIView -from rest_framework.response import Response from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView -from rest_framework.permissions import IsAuthenticated, AllowAny +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView -from .app_settings import ( - TokenSerializer, UserDetailsSerializer, LoginSerializer, - PasswordResetSerializer, PasswordResetConfirmSerializer, - PasswordChangeSerializer, JWTSerializer, create_token -) +from .app_settings import (JWTSerializer, LoginSerializer, + PasswordChangeSerializer, + PasswordResetConfirmSerializer, + PasswordResetSerializer, TokenSerializer, + UserDetailsSerializer, create_token) from .models import TokenModel from .utils import jwt_encode diff --git a/docs/conf.py b/docs/conf.py index dd54bb6..7730562 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,8 +12,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the diff --git a/runtests.py b/runtests.py index 04dfa7c..3cb605b 100644 --- a/runtests.py +++ b/runtests.py @@ -3,13 +3,14 @@ import os import sys +import django +from django.conf import settings +from django.test.utils import get_runner + os.environ['DJANGO_SETTINGS_MODULE'] = 'dj_rest_auth.tests.settings' test_dir = os.path.join(os.path.dirname(__file__), 'dj_rest_auth') sys.path.insert(0, test_dir) -import django -from django.test.utils import get_runner -from django.conf import settings def runtests(): diff --git a/setup.py b/setup.py index b00ff9e..4bbfac8 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ #!/usr/bin/env python import os -from setuptools import setup, find_packages +from setuptools import find_packages, setup here = os.path.dirname(os.path.abspath(__file__)) f = open(os.path.join(here, 'README.md')) @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.1.2', + version='0.1.3', author='iMerica', author_email='imichael@pm.me', url='http://github.com/iMerica/dj-rest-auth', From 38945e871c5844cae71e444ede35f58af85866c3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 1 Mar 2020 00:06:45 -0600 Subject: [PATCH 078/216] Updates README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 268c56a..e6b1e40 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ [![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/iMerica/dj-rest-auth/pipelines) -Drop-in API endpoints for authentication in Django Rest Framework. +Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well +with with SPAs (e.g React, Vue, Angular), and Mobile applications. ## Requirements - Django 2 or 3. From 3c30c399da43e54ce3ff8b320158d07cb83b1b81 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 1 Mar 2020 00:07:36 -0600 Subject: [PATCH 079/216] Corrects grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6b1e40..56d4315 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well -with with SPAs (e.g React, Vue, Angular), and Mobile applications. +with SPAs (e.g React, Vue, Angular), and Mobile applications. ## Requirements - Django 2 or 3. From d90e3db7eb4a3471ab853818bedce75798096cd3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 1 Mar 2020 16:42:28 -0600 Subject: [PATCH 080/216] Uses new org --- AUTHORS | 2 +- demo/templates/base.html | 2 +- dj_rest_auth/locale/cs/LC_MESSAGES/django.po | 8 ++++---- dj_rest_auth/views.py | 1 - docs/api_endpoints.rst | 2 +- docs/demo.rst | 2 +- setup.py | 4 ++-- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/AUTHORS b/AUTHORS index c5ba2ed..e41efa7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1 @@ -http://github.com/iMerica/dj-rest-auth/contributors +http://github.com/jazzband/dj-rest-auth/contributors diff --git a/demo/templates/base.html b/demo/templates/base.html index 47e4e64..d57ece3 100644 --- a/demo/templates/base.html +++ b/demo/templates/base.html @@ -59,7 +59,7 @@ diff --git a/dj_rest_auth/locale/cs/LC_MESSAGES/django.po b/dj_rest_auth/locale/cs/LC_MESSAGES/django.po index e6acf92..90e6f71 100644 --- a/dj_rest_auth/locale/cs/LC_MESSAGES/django.po +++ b/dj_rest_auth/locale/cs/LC_MESSAGES/django.po @@ -1,11 +1,11 @@ -# Czech translations of iMerica/dj-rest-auth +# Czech translations of jazzband/dj-rest-auth # -# This file is distributed under the same license as the iMerica/dj-rest-auth package. +# This file is distributed under the same license as the jazzband/dj-rest-auth package. # msgid "" msgstr "" -"Project-Id-Version: iMerica/dj-rest-auth\n" -"Report-Msgid-Bugs-To: https://github.com/iMerica/dj-rest-auth/issues\n" +"Project-Id-Version: jazzband/dj-rest-auth\n" +"Report-Msgid-Bugs-To: https://github.com/jazzband/dj-rest-auth/issues\n" "POT-Creation-Date: 2018-06-27 23:05+0200\n" "PO-Revision-Date: 2018-06-27 23:22+0200\n" "Language: cs\n" diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index b3b8f22..c5bcb1a 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -161,7 +161,6 @@ class UserDetailsView(RetrieveUpdateAPIView): """ Adding this method since it is sometimes called when using django-rest-swagger - https://github.com/iMerica/dj-rest-auth/issues/275 """ return get_user_model().objects.none() diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index f23dabd..a4e602a 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -72,7 +72,7 @@ Basing on example from installation section :doc:`Installation ` - access_token - code - .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/iMerica/dj-rest-auth/blob/master/dj_rest_auth/registration/views.py + .. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/jazzband/dj-rest-auth/blob/master/dj_rest_auth/registration/views.py - /dj-rest-auth/twitter/ (POST) diff --git a/docs/demo.rst b/docs/demo.rst index 22620f8..ecceddd 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -8,7 +8,7 @@ Do these steps to make it running (ideally in virtualenv). .. code-block:: python cd /tmp - git clone https://github.com/iMerica/dj-rest-auth.git + git clone https://github.com/jazzband/dj-rest-auth.git cd dj-rest-auth/demo/ pip install -r requirements.pip python manage.py migrate --settings=demo.settings --noinput diff --git a/setup.py b/setup.py index 4bbfac8..e4f3ec9 100644 --- a/setup.py +++ b/setup.py @@ -12,10 +12,10 @@ f.close() setup( name='dj-rest-auth', - version='0.1.3', + version='0.1.4', author='iMerica', author_email='imichael@pm.me', - url='http://github.com/iMerica/dj-rest-auth', + url='http://github.com/jazzband/dj-rest-auth', description='Authentication and Registration in Django Rest Framework', packages=find_packages(), long_description=long_description, From 238b92b472c5473d0a4fc01b993359525f4ded9d Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 1 Mar 2020 16:46:47 -0600 Subject: [PATCH 081/216] Updates Circle CI badge --- README.md | 2 +- docs/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 56d4315..ec7ae1d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Dj-Rest-Auth -[![](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/iMerica/dj-rest-auth/pipelines) +[![](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/jazzband/dj-rest-auth/pipelines) Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well diff --git a/docs/index.rst b/docs/index.rst index c3de8ce..82118cc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,8 +10,8 @@ Welcome to dj-rest-auth's documentation! .. note:: dj-rest-auth supports django-rest-framework >= v3.0 -.. image:: https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg - :target: https://circleci.com/gh/iMerica/dj-rest-auth +.. image:: https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg + :target: https://circleci.com/gh/jazzband/dj-rest-auth Contents -------- From c35773d786b7cecc6d1d8ed6763d94bec85db36c Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Mar 2020 17:47:44 -0600 Subject: [PATCH 082/216] Adds Jazzband badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ec7ae1d..46af4d8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Dj-Rest-Auth [![](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/jazzband/dj-rest-auth/pipelines) +[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/) Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well From b5914dbb4597624dca62ada0351dd99d69249907 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Mar 2020 17:48:57 -0600 Subject: [PATCH 083/216] Adds contributing file --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..10d7919 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/) + +This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/about/conduct) and follow the [guidelines](https://jazzband.co/about/guidelines). \ No newline at end of file From fe01ba02314a66bbe684ec52b88acc8278e33721 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Mar 2020 17:56:32 -0600 Subject: [PATCH 084/216] Adds coverage badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46af4d8..3ec4ef7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Dj-Rest-Auth [![](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/jazzband/dj-rest-auth/pipelines) [![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/) - +[![Coverage Status](https://coveralls.io/repos/github/jazzband/dj-rest-auth/badge.svg?branch=master)](https://coveralls.io/github/jazzband/dj-rest-auth?branch=master) Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well with SPAs (e.g React, Vue, Angular), and Mobile applications. From 3b830790f7ddf2aa16780fd54887524cdc4a5c02 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Mar 2020 18:01:31 -0600 Subject: [PATCH 085/216] Adds coveralls dep and tests --- .circleci/config.yml | 3 +++ dev-requirements.txt | 1 + setup.py | 1 + 3 files changed, 5 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 75c5e48..5830b0b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,6 +18,9 @@ jobs: - run: command: coverage run --source=dj_rest_auth setup.py test name: Test + - run: + command: coveralls + name: Coverage test-django-2: <<: *template environment: diff --git a/dev-requirements.txt b/dev-requirements.txt index 0a2a9e4..9d2af20 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,3 +2,4 @@ responses>=0.5.0 djangorestframework-jwt django-allauth +coveralls>=1.11.1 \ No newline at end of file diff --git a/setup.py b/setup.py index e4f3ec9..94aad46 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ setup( 'responses>=0.5.0', 'django-allauth>=0.25.0', 'djangorestframework-jwt>=1.9.0', + 'coveralls>=1.11.1' ], test_suite='runtests.runtests', include_package_data=True, From a4915a1ea8d92ad6baea35c55a84164767c65607 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Mar 2020 18:04:47 -0600 Subject: [PATCH 086/216] Adds coverage repo token --- .circleci/config.yml | 2 +- .coveralls.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .coveralls.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 5830b0b..d124869 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ jobs: command: coverage run --source=dj_rest_auth setup.py test name: Test - run: - command: coveralls + command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage test-django-2: <<: *template diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..16eb397 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,2 @@ +service_name: travis-pro +repo_token: Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 \ No newline at end of file From 229b75543e1454331649c098f7ebd4e3f2e5d8bd Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 10 Mar 2020 22:44:21 -0500 Subject: [PATCH 087/216] Updates version in demo project --- demo/requirements.pip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index ab0a814..7442229 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ django>=1.9.0 -dj-rest-auth==0.9.5 +dj-rest-auth==0.1.4 djangorestframework>=3.7.0 django-allauth>=0.24.1 django-rest-swagger==2.0.7 From 9bbc4a3014df5d1da3771bbd1c7170a976f66842 Mon Sep 17 00:00:00 2001 From: alichass Date: Wed, 11 Mar 2020 06:01:03 -0400 Subject: [PATCH 088/216] change standard auth stuff to work with simplejwt --- dj_rest_auth/serializers.py | 3 ++- dj_rest_auth/utils.py | 12 +++++------- dj_rest_auth/views.py | 18 +++--------------- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index 07783da..b34c9cc 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -135,7 +135,8 @@ class JWTSerializer(serializers.Serializer): """ Serializer for JWT authentication. """ - token = serializers.CharField() + access_token = serializers.CharField() + refresh_token = serializers.CharField() user = serializers.SerializerMethodField() def get_user(self, obj): diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index b4858c8..165963d 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -17,12 +17,10 @@ def default_create_token(token_model, user, serializer): def jwt_encode(user): try: - from rest_framework_jwt.settings import api_settings + from rest_framework_simplejwt.serializers import TokenObtainPairSerializer + from rest_framework_simplejwt.views import TokenObtainPairView except ImportError: - raise ImportError("djangorestframework_jwt needs to be installed") + raise ImportError("rest-framework-simplejwt needs to be installed") - jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER - jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER - - payload = jwt_payload_handler(user) - return jwt_encode_handler(payload) + refresh = TokenObtainPairSerializer.get_token(user) + return refresh.access_token, refresh diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index c5bcb1a..f30980c 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -59,7 +59,7 @@ class LoginView(GenericAPIView): self.user = self.serializer.validated_data['user'] if getattr(settings, 'REST_USE_JWT', False): - self.token = jwt_encode(self.user) + self.access_token, self.refresh_token = jwt_encode(self.user) else: self.token = create_token(self.token_model, self.user, self.serializer) @@ -73,7 +73,8 @@ class LoginView(GenericAPIView): if getattr(settings, 'REST_USE_JWT', False): data = { 'user': self.user, - 'token': self.token + 'access_token': self.access_token, + 'refresh_token': self.refresh_token } serializer = serializer_class(instance=data, context={'request': self.request}) @@ -82,15 +83,6 @@ class LoginView(GenericAPIView): context={'request': self.request}) response = Response(serializer.data, status=status.HTTP_200_OK) - if getattr(settings, 'REST_USE_JWT', False): - from rest_framework_jwt.settings import api_settings as jwt_settings - if jwt_settings.JWT_AUTH_COOKIE: - from datetime import datetime - expiration = (datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA) - response.set_cookie(jwt_settings.JWT_AUTH_COOKIE, - self.token, - expires=expiration, - httponly=True) return response def post(self, request, *args, **kwargs): @@ -133,10 +125,6 @@ class LogoutView(APIView): response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) - if getattr(settings, 'REST_USE_JWT', False): - from rest_framework_jwt.settings import api_settings as jwt_settings - if jwt_settings.JWT_AUTH_COOKIE: - response.delete_cookie(jwt_settings.JWT_AUTH_COOKIE) return response From 4fb746e6455bdb78ca1421f53c2d4c86006fbcd3 Mon Sep 17 00:00:00 2001 From: alichass Date: Wed, 11 Mar 2020 06:03:59 -0400 Subject: [PATCH 089/216] updated tests --- dj_rest_auth/tests/settings.py | 4 +--- dj_rest_auth/tests/test_api.py | 8 ++++---- dj_rest_auth/tests/test_social.py | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index d18f41e..7279c21 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -68,7 +68,7 @@ TEMPLATES = [ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', - 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', ) } @@ -94,8 +94,6 @@ INSTALLED_APPS = [ 'dj_rest_auth', 'dj_rest_auth.registration', - - 'rest_framework_jwt' ] SECRET_KEY = "38dh*skf8sjfhs287dh&^hd8&3hdg*j2&sd" diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 585b38d..5d06fac 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -152,8 +152,8 @@ class APIBasicTests(TestsMixin, TestCase): get_user_model().objects.create_user(self.USERNAME, '', self.PASS) self.post(self.login_url, data=payload, status_code=200) - self.assertEqual('token' in self.response.json.keys(), True) - self.token = self.response.json['token'] + self.assertEqual('access_token' in self.response.json.keys(), True) + self.token = self.response.json['access_token'] def test_login_by_email(self): # starting test without allauth app @@ -382,7 +382,7 @@ class APIBasicTests(TestsMixin, TestCase): "password": self.PASS } self.post(self.login_url, data=payload, status_code=200) - self.token = self.response.json['token'] + self.token = self.response.json['access_token'] self.get(self.user_url, status_code=200) self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) @@ -426,7 +426,7 @@ class APIBasicTests(TestsMixin, TestCase): self.post(self.register_url, data={}, status_code=400) result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) - self.assertIn('token', result.data) + self.assertIn('access_token', result.data) self.assertEqual(get_user_model().objects.all().count(), user_count + 1) self._login() diff --git a/dj_rest_auth/tests/test_social.py b/dj_rest_auth/tests/test_social.py index 47c8d93..cceba3f 100644 --- a/dj_rest_auth/tests/test_social.py +++ b/dj_rest_auth/tests/test_social.py @@ -305,7 +305,7 @@ class TestSocialAuth(TestsMixin, TestCase): } self.post(self.fb_login_url, data=payload, status_code=200) - self.assertIn('token', self.response.json.keys()) + self.assertIn('access_token', self.response.json.keys()) self.assertIn('user', self.response.json.keys()) self.assertEqual(get_user_model().objects.all().count(), users_count + 1) From 23e88f9838f421b6f85471b51d9fafcf1fc7c7c0 Mon Sep 17 00:00:00 2001 From: alichass Date: Wed, 11 Mar 2020 06:05:11 -0400 Subject: [PATCH 090/216] update registration views to work with simplejwt --- dj_rest_auth/registration/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index 81ed1ea..e9577a1 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -49,7 +49,8 @@ class RegisterView(CreateAPIView): if getattr(settings, 'REST_USE_JWT', False): data = { 'user': user, - 'token': self.token + 'access_token': self.access_token, + 'refresh_token': self.refresh_token } return JWTSerializer(data).data else: @@ -68,7 +69,7 @@ class RegisterView(CreateAPIView): def perform_create(self, serializer): user = serializer.save(self.request) if getattr(settings, 'REST_USE_JWT', False): - self.token = jwt_encode(user) + self.access_token, self.refresh_token = jwt_encode(user) else: create_token(self.token_model, user, serializer) From 231ccc04a38eb1fc4a21545f75d6b0c4c70760b6 Mon Sep 17 00:00:00 2001 From: alichass Date: Wed, 11 Mar 2020 06:15:32 -0400 Subject: [PATCH 091/216] updated docs --- docs/configuration.rst | 2 +- docs/installation.rst | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index b988a76..af858c0 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -46,7 +46,7 @@ Configuration - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) -- **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of django-rest-framework-jwt http://getblimp.github.io/django-rest-framework-jwt/, which must also be installed. (default: False) +- **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of djangorestframework-simplejwt https://github.com/SimpleJWT/django-rest-framework-simplejwt, which must also be installed. (default: False) - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) diff --git a/docs/installation.rst b/docs/installation.rst index cba551e..5004752 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -248,12 +248,23 @@ JSON Web Token (JWT) Support (optional) By default ``dj-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps: -1. Install `djangorestframework-jwt `_ - - ``djangorestframework-jwt`` is currently the only supported JWT library. -2. The ``JWT_PAYLOAD_HANDLER`` and ``JWT_ENCODE_HANDLER`` settings are imported from the ``django-rest-framework-jwt`` settings object. - - Refer to `the library's documentation `_ for information on using different encoders. +1. Install `djangorestframework-simplejwt `_ + - ``djangorestframework-simplejwt`` is currently the only supported JWT library. -3. Add the following configuration value to your settings file to enable JWT authentication. +2. Add a simple_jwt auth configuration to the list of authentication classes. + +.. code-block:: python + + REST_FRAMEWORK = { + ... + 'DEFAULT_AUTHENTICATION_CLASSES': ( + ... + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ) + ... + } + +3. Add the following configuration value to your settings file to enable JWT authentication in dj-rest-auth. .. code-block:: python From 6dd2aea624482cc527b0e10391a56a2dd95d3423 Mon Sep 17 00:00:00 2001 From: alichass Date: Wed, 11 Mar 2020 06:22:52 -0400 Subject: [PATCH 092/216] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 94aad46..8872a56 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ setup( tests_require=[ 'responses>=0.5.0', 'django-allauth>=0.25.0', - 'djangorestframework-jwt>=1.9.0', + 'djangorestframework-simplejwt>=4.4.0 ', 'coveralls>=1.11.1' ], test_suite='runtests.runtests', From e198f8dddb9d54fd445a4bba105152ab6e5c7efe Mon Sep 17 00:00:00 2001 From: Mathias Lantean Date: Wed, 11 Mar 2020 15:23:22 -0300 Subject: [PATCH 093/216] Fix if condition in LoginSerializer As there is no reference to 'rest_auth.registration' this condition always validates to False. We should check if 'dj_rest_auth.registration' is in INSTALLED_APPS. --- dj_rest_auth/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index 07783da..91c7b8a 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -100,7 +100,7 @@ class LoginSerializer(serializers.Serializer): raise exceptions.ValidationError(msg) # If required, is the email verified? - if 'rest_auth.registration' in settings.INSTALLED_APPS: + if 'dj_rest_auth.registration' in settings.INSTALLED_APPS: from allauth.account import app_settings if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY: email_address = user.emailaddress_set.get(email=user.email) From 597d17e6ff0f84d26d42808c6dd96427b64136c0 Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Thu, 12 Mar 2020 17:22:46 +0200 Subject: [PATCH 094/216] Uncomment 'django.contrib.messages' When run 'python manage.py migrate --settings=demo.settings --noinput' I get this on console SystemCheckError: System check identified some issues: ERRORS: ?: (admin.E406) 'django.contrib.messages' must be in INSTALLED_APPS in order to use the admin application. So uncomment it to solve the issue. --- demo/demo/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index df6807a..50f5afb 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -31,7 +31,7 @@ INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - # 'django.contrib.messages', + 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', From 654eb22b7bee4a2a44252af3c14ebbd96ea18dc6 Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Thu, 12 Mar 2020 17:42:09 +0200 Subject: [PATCH 095/216] Fix AttributeError at /docs/ Using this solution https://github.com/encode/django-rest-framework/issues/6809#issuecomment-546302742 To fix: AttributeError at /docs/ 'AutoSchema' object has no attribute 'get_link' --- demo/demo/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index df6807a..1cf35f5 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -120,7 +120,8 @@ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', - ) + ), + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' } SWAGGER_SETTINGS = { From 12e79aa33ebf835579492a1dd9db970aaef4fbdc Mon Sep 17 00:00:00 2001 From: alichass Date: Thu, 19 Mar 2020 14:37:35 -0400 Subject: [PATCH 096/216] changed for use w/ cookies --- dj_rest_auth/utils.py | 1 - dj_rest_auth/views.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 165963d..85912a6 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -18,7 +18,6 @@ def default_create_token(token_model, user, serializer): def jwt_encode(user): try: from rest_framework_simplejwt.serializers import TokenObtainPairSerializer - from rest_framework_simplejwt.views import TokenObtainPairView except ImportError: raise ImportError("rest-framework-simplejwt needs to be installed") diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index f30980c..37e4880 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -83,6 +83,15 @@ class LoginView(GenericAPIView): context={'request': self.request}) response = Response(serializer.data, status=status.HTTP_200_OK) + if getattr(settings, 'REST_USE_JWT', False): + from rest_framework_simplejwt.settings import api_settings as jwt_settings + #if jwt_settings.JWT_AUTH_COOKIE #this needs to be added to simplejwt + from datetime import datetime + expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME) + response.set_cookie('somestring', #replace with jwt_settings.JWT_AUTH_COOKIE + self.access_token, + expires=expiration, + httponly=True) return response def post(self, request, *args, **kwargs): @@ -125,6 +134,10 @@ class LogoutView(APIView): response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) + if getattr(settings, 'REST_USE_JWT', False): + from rest_framework_simplejwt.settings import api_settings as jwt_settings + #if jwt_settings.JWT_AUTH_COOKIE #this needs to be added to simplejwt + response.delete_cookie('somestring') #replace with jwt_settings.JWT_AUTH_COOKIE return response From f73f3af1d3698336d0ad15dceb0add289cb2188c Mon Sep 17 00:00:00 2001 From: alichass Date: Thu, 19 Mar 2020 17:09:20 -0400 Subject: [PATCH 097/216] hopefully this should work? --- dj_rest_auth/app_settings.py | 3 +++ dj_rest_auth/tests/settings.py | 2 +- dj_rest_auth/utils.py | 30 +++++++++++++++++++++++++++++- dj_rest_auth/views.py | 22 +++++++++++----------- docs/installation.rst | 2 +- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index d89202d..39e44ef 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -34,3 +34,6 @@ PasswordResetConfirmSerializer = serializers.get( ) PasswordChangeSerializer = import_callable(serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)) + +JWT_AUTH_COOKIE = getattr(settings, 'JWT_AUTH_COOKIE', None) + diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index 7279c21..3d02309 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -68,7 +68,7 @@ TEMPLATES = [ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', - 'rest_framework_simplejwt.authentication.JWTAuthentication', + 'dj_rest_auth.utils.JWTCookieAuthentication', ) } diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 85912a6..2b8094a 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -1,5 +1,5 @@ from importlib import import_module - +from .app_settings import JWT_AUTH_COOKIE def import_callable(path_or_callable): if hasattr(path_or_callable, '__call__'): @@ -23,3 +23,31 @@ def jwt_encode(user): refresh = TokenObtainPairSerializer.get_token(user) return refresh.access_token, refresh + + +try: + from rest_framework_simplejwt.authentication import JWTAuthentication + + class JWTCookieAuthentication(JWTAuthentication): + """ + An authentication plugin that hopefully authenticates requests through a JSON web + token provided in a request cookie (and through the header as normal, with a preference to the header). + """ + def authenticate(self, request): + header = self.get_header(request) + if header is None: + if JWT_AUTH_COOKIE: # or settings.JWT_AUTH_COOKIE + raw_token = request.COOKIES.get(JWT_AUTH_COOKIE) # or settings.jwt_auth_cookie + else: + return None + else: + raw_token = self.get_raw_token(header) + + if raw_token is None: + return None + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), validated_token +except ImportError as I: + pass diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 37e4880..2896209 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -16,7 +16,7 @@ from .app_settings import (JWTSerializer, LoginSerializer, PasswordChangeSerializer, PasswordResetConfirmSerializer, PasswordResetSerializer, TokenSerializer, - UserDetailsSerializer, create_token) + UserDetailsSerializer, create_token, JWT_AUTH_COOKIE) from .models import TokenModel from .utils import jwt_encode @@ -85,13 +85,13 @@ class LoginView(GenericAPIView): response = Response(serializer.data, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): from rest_framework_simplejwt.settings import api_settings as jwt_settings - #if jwt_settings.JWT_AUTH_COOKIE #this needs to be added to simplejwt - from datetime import datetime - expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME) - response.set_cookie('somestring', #replace with jwt_settings.JWT_AUTH_COOKIE - self.access_token, - expires=expiration, - httponly=True) + if JWT_AUTH_COOKIE: #this needs to be added to simplejwt + from datetime import datetime + expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME) + response.set_cookie(JWT_AUTH_COOKIE, #this needs to be added to simplejwt + self.access_token, + expires=expiration, + httponly=True) return response def post(self, request, *args, **kwargs): @@ -135,9 +135,9 @@ class LogoutView(APIView): response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): - from rest_framework_simplejwt.settings import api_settings as jwt_settings - #if jwt_settings.JWT_AUTH_COOKIE #this needs to be added to simplejwt - response.delete_cookie('somestring') #replace with jwt_settings.JWT_AUTH_COOKIE + # from rest_framework_simplejwt.settings import api_settings as jwt_settings + if JWT_AUTH_COOKIE: #this needs to be added to simplejwt + response.delete_cookie(JWT_AUTH_COOKIE) #this needs to be added to simplejwt return response diff --git a/docs/installation.rst b/docs/installation.rst index 5004752..fa4345d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -259,7 +259,7 @@ By default ``dj-rest-auth`` uses Django's Token-based authentication. If you wan ... 'DEFAULT_AUTHENTICATION_CLASSES': ( ... - 'rest_framework_simplejwt.authentication.JWTAuthentication', + 'dj_rest_auth.utils.JWTCookieAuthentication', ) ... } From dbb3ff2b81d0eb3ba897243995f967be8c50aa76 Mon Sep 17 00:00:00 2001 From: David De Sousa Date: Sat, 21 Mar 2020 11:10:51 +0100 Subject: [PATCH 098/216] Fix typos in the registration serializer documentation --- docs/configuration.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index b988a76..5abaf4b 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -6,19 +6,19 @@ Configuration You can define your custom serializers for each endpoint without overriding urls and views by adding ``REST_AUTH_SERIALIZERS`` dictionary in your django settings. Possible key values: - - LOGIN_SERIALIZER - serializer class in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.LoginSerializer`` + - LOGIN_SERIALIZER - serializer class in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.LoginSerializer`` - - TOKEN_SERIALIZER - response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.TokenSerializer`` + - TOKEN_SERIALIZER - response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.TokenSerializer`` - - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``rest_auth.serializers.JWTSerializer`` + - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.JWTSerializer`` - - USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``rest_auth.serializers.UserDetailsSerializer`` + - USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``dj_rest_auth.serializers.UserDetailsSerializer`` - - PASSWORD_RESET_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetView``, default value ``rest_auth.serializers.PasswordResetSerializer`` + - PASSWORD_RESET_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetView``, default value ``dj_rest_auth.serializers.PasswordResetSerializer`` - - PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetConfirmView``, default value ``rest_auth.serializers.PasswordResetConfirmSerializer`` + - PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetConfirmView``, default value ``dj_rest_auth.serializers.PasswordResetConfirmSerializer`` - - PASSWORD_CHANGE_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordChangeView``, default value ``rest_auth.serializers.PasswordChangeSerializer`` + - PASSWORD_CHANGE_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordChangeView``, default value ``dj_rest_auth.serializers.PasswordChangeSerializer`` Example configuration: @@ -36,7 +36,7 @@ Configuration You can define your custom serializers for registration endpoint. Possible key values: - - REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer`` + - REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``dj_rest_auth.registration.serializers.RegisterSerializer`` .. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance From 475e0b94c2cb00e9c260cd944e91d850627fd211 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 05:41:16 -0500 Subject: [PATCH 099/216] Support for Http-Only JWT Cookies --- demo/requirements.pip | 1 + dev-requirements.txt | 2 +- dj_rest_auth/tests/requirements.pip | 3 +- dj_rest_auth/tests/test_api.py | 299 +++------------------------- dj_rest_auth/tests/test_social.py | 3 - dj_rest_auth/tests/urls.py | 12 ++ dj_rest_auth/utils.py | 15 +- dj_rest_auth/views.py | 21 +- docs/configuration.rst | 2 +- 9 files changed, 64 insertions(+), 294 deletions(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index 7442229..6d24967 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,6 @@ django>=1.9.0 dj-rest-auth==0.1.4 djangorestframework>=3.7.0 +djangorestframework-simplejwt==4.4.0 django-allauth>=0.24.1 django-rest-swagger==2.0.7 diff --git a/dev-requirements.txt b/dev-requirements.txt index 9d2af20..cee8ea6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,5 +1,5 @@ --editable . responses>=0.5.0 -djangorestframework-jwt +djangorestframework-simplejwt==4.4.0 django-allauth coveralls>=1.11.1 \ No newline at end of file diff --git a/dj_rest_auth/tests/requirements.pip b/dj_rest_auth/tests/requirements.pip index f48ee3c..4ff9b2d 100644 --- a/dj_rest_auth/tests/requirements.pip +++ b/dj_rest_auth/tests/requirements.pip @@ -1,5 +1,6 @@ django-allauth>=0.25.0 responses>=0.3.0 flake8==2.4.0 -djangorestframework-jwt>=1.7.2 +Django==3.0.4 +djangorestframework-simplejwt==4.4.0 djangorestframework>=3.6.4 diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 5d06fac..4519186 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -144,293 +144,46 @@ class APIBasicTests(TestsMixin, TestCase): self.post(self.login_url, data=payload, status_code=200) @override_settings(REST_USE_JWT=True) - def test_login_jwt(self): + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + def test_login_jwt_sets_cookie(self): payload = { "username": self.USERNAME, "password": self.PASS } get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - - self.post(self.login_url, data=payload, status_code=200) - self.assertEqual('access_token' in self.response.json.keys(), True) - self.token = self.response.json['access_token'] - - def test_login_by_email(self): - # starting test without allauth app - settings.INSTALLED_APPS.remove('allauth') - - payload = { - "email": self.EMAIL.lower(), - "password": self.PASS - } - # there is no users in db so it should throw error (400) - self.post(self.login_url, data=payload, status_code=400) - - self.post(self.password_change_url, status_code=403) - - # create user - user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) - - # test auth by email - self.post(self.login_url, data=payload, status_code=200) - self.assertEqual('key' in self.response.json.keys(), True) - self.token = self.response.json['key'] - - # test auth by email in different case - payload = { - "email": self.EMAIL.upper(), - "password": self.PASS - } - self.post(self.login_url, data=payload, status_code=200) - self.assertEqual('key' in self.response.json.keys(), True) - self.token = self.response.json['key'] - - # test inactive user - user.is_active = False - user.save() - self.post(self.login_url, data=payload, status_code=400) - - # test wrong email/password - payload = { - "email": 't' + self.EMAIL, - "password": self.PASS - } - self.post(self.login_url, data=payload, status_code=400) - - # test empty payload - self.post(self.login_url, data={}, status_code=400) - - # bring back allauth - settings.INSTALLED_APPS.append('allauth') - - def test_password_change(self): - login_payload = { - "username": self.USERNAME, - "password": self.PASS - } - get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - self.post(self.login_url, data=login_payload, status_code=200) - self.token = self.response.json['key'] - - new_password_payload = { - "new_password1": "new_person", - "new_password2": "new_person" - } - self.post( - self.password_change_url, - data=new_password_payload, - status_code=200 - ) - - # user should not be able to login using old password - self.post(self.login_url, data=login_payload, status_code=400) - - # new password should work - login_payload['password'] = new_password_payload['new_password1'] - self.post(self.login_url, data=login_payload, status_code=200) - - # pass1 and pass2 are not equal - new_password_payload = { - "new_password1": "new_person1", - "new_password2": "new_person" - } - self.post( - self.password_change_url, - data=new_password_payload, - status_code=400 - ) - - # send empty payload - self.post(self.password_change_url, data={}, status_code=400) - - @override_settings(OLD_PASSWORD_FIELD_ENABLED=True) - def test_password_change_with_old_password(self): - login_payload = { - "username": self.USERNAME, - "password": self.PASS - } - get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - self.post(self.login_url, data=login_payload, status_code=200) - self.token = self.response.json['key'] - - new_password_payload = { - "old_password": "%s!" % self.PASS, # wrong password - "new_password1": "new_person", - "new_password2": "new_person" - } - self.post( - self.password_change_url, - data=new_password_payload, - status_code=400 - ) - - new_password_payload = { - "old_password": self.PASS, - "new_password1": "new_person", - "new_password2": "new_person" - } - self.post( - self.password_change_url, - data=new_password_payload, - status_code=200 - ) - - # user should not be able to login using old password - self.post(self.login_url, data=login_payload, status_code=400) - - # new password should work - login_payload['password'] = new_password_payload['new_password1'] - self.post(self.login_url, data=login_payload, status_code=200) - - def test_password_reset(self): - user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) - - # call password reset - mail_count = len(mail.outbox) - payload = {'email': self.EMAIL} - self.post(self.password_reset_url, data=payload, status_code=200) - self.assertEqual(len(mail.outbox), mail_count + 1) - - url_kwargs = self._generate_uid_and_token(user) - url = reverse('rest_password_reset_confirm') - - # wrong token - data = { - 'new_password1': self.NEW_PASS, - 'new_password2': self.NEW_PASS, - 'uid': force_text(url_kwargs['uid']), - 'token': '-wrong-token-' - } - self.post(url, data=data, status_code=400) - - # wrong uid - data = { - 'new_password1': self.NEW_PASS, - 'new_password2': self.NEW_PASS, - 'uid': '-wrong-uid-', - 'token': url_kwargs['token'] - } - self.post(url, data=data, status_code=400) - - # wrong token and uid - data = { - 'new_password1': self.NEW_PASS, - 'new_password2': self.NEW_PASS, - 'uid': '-wrong-uid-', - 'token': '-wrong-token-' - } - self.post(url, data=data, status_code=400) - - # valid payload - data = { - 'new_password1': self.NEW_PASS, - 'new_password2': self.NEW_PASS, - 'uid': force_text(url_kwargs['uid']), - 'token': url_kwargs['token'] - } - url = reverse('rest_password_reset_confirm') - self.post(url, data=data, status_code=200) - - payload = { - "username": self.USERNAME, - "password": self.NEW_PASS - } - self.post(self.login_url, data=payload, status_code=200) - - def test_password_reset_with_email_in_different_case(self): - get_user_model().objects.create_user(self.USERNAME, self.EMAIL.lower(), self.PASS) - - # call password reset in upper case - mail_count = len(mail.outbox) - payload = {'email': self.EMAIL.upper()} - self.post(self.password_reset_url, data=payload, status_code=200) - self.assertEqual(len(mail.outbox), mail_count + 1) - - def test_password_reset_with_invalid_email(self): - """ - Invalid email should not raise error, as this would leak users - """ - get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) - - # call password reset - mail_count = len(mail.outbox) - payload = {'email': 'nonexisting@email.com'} - self.post(self.password_reset_url, data=payload, status_code=200) - self.assertEqual(len(mail.outbox), mail_count) - - def test_user_details(self): - user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) - payload = { - "username": self.USERNAME, - "password": self.PASS - } - self.post(self.login_url, data=payload, status_code=200) - self.token = self.response.json['key'] - self.get(self.user_url, status_code=200) - - self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) - user = get_user_model().objects.get(pk=user.pk) - self.assertEqual(user.first_name, self.response.json['first_name']) - self.assertEqual(user.last_name, self.response.json['last_name']) - self.assertEqual(user.email, self.response.json['email']) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertTrue('jwt-auth' in resp.cookies.keys()) @override_settings(REST_USE_JWT=True) - def test_user_details_using_jwt(self): - user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + def test_logout_jwt_deletes_cookie(self): payload = { "username": self.USERNAME, "password": self.PASS } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) self.post(self.login_url, data=payload, status_code=200) - self.token = self.response.json['access_token'] - self.get(self.user_url, status_code=200) - - self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) - user = get_user_model().objects.get(pk=user.pk) - self.assertEqual(user.email, self.response.json['email']) - - def test_registration(self): - user_count = get_user_model().objects.all().count() - - # test empty payload - self.post(self.register_url, data={}, status_code=400) - - result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) - self.assertIn('key', result.data) - self.assertEqual(get_user_model().objects.all().count(), user_count + 1) - - new_user = get_user_model().objects.latest('id') - self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) - - self._login() - self._logout() - - @override_settings(REST_AUTH_REGISTER_PERMISSION_CLASSES=(CustomPermissionClass,)) - def test_registration_with_custom_permission_class(self): - - class CustomRegisterView(RegisterView): - permission_classes = register_permission_classes() - authentication_classes = () - - factory = APIRequestFactory() - request = factory.post('/customer/details', self.REGISTRATION_DATA, format='json') - - response = CustomRegisterView.as_view()(request) - self.assertEqual(response.data['detail'], CustomPermissionClass.message) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + resp = self.post(self.logout_url, status=200) + self.assertEqual('', resp.cookies.get('jwt-auth').value) @override_settings(REST_USE_JWT=True) - def test_registration_with_jwt(self): - user_count = get_user_model().objects.all().count() - - self.post(self.register_url, data={}, status_code=400) - - result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) - self.assertIn('access_token', result.data) - self.assertEqual(get_user_model().objects.all().count(), user_count + 1) - - self._login() - self._logout() + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + def test_cookie_authentication(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) + resp = self.get('/protected-view/') + self.assertEquals(resp.status_code, 200) def test_registration_with_invalid_password(self): data = self.REGISTRATION_DATA.copy() diff --git a/dj_rest_auth/tests/test_social.py b/dj_rest_auth/tests/test_social.py index cceba3f..819b153 100644 --- a/dj_rest_auth/tests/test_social.py +++ b/dj_rest_auth/tests/test_social.py @@ -17,9 +17,6 @@ except ImportError: from django.core.urlresolvers import reverse - - - @override_settings(ROOT_URLCONF="tests.urls") class TestSocialAuth(TestsMixin, TestCase): diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index be199a5..7579e83 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -11,10 +11,21 @@ from dj_rest_auth.urls import urlpatterns from django.conf.urls import include, url from django.views.generic import TemplateView from rest_framework.decorators import api_view +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import permissions from . import django_urls +class ExampleProtectedView(APIView): + permission_classes = [permissions.IsAuthenticated] + + + def get(self, *args, **kwargs): + return Response(dict(success=True)) + + class FacebookLogin(SocialLoginView): adapter_class = FacebookOAuth2Adapter @@ -64,6 +75,7 @@ urlpatterns += [ url(r'^social-login/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect'), url(r'^social-login/twitter/connect/$', TwitterConnect.as_view(), name='tw_connect'), url(r'^socialaccounts/$', SocialAccountListView.as_view(), name='social_account_list'), + url(r'^protected-view/$', ExampleProtectedView.as_view()), url(r'^socialaccounts/(?P\d+)/disconnect/$', SocialAccountDisconnectView.as_view(), name='social_account_disconnect'), url(r'^accounts/', include('allauth.socialaccount.urls')) diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 2b8094a..7cbf3ad 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -1,5 +1,5 @@ from importlib import import_module -from .app_settings import JWT_AUTH_COOKIE + def import_callable(path_or_callable): if hasattr(path_or_callable, '__call__'): @@ -31,13 +31,16 @@ try: class JWTCookieAuthentication(JWTAuthentication): """ An authentication plugin that hopefully authenticates requests through a JSON web - token provided in a request cookie (and through the header as normal, with a preference to the header). + token provided in a request cookie (and through the header as normal, with a + preference to the header). """ def authenticate(self, request): + from django.conf import settings + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) header = self.get_header(request) if header is None: - if JWT_AUTH_COOKIE: # or settings.JWT_AUTH_COOKIE - raw_token = request.COOKIES.get(JWT_AUTH_COOKIE) # or settings.jwt_auth_cookie + if cookie_name: + raw_token = request.COOKIES.get(cookie_name) else: return None else: @@ -47,7 +50,7 @@ try: return None validated_token = self.get_validated_token(raw_token) - return self.get_user(validated_token), validated_token -except ImportError as I: + +except ImportError: pass diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 2896209..a31e879 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -16,7 +16,7 @@ from .app_settings import (JWTSerializer, LoginSerializer, PasswordChangeSerializer, PasswordResetConfirmSerializer, PasswordResetSerializer, TokenSerializer, - UserDetailsSerializer, create_token, JWT_AUTH_COOKIE) + UserDetailsSerializer, create_token) from .models import TokenModel from .utils import jwt_encode @@ -84,14 +84,17 @@ class LoginView(GenericAPIView): response = Response(serializer.data, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) from rest_framework_simplejwt.settings import api_settings as jwt_settings - if JWT_AUTH_COOKIE: #this needs to be added to simplejwt + if cookie_name: from datetime import datetime expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME) - response.set_cookie(JWT_AUTH_COOKIE, #this needs to be added to simplejwt - self.access_token, - expires=expiration, - httponly=True) + response.set_cookie( + cookie_name, + self.access_token, + expires=expiration, + httponly=True + ) return response def post(self, request, *args, **kwargs): @@ -135,9 +138,9 @@ class LogoutView(APIView): response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): - # from rest_framework_simplejwt.settings import api_settings as jwt_settings - if JWT_AUTH_COOKIE: #this needs to be added to simplejwt - response.delete_cookie(JWT_AUTH_COOKIE) #this needs to be added to simplejwt + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE') + if cookie_name: + response.delete_cookie(cookie_name) return response diff --git a/docs/configuration.rst b/docs/configuration.rst index af858c0..d4d67cc 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -47,7 +47,7 @@ Configuration - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) - **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of djangorestframework-simplejwt https://github.com/SimpleJWT/django-rest-framework-simplejwt, which must also be installed. (default: False) - +- **JWT_AUTH_COOKIE** - The cookie name/key. - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) - **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change From ce3b90dea6e2bd5b691d6f2c84fd9e85b07a5952 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 05:52:26 -0500 Subject: [PATCH 100/216] Re-adds previous tests --- dj_rest_auth/tests/test_api.py | 345 ++++++++++++++++++++++++++++++--- dj_rest_auth/views.py | 2 +- 2 files changed, 319 insertions(+), 28 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 4519186..f0607b5 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -144,46 +144,293 @@ class APIBasicTests(TestsMixin, TestCase): self.post(self.login_url, data=payload, status_code=200) @override_settings(REST_USE_JWT=True) - @override_settings(JWT_AUTH_COOKIE='jwt-auth') - def test_login_jwt_sets_cookie(self): + def test_login_jwt(self): payload = { "username": self.USERNAME, "password": self.PASS } get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - resp = self.post(self.login_url, data=payload, status_code=200) - self.assertTrue('jwt-auth' in resp.cookies.keys()) - @override_settings(REST_USE_JWT=True) - @override_settings(JWT_AUTH_COOKIE='jwt-auth') - def test_logout_jwt_deletes_cookie(self): - payload = { - "username": self.USERNAME, - "password": self.PASS - } - get_user_model().objects.create_user(self.USERNAME, '', self.PASS) self.post(self.login_url, data=payload, status_code=200) - resp = self.post(self.logout_url, status=200) - self.assertEqual('', resp.cookies.get('jwt-auth').value) + self.assertEqual('access_token' in self.response.json.keys(), True) + self.token = self.response.json['access_token'] + + def test_login_by_email(self): + # starting test without allauth app + settings.INSTALLED_APPS.remove('allauth') - @override_settings(REST_USE_JWT=True) - @override_settings(JWT_AUTH_COOKIE='jwt-auth') - @override_settings(REST_FRAMEWORK=dict( - DEFAULT_AUTHENTICATION_CLASSES=[ - 'dj_rest_auth.utils.JWTCookieAuthentication' - ] - )) - @override_settings(REST_SESSION_LOGIN=False) - def test_cookie_authentication(self): payload = { + "email": self.EMAIL.lower(), + "password": self.PASS + } + # there is no users in db so it should throw error (400) + self.post(self.login_url, data=payload, status_code=400) + + self.post(self.password_change_url, status_code=403) + + # create user + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + # test auth by email + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('key' in self.response.json.keys(), True) + self.token = self.response.json['key'] + + # test auth by email in different case + payload = { + "email": self.EMAIL.upper(), + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('key' in self.response.json.keys(), True) + self.token = self.response.json['key'] + + # test inactive user + user.is_active = False + user.save() + self.post(self.login_url, data=payload, status_code=400) + + # test wrong email/password + payload = { + "email": 't' + self.EMAIL, + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=400) + + # test empty payload + self.post(self.login_url, data={}, status_code=400) + + # bring back allauth + settings.INSTALLED_APPS.append('allauth') + + def test_password_change(self): + login_payload = { "username": self.USERNAME, "password": self.PASS } get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - resp = self.post(self.login_url, data=payload, status_code=200) - self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) - resp = self.get('/protected-view/') - self.assertEquals(resp.status_code, 200) + self.post(self.login_url, data=login_payload, status_code=200) + self.token = self.response.json['key'] + + new_password_payload = { + "new_password1": "new_person", + "new_password2": "new_person" + } + self.post( + self.password_change_url, + data=new_password_payload, + status_code=200 + ) + + # user should not be able to login using old password + self.post(self.login_url, data=login_payload, status_code=400) + + # new password should work + login_payload['password'] = new_password_payload['new_password1'] + self.post(self.login_url, data=login_payload, status_code=200) + + # pass1 and pass2 are not equal + new_password_payload = { + "new_password1": "new_person1", + "new_password2": "new_person" + } + self.post( + self.password_change_url, + data=new_password_payload, + status_code=400 + ) + + # send empty payload + self.post(self.password_change_url, data={}, status_code=400) + + @override_settings(OLD_PASSWORD_FIELD_ENABLED=True) + def test_password_change_with_old_password(self): + login_payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + self.post(self.login_url, data=login_payload, status_code=200) + self.token = self.response.json['key'] + + new_password_payload = { + "old_password": "%s!" % self.PASS, # wrong password + "new_password1": "new_person", + "new_password2": "new_person" + } + self.post( + self.password_change_url, + data=new_password_payload, + status_code=400 + ) + + new_password_payload = { + "old_password": self.PASS, + "new_password1": "new_person", + "new_password2": "new_person" + } + self.post( + self.password_change_url, + data=new_password_payload, + status_code=200 + ) + + # user should not be able to login using old password + self.post(self.login_url, data=login_payload, status_code=400) + + # new password should work + login_payload['password'] = new_password_payload['new_password1'] + self.post(self.login_url, data=login_payload, status_code=200) + + def test_password_reset(self): + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + # call password reset + mail_count = len(mail.outbox) + payload = {'email': self.EMAIL} + self.post(self.password_reset_url, data=payload, status_code=200) + self.assertEqual(len(mail.outbox), mail_count + 1) + + url_kwargs = self._generate_uid_and_token(user) + url = reverse('rest_password_reset_confirm') + + # wrong token + data = { + 'new_password1': self.NEW_PASS, + 'new_password2': self.NEW_PASS, + 'uid': force_text(url_kwargs['uid']), + 'token': '-wrong-token-' + } + self.post(url, data=data, status_code=400) + + # wrong uid + data = { + 'new_password1': self.NEW_PASS, + 'new_password2': self.NEW_PASS, + 'uid': '-wrong-uid-', + 'token': url_kwargs['token'] + } + self.post(url, data=data, status_code=400) + + # wrong token and uid + data = { + 'new_password1': self.NEW_PASS, + 'new_password2': self.NEW_PASS, + 'uid': '-wrong-uid-', + 'token': '-wrong-token-' + } + self.post(url, data=data, status_code=400) + + # valid payload + data = { + 'new_password1': self.NEW_PASS, + 'new_password2': self.NEW_PASS, + 'uid': force_text(url_kwargs['uid']), + 'token': url_kwargs['token'] + } + url = reverse('rest_password_reset_confirm') + self.post(url, data=data, status_code=200) + + payload = { + "username": self.USERNAME, + "password": self.NEW_PASS + } + self.post(self.login_url, data=payload, status_code=200) + + def test_password_reset_with_email_in_different_case(self): + get_user_model().objects.create_user(self.USERNAME, self.EMAIL.lower(), self.PASS) + + # call password reset in upper case + mail_count = len(mail.outbox) + payload = {'email': self.EMAIL.upper()} + self.post(self.password_reset_url, data=payload, status_code=200) + self.assertEqual(len(mail.outbox), mail_count + 1) + + def test_password_reset_with_invalid_email(self): + """ + Invalid email should not raise error, as this would leak users + """ + get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + # call password reset + mail_count = len(mail.outbox) + payload = {'email': 'nonexisting@email.com'} + self.post(self.password_reset_url, data=payload, status_code=200) + self.assertEqual(len(mail.outbox), mail_count) + + def test_user_details(self): + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + payload = { + "username": self.USERNAME, + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=200) + self.token = self.response.json['key'] + self.get(self.user_url, status_code=200) + + self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) + user = get_user_model().objects.get(pk=user.pk) + self.assertEqual(user.first_name, self.response.json['first_name']) + self.assertEqual(user.last_name, self.response.json['last_name']) + self.assertEqual(user.email, self.response.json['email']) + + @override_settings(REST_USE_JWT=True) + def test_user_details_using_jwt(self): + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + payload = { + "username": self.USERNAME, + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=200) + self.token = self.response.json['access_token'] + self.get(self.user_url, status_code=200) + + self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) + user = get_user_model().objects.get(pk=user.pk) + self.assertEqual(user.email, self.response.json['email']) + + def test_registration(self): + user_count = get_user_model().objects.all().count() + + # test empty payload + self.post(self.register_url, data={}, status_code=400) + + result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) + self.assertIn('key', result.data) + self.assertEqual(get_user_model().objects.all().count(), user_count + 1) + + new_user = get_user_model().objects.latest('id') + self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) + + self._login() + self._logout() + + @override_settings(REST_AUTH_REGISTER_PERMISSION_CLASSES=(CustomPermissionClass,)) + def test_registration_with_custom_permission_class(self): + + class CustomRegisterView(RegisterView): + permission_classes = register_permission_classes() + authentication_classes = () + + factory = APIRequestFactory() + request = factory.post('/customer/details', self.REGISTRATION_DATA, format='json') + + response = CustomRegisterView.as_view()(request) + self.assertEqual(response.data['detail'], CustomPermissionClass.message) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + @override_settings(REST_USE_JWT=True) + def test_registration_with_jwt(self): + user_count = get_user_model().objects.all().count() + + self.post(self.register_url, data={}, status_code=400) + + result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) + self.assertIn('access_token', result.data) + self.assertEqual(get_user_model().objects.all().count(), user_count + 1) + + self._login() + self._logout() def test_registration_with_invalid_password(self): data = self.REGISTRATION_DATA.copy() @@ -267,3 +514,47 @@ class APIBasicTests(TestsMixin, TestCase): self.post(self.login_url, data=payload, status_code=status.HTTP_200_OK) self.get(self.logout_url, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + def test_login_jwt_sets_cookie(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertTrue('jwt-auth' in resp.cookies.keys()) + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + def test_logout_jwt_deletes_cookie(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + self.post(self.login_url, data=payload, status_code=200) + resp = self.post(self.logout_url, status=200) + self.assertEqual('', resp.cookies.get('jwt-auth').value) + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + def test_cookie_authentication(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) + resp = self.get('/protected-view/') + self.assertEquals(resp.status_code, 200) \ No newline at end of file diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index a31e879..c5ba7fc 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -138,7 +138,7 @@ class LogoutView(APIView): response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): - cookie_name = getattr(settings, 'JWT_AUTH_COOKIE') + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) return response From 4070bce94bda8d3c3d04839f0f2952d88f95490f Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 06:20:44 -0500 Subject: [PATCH 101/216] Attempts to fix tests --- .circleci/config.yml | 2 +- dev-requirements.txt | 2 +- dj_rest_auth/tests/requirements.pip | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d124869..efcf792 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,9 +12,9 @@ jobs: executor: docker/docker steps: - checkout - - run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION - run: pip install --user -r dev-requirements.txt - run: pip install --user -r dj_rest_auth/tests/requirements.pip + - run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION - run: command: coverage run --source=dj_rest_auth setup.py test name: Test diff --git a/dev-requirements.txt b/dev-requirements.txt index cee8ea6..9cb5377 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,4 +2,4 @@ responses>=0.5.0 djangorestframework-simplejwt==4.4.0 django-allauth -coveralls>=1.11.1 \ No newline at end of file +coveralls>=1.11. \ No newline at end of file diff --git a/dj_rest_auth/tests/requirements.pip b/dj_rest_auth/tests/requirements.pip index 4ff9b2d..9f28d70 100644 --- a/dj_rest_auth/tests/requirements.pip +++ b/dj_rest_auth/tests/requirements.pip @@ -1,6 +1,4 @@ django-allauth>=0.25.0 responses>=0.3.0 flake8==2.4.0 -Django==3.0.4 djangorestframework-simplejwt==4.4.0 -djangorestframework>=3.6.4 From 27815933f52ab393477abaa94bcae0d86fee6fcf Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 06:23:13 -0500 Subject: [PATCH 102/216] Bumps minor version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8872a56..46f5d5f 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.1.4', + version='0.2.0', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From bfd67501048a519b6e07f9ef55e04f21a4695353 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 06:25:43 -0500 Subject: [PATCH 103/216] Removes coveralls patch edit --- dev-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 9cb5377..cee8ea6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,4 +2,4 @@ responses>=0.5.0 djangorestframework-simplejwt==4.4.0 django-allauth -coveralls>=1.11. \ No newline at end of file +coveralls>=1.11.1 \ No newline at end of file From fe06053abe2859e5a5c4887590c3546f71b6d332 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 06:38:54 -0500 Subject: [PATCH 104/216] Adds JWT example to Readme --- README.md | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3ec4ef7..a106d5e 100644 --- a/README.md +++ b/README.md @@ -18,20 +18,35 @@ Install package Add `dj_rest_auth` app to INSTALLED_APPS in your django settings.py: - INSTALLED_APPS = ( - ..., - 'rest_framework', - 'rest_framework.authtoken', - ..., - 'dj_rest_auth' - ) +```python +INSTALLED_APPS = ( + ..., + 'rest_framework', + 'rest_framework.authtoken', + ..., + 'dj_rest_auth' +) +``` Add URL patterns +```python +urlpatterns = [ + url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) +] +``` + +(Optional) + +Use Http-Only cookies + +```python +REST_USE_JWT = True +JWT_AUTH_COOKIE = 'jwt-auth' +``` + + - urlpatterns = [ - url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) - ] ### Documentation From 1eaa8edd0ef1718d612b037c2f1e367a28aea23f Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Mar 2020 06:40:01 -0500 Subject: [PATCH 105/216] README tweak --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index a106d5e..b87ba30 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,8 @@ urlpatterns = [ ] ``` -(Optional) -Use Http-Only cookies +(Optional) Use Http-Only cookies ```python REST_USE_JWT = True From c933513438d8fb53cf55f2dd3a8ea8ab2bdad00f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 11:09:07 -0500 Subject: [PATCH 106/216] Bumps version, fixes import ordering --- dj_rest_auth/app_settings.py | 1 - dj_rest_auth/tests/test_api.py | 7 ++----- dj_rest_auth/tests/urls.py | 6 +++--- setup.py | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index 39e44ef..16c3888 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -36,4 +36,3 @@ PasswordResetConfirmSerializer = serializers.get( PasswordChangeSerializer = import_callable(serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)) JWT_AUTH_COOKIE = getattr(settings, 'JWT_AUTH_COOKIE', None) - diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index f0607b5..0134560 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -407,7 +407,6 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(REST_AUTH_REGISTER_PERMISSION_CLASSES=(CustomPermissionClass,)) def test_registration_with_custom_permission_class(self): - class CustomRegisterView(RegisterView): permission_classes = register_permission_classes() authentication_classes = () @@ -477,7 +476,7 @@ class APIBasicTests(TestsMixin, TestCase): ) # verify email - email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ + email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL) \ .emailconfirmation_set.order_by('-created')[0] self.post( self.verify_email_url, @@ -526,7 +525,6 @@ class APIBasicTests(TestsMixin, TestCase): resp = self.post(self.login_url, data=payload, status_code=200) self.assertTrue('jwt-auth' in resp.cookies.keys()) - @override_settings(REST_USE_JWT=True) @override_settings(JWT_AUTH_COOKIE='jwt-auth') def test_logout_jwt_deletes_cookie(self): @@ -539,7 +537,6 @@ class APIBasicTests(TestsMixin, TestCase): resp = self.post(self.logout_url, status=200) self.assertEqual('', resp.cookies.get('jwt-auth').value) - @override_settings(REST_USE_JWT=True) @override_settings(JWT_AUTH_COOKIE='jwt-auth') @override_settings(REST_FRAMEWORK=dict( @@ -557,4 +554,4 @@ class APIBasicTests(TestsMixin, TestCase): resp = self.post(self.login_url, data=payload, status_code=200) self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) resp = self.get('/protected-view/') - self.assertEquals(resp.status_code, 200) \ No newline at end of file + self.assertEquals(resp.status_code, 200) diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index 7579e83..e2c786e 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -10,10 +10,10 @@ from dj_rest_auth.social_serializers import (TwitterConnectSerializer, from dj_rest_auth.urls import urlpatterns from django.conf.urls import include, url from django.views.generic import TemplateView -from rest_framework.decorators import api_view -from rest_framework.views import APIView -from rest_framework.response import Response from rest_framework import permissions +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework.views import APIView from . import django_urls diff --git a/setup.py b/setup.py index 46f5d5f..da11337 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='0.2.0', + version='1.0.0', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From 9d24b4ffe00c83e5279b4c4a2dfca4bc36d5bfa6 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 11:36:03 -0500 Subject: [PATCH 107/216] Updates docs and demo --- demo/demo/settings.py | 2 -- demo/requirements.pip | 3 ++- docs/changelog.rst | 13 ++++++++++++- docs/index.rst | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 31056de..9394428 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -34,11 +34,9 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', - 'rest_framework', 'rest_framework.authtoken', 'dj_rest_auth', - 'allauth', 'allauth.account', 'dj_rest_auth.registration', diff --git a/demo/requirements.pip b/demo/requirements.pip index 6d24967..04b962d 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,6 +1,7 @@ django>=1.9.0 dj-rest-auth==0.1.4 -djangorestframework>=3.7.0 +djangorestframework>=3.11.0 djangorestframework-simplejwt==4.4.0 django-allauth>=0.24.1 django-rest-swagger==2.0.7 +coreapi==2.3.3 \ No newline at end of file diff --git a/docs/changelog.rst b/docs/changelog.rst index 42d36bc..405df48 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -3,4 +3,15 @@ Changelog 0.1.2 ----- -Welcome Dj-Rest-Auth \ No newline at end of file +Welcome Dj-Rest-Auth + +1.0.0 +----- +Replaces `rest_framework_jwt` with `djangorestframework-simplejwt`. + + +- rest_framework_jwt is now unmaintained so we've switched to simplewjt, +which is a strong jwt library with a large community. +- This change means you may need to change your client code if you're upgrading + from the previous version. Example: token -> access_token. Please see demo + for more information. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 82118cc..10eb7cb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,7 @@ Welcome to dj-rest-auth's documentation! ============================================ -.. note:: dj-rest-auth supports django-rest-framework >= v3.0 +.. note:: dj-rest-auth version 1.0.0 now uses Django Simple JWT. Please see changelog. .. image:: https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg From ff7d9728bb9baad2fbea3135bc93892375831ae2 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 11:39:21 -0500 Subject: [PATCH 108/216] Use master in demo --- demo/requirements.pip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index 04b962d..64a3488 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ django>=1.9.0 -dj-rest-auth==0.1.4 +git+https://github.com/jazzband/dj-rest-auth.git@master djangorestframework>=3.11.0 djangorestframework-simplejwt==4.4.0 django-allauth>=0.24.1 From ac3cbcb613f78e385a3a94c4339cc2c5394949ec Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 12:15:02 -0500 Subject: [PATCH 109/216] Adds React SPA --- .gitignore | 2 + demo/demo/settings.py | 5 + demo/react-spa/.gitignore | 23 +++++ demo/react-spa/README.md | 68 ++++++++++++++ demo/react-spa/package.json | 34 +++++++ demo/react-spa/public/favicon.ico | Bin 0 -> 3150 bytes demo/react-spa/public/index.html | 43 +++++++++ demo/react-spa/public/logo192.png | Bin 0 -> 5347 bytes demo/react-spa/public/logo512.png | Bin 0 -> 9664 bytes demo/react-spa/public/manifest.json | 25 +++++ demo/react-spa/public/robots.txt | 3 + demo/react-spa/src/App.css | 38 ++++++++ demo/react-spa/src/App.js | 58 ++++++++++++ demo/react-spa/src/App.test.js | 9 ++ demo/react-spa/src/index.css | 13 +++ demo/react-spa/src/index.js | 17 ++++ demo/react-spa/src/logo.svg | 7 ++ demo/react-spa/src/serviceWorker.js | 141 ++++++++++++++++++++++++++++ demo/react-spa/src/setupTests.js | 5 + demo/requirements.pip | 3 +- 20 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 demo/react-spa/.gitignore create mode 100644 demo/react-spa/README.md create mode 100644 demo/react-spa/package.json create mode 100644 demo/react-spa/public/favicon.ico create mode 100644 demo/react-spa/public/index.html create mode 100644 demo/react-spa/public/logo192.png create mode 100644 demo/react-spa/public/logo512.png create mode 100644 demo/react-spa/public/manifest.json create mode 100644 demo/react-spa/public/robots.txt create mode 100644 demo/react-spa/src/App.css create mode 100644 demo/react-spa/src/App.js create mode 100644 demo/react-spa/src/App.test.js create mode 100644 demo/react-spa/src/index.css create mode 100644 demo/react-spa/src/index.js create mode 100644 demo/react-spa/src/logo.svg create mode 100644 demo/react-spa/src/serviceWorker.js create mode 100644 demo/react-spa/src/setupTests.js diff --git a/.gitignore b/.gitignore index 894a44c..84cc2de 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ venv.bak/ # mypy .mypy_cache/ +demo/react-spa/node_modules/ +demo/react-spa/yarn.lock \ No newline at end of file diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 9394428..c001399 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -43,9 +43,11 @@ INSTALLED_APPS = ( 'allauth.socialaccount', 'allauth.socialaccount.providers.facebook', 'rest_framework_swagger', + 'corsheaders' ) MIDDLEWARE = ( + 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -126,3 +128,6 @@ SWAGGER_SETTINGS = { 'LOGIN_URL': 'login', 'LOGOUT_URL': 'logout', } + + +CORS_ORIGIN_ALLOW_ALL = True # For demo purposes only. Use a white list in the real world. \ No newline at end of file diff --git a/demo/react-spa/.gitignore b/demo/react-spa/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/demo/react-spa/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/demo/react-spa/README.md b/demo/react-spa/README.md new file mode 100644 index 0000000..9c40dcd --- /dev/null +++ b/demo/react-spa/README.md @@ -0,0 +1,68 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting + +### Analyzing the Bundle Size + +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size + +### Making a Progressive Web App + +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app + +### Advanced Configuration + +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration + +### Deployment + +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment + +### `yarn build` fails to minify + +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify diff --git a/demo/react-spa/package.json b/demo/react-spa/package.json new file mode 100644 index 0000000..62f4226 --- /dev/null +++ b/demo/react-spa/package.json @@ -0,0 +1,34 @@ +{ + "name": "react-spa", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-scripts": "3.4.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/demo/react-spa/public/favicon.ico b/demo/react-spa/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..bcd5dfd67cd0361b78123e95c2dd96031f27f743 GIT binary patch literal 3150 zcmaKtc{Ei0AIGn;MZ^<@lHD*OV;K7~W1q3jSjJcqNywTkMOhP*k~Oj?GO|6{m(*C2 zC7JA+hN%%Bp7T4;J@?%2_x=5zbI<2~->=X60stMr0B~{wzpi9D0MG|# zyuANt7z6;uz%?PEfAnimLl^)6h5ARwGXemG2>?hqQv-I^Gpyh$JH}Ag92}3{$a#z& zd`il2Sb#$U&e&4#^4R|GTgk!Qs+x*PCL{2+`uB5mqtnqLaaw`*H2oqJ?XF(zUACc2 zSibBrdQzcidqv*TK}rpEv1ie&;Famq2IK5%4c}1Jt2b1x_{y1C!?EU)@`_F)yN*NK z)(u03@%g%uDawwXGAMm%EnP9FgoucUedioDwL~{6RVO@A-Q$+pwVRR%WYR>{K3E&Q zzqzT!EEZ$_NHGYM6&PK#CGUV$pTWsiI5#~m>htoJ!vbc0=gm3H8sz8KzIiVN5xdCT z%;}`UH2Pc8))1VS-unh?v4*H*NIy5On{MRKw7BTmOO9oE2UApwkCl9Z?^dod9M^#w z51tEZhf+#dpTo#GDDy#kuzoIjMjZ?%v*h$ z*vwUMOjGc?R0(FjLWkMD)kca4z6~H45FIzQ!Zzu&-yWyMdCBsDr2`l}Q{8fH$H@O< z$&snNzbqLk?(GIe?!PVh?F~2qk4z^rMcp$P^hw^rUPjyCyoNTRw%;hNOwrCoN?G0E z!wT^=4Loa9@O{t;Wk(Nj=?ms1Z?UN_;21m%sUm?uib=pg&x|u)8pP#l--$;B9l47n zUUnMV0sXLe*@Gvy>XWjRoqc2tOzgYn%?g@Lb8C&WsxV1Kjssh^ZBs*Ysr+E6%tsC_ zCo-)hkYY=Bn?wMB4sqm?WS>{kh<6*DO)vXnQpQ9`-_qF6!#b;3Nf@;#B>e2j$yokl6F|9p1<($2 z=WSr%)Z?^|r6njhgbuMrIN>8JE05u0x5t@_dEfbGn9r0hK4c2vp>(*$GXsjeLL_uz zWpyfUgdv!~-2N;llVzik#s2*XB*%7u8(^sJv&T3pzaR&<9({17Zs~UY>#ugZZkHBs zD+>0_an$?}utGp$dcXtyFHnTQZJ}SF=oZ}X07dz~K>^o(vjTzw8ZQc!Fw1W=&Z?9% zv63|~l}70sJbY?H8ON8j)w5=6OpXuaZ}YT03`2%u8{;B0Vafo_iY7&BiQTbRkdJBYL}?%ATfmc zLG$uXt$@3j#OIjALdT&Ut$=9F8cgV{w_f5eS)PjoVi z&oemp-SKJ~UuGuCP1|iY?J^S&P z)-IG?O-*=z6kfZrX5H*G=aQ{ZaqnOqP@&+_;nq@mA>EcjgxrYX8EK|Iq4&E&rxR?R z8N$QOdRwY zr{P`O)=87>YLHtFfGXW z6P)ucrhj~It_9w<^v5>T6N1U}+BkS))=WX*2JY=}^b2czGhH<`?`(}}qMcpPx_%>M zM|fs(+I1m&_h(zqp-HgP>re$2O^o$q)xu#fl0ivOJE({duU)a*OD(eYgSi^cdTn}pqcPM(;S)2%1By^Wh%-CaC%>d9hi`7J zaxL7@;nhA>PE%s99&;z{8>VFgf{u!(-B-x7Of6ueme+ScryL`h(^qKE)DtieWY>-7 zgB)VJESQS4*1LU(2&@pgLvSt{(((C?K_V(rQk``i&5}ZPG;G^FiPlZ$7|-vEmMWlU z5lQ%iK2nu=h2wd_7>gK@vX=*AG+u~rQP$NwPC`ZA?4nh{3tui1x@bT6-;Rk3yDQ>d z?3qRD#+PeV7#FAa>s`Xwxsx_oRFcN$StW2=CW`=qObsT?SD^#^jM1Yk}PSPxJ zG@-_mnNU_)vM|iLRSI>UMp|hatyS}17R{10IuL0TLlupt>9dRs_SPQbv7BLYyC#qv16E-y@XZ= z-!p7I%#r-BVi$nQq3&ssRc_IC%R6$tA&^s_l46880~Wst3@>(|EO<}T4~ci~#!=e; zD)B>o%1+$ksURD1p7I-<3ehlFyVkqrySf&gg>Bp0Z9?JaG|gyTZ{Cb8SdvAWVmFX7v2ohs!OCc!Udk zUITUpmZ33rKLI#(&lDj}cKA#dpL4Fil=$5pu_wi1XJR!llw` zSItPBDEdMHk2>c7#%lBxZHHvtVUOZ$}v?=?AT~9!Jcqa@IJGuMg(s^7r>pcTrd)pS`{5Cu8WPey` z9)!!OUUY@L%9Q+bZa*S5`3f_|lFCPN6kdp_M2>{le8;cn^XUsPa+TUk47qd6)IBR% zk*&Ip?!Ge_gmmdj)BX}P_5o@VI2*wbZ^>UhFju}0gQZh!pP%4XT9{@w;G#b3XK8sN zF(7i$Jv(IM$8Akys9dhP^^~H2(7BfJp}yDW1#@!CL-!mGcSCnJ599WK9MV@yo_u$v MDeX2GIKR{Qf5okjU;qFB literal 0 HcmV?d00001 diff --git a/demo/react-spa/public/index.html b/demo/react-spa/public/index.html new file mode 100644 index 0000000..aa069f2 --- /dev/null +++ b/demo/react-spa/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/demo/react-spa/public/logo192.png b/demo/react-spa/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..fc44b0a3796c0e0a64c3d858ca038bd4570465d9 GIT binary patch literal 5347 zcmZWtbyO6NvR-oO24RV%BvuJ&=?+<7=`LvyB&A_#M7mSDYw1v6DJkiYl9XjT!%$dLEBTQ8R9|wd3008in6lFF3GV-6mLi?MoP_y~}QUnaDCHI#t z7w^m$@6DI)|C8_jrT?q=f8D?0AM?L)Z}xAo^e^W>t$*Y0KlT5=@bBjT9kxb%-KNdk zeOS1tKO#ChhG7%{ApNBzE2ZVNcxbrin#E1TiAw#BlUhXllzhN$qWez5l;h+t^q#Eav8PhR2|T}y5kkflaK`ba-eoE+Z2q@o6P$)=&` z+(8}+-McnNO>e#$Rr{32ngsZIAX>GH??tqgwUuUz6kjns|LjsB37zUEWd|(&O!)DY zQLrq%Y>)Y8G`yYbYCx&aVHi@-vZ3|ebG!f$sTQqMgi0hWRJ^Wc+Ibv!udh_r%2|U) zPi|E^PK?UE!>_4`f`1k4hqqj_$+d!EB_#IYt;f9)fBOumGNyglU(ofY`yHq4Y?B%- zp&G!MRY<~ajTgIHErMe(Z8JG*;D-PJhd@RX@QatggM7+G(Lz8eZ;73)72Hfx5KDOE zkT(m}i2;@X2AT5fW?qVp?@WgN$aT+f_6eo?IsLh;jscNRp|8H}Z9p_UBO^SJXpZew zEK8fz|0Th%(Wr|KZBGTM4yxkA5CFdAj8=QSrT$fKW#tweUFqr0TZ9D~a5lF{)%-tTGMK^2tz(y2v$i%V8XAxIywrZCp=)83p(zIk6@S5AWl|Oa2hF`~~^W zI;KeOSkw1O#TiQ8;U7OPXjZM|KrnN}9arP)m0v$c|L)lF`j_rpG(zW1Qjv$=^|p*f z>)Na{D&>n`jOWMwB^TM}slgTEcjxTlUby89j1)|6ydRfWERn3|7Zd2&e7?!K&5G$x z`5U3uFtn4~SZq|LjFVrz$3iln-+ucY4q$BC{CSm7Xe5c1J<=%Oagztj{ifpaZk_bQ z9Sb-LaQMKp-qJA*bP6DzgE3`}*i1o3GKmo2pn@dj0;He}F=BgINo};6gQF8!n0ULZ zL>kC0nPSFzlcB7p41doao2F7%6IUTi_+!L`MM4o*#Y#0v~WiO8uSeAUNp=vA2KaR&=jNR2iVwG>7t%sG2x_~yXzY)7K& zk3p+O0AFZ1eu^T3s};B%6TpJ6h-Y%B^*zT&SN7C=N;g|#dGIVMSOru3iv^SvO>h4M=t-N1GSLLDqVTcgurco6)3&XpU!FP6Hlrmj}f$ zp95;b)>M~`kxuZF3r~a!rMf4|&1=uMG$;h^g=Kl;H&Np-(pFT9FF@++MMEx3RBsK?AU0fPk-#mdR)Wdkj)`>ZMl#^<80kM87VvsI3r_c@_vX=fdQ`_9-d(xiI z4K;1y1TiPj_RPh*SpDI7U~^QQ?%0&!$Sh#?x_@;ag)P}ZkAik{_WPB4rHyW#%>|Gs zdbhyt=qQPA7`?h2_8T;-E6HI#im9K>au*(j4;kzwMSLgo6u*}-K`$_Gzgu&XE)udQ zmQ72^eZd|vzI)~!20JV-v-T|<4@7ruqrj|o4=JJPlybwMg;M$Ud7>h6g()CT@wXm` zbq=A(t;RJ^{Xxi*Ff~!|3!-l_PS{AyNAU~t{h;(N(PXMEf^R(B+ZVX3 z8y0;0A8hJYp@g+c*`>eTA|3Tgv9U8#BDTO9@a@gVMDxr(fVaEqL1tl?md{v^j8aUv zm&%PX4^|rX|?E4^CkplWWNv*OKM>DxPa z!RJ)U^0-WJMi)Ksc!^ixOtw^egoAZZ2Cg;X7(5xZG7yL_;UJ#yp*ZD-;I^Z9qkP`} zwCTs0*%rIVF1sgLervtnUo&brwz?6?PXRuOCS*JI-WL6GKy7-~yi0giTEMmDs_-UX zo=+nFrW_EfTg>oY72_4Z0*uG>MnXP=c0VpT&*|rvv1iStW;*^={rP1y?Hv+6R6bxFMkxpWkJ>m7Ba{>zc_q zEefC3jsXdyS5??Mz7IET$Kft|EMNJIv7Ny8ZOcKnzf`K5Cd)&`-fTY#W&jnV0l2vt z?Gqhic}l}mCv1yUEy$%DP}4AN;36$=7aNI^*AzV(eYGeJ(Px-j<^gSDp5dBAv2#?; zcMXv#aj>%;MiG^q^$0MSg-(uTl!xm49dH!{X0){Ew7ThWV~Gtj7h%ZD zVN-R-^7Cf0VH!8O)uUHPL2mO2tmE*cecwQv_5CzWeh)ykX8r5Hi`ehYo)d{Jnh&3p z9ndXT$OW51#H5cFKa76c<%nNkP~FU93b5h-|Cb}ScHs@4Q#|}byWg;KDMJ#|l zE=MKD*F@HDBcX@~QJH%56eh~jfPO-uKm}~t7VkHxHT;)4sd+?Wc4* z>CyR*{w@4(gnYRdFq=^(#-ytb^5ESD?x<0Skhb%Pt?npNW1m+Nv`tr9+qN<3H1f<% zZvNEqyK5FgPsQ`QIu9P0x_}wJR~^CotL|n zk?dn;tLRw9jJTur4uWoX6iMm914f0AJfB@C74a;_qRrAP4E7l890P&{v<}>_&GLrW z)klculcg`?zJO~4;BBAa=POU%aN|pmZJn2{hA!d!*lwO%YSIzv8bTJ}=nhC^n}g(ld^rn#kq9Z3)z`k9lvV>y#!F4e{5c$tnr9M{V)0m(Z< z#88vX6-AW7T2UUwW`g<;8I$Jb!R%z@rCcGT)-2k7&x9kZZT66}Ztid~6t0jKb&9mm zpa}LCb`bz`{MzpZR#E*QuBiZXI#<`5qxx=&LMr-UUf~@dRk}YI2hbMsAMWOmDzYtm zjof16D=mc`^B$+_bCG$$@R0t;e?~UkF?7<(vkb70*EQB1rfUWXh$j)R2)+dNAH5%R zEBs^?N;UMdy}V};59Gu#0$q53$}|+q7CIGg_w_WlvE}AdqoS<7DY1LWS9?TrfmcvT zaypmplwn=P4;a8-%l^e?f`OpGb}%(_mFsL&GywhyN(-VROj`4~V~9bGv%UhcA|YW% zs{;nh@aDX11y^HOFXB$a7#Sr3cEtNd4eLm@Y#fc&j)TGvbbMwze zXtekX_wJqxe4NhuW$r}cNy|L{V=t#$%SuWEW)YZTH|!iT79k#?632OFse{+BT_gau zJwQcbH{b}dzKO?^dV&3nTILYlGw{27UJ72ZN){BILd_HV_s$WfI2DC<9LIHFmtyw? zQ;?MuK7g%Ym+4e^W#5}WDLpko%jPOC=aN)3!=8)s#Rnercak&b3ESRX3z{xfKBF8L z5%CGkFmGO@x?_mPGlpEej!3!AMddChabyf~nJNZxx!D&{@xEb!TDyvqSj%Y5@A{}9 zRzoBn0?x}=krh{ok3Nn%e)#~uh;6jpezhA)ySb^b#E>73e*frBFu6IZ^D7Ii&rsiU z%jzygxT-n*joJpY4o&8UXr2s%j^Q{?e-voloX`4DQyEK+DmrZh8A$)iWL#NO9+Y@!sO2f@rI!@jN@>HOA< z?q2l{^%mY*PNx2FoX+A7X3N}(RV$B`g&N=e0uvAvEN1W^{*W?zT1i#fxuw10%~))J zjx#gxoVlXREWZf4hRkgdHx5V_S*;p-y%JtGgQ4}lnA~MBz-AFdxUxU1RIT$`sal|X zPB6sEVRjGbXIP0U+?rT|y5+ev&OMX*5C$n2SBPZr`jqzrmpVrNciR0e*Wm?fK6DY& zl(XQZ60yWXV-|Ps!A{EF;=_z(YAF=T(-MkJXUoX zI{UMQDAV2}Ya?EisdEW;@pE6dt;j0fg5oT2dxCi{wqWJ<)|SR6fxX~5CzblPGr8cb zUBVJ2CQd~3L?7yfTpLNbt)He1D>*KXI^GK%<`bq^cUq$Q@uJifG>p3LU(!H=C)aEL zenk7pVg}0{dKU}&l)Y2Y2eFMdS(JS0}oZUuVaf2+K*YFNGHB`^YGcIpnBlMhO7d4@vV zv(@N}(k#REdul8~fP+^F@ky*wt@~&|(&&meNO>rKDEnB{ykAZ}k>e@lad7to>Ao$B zz<1(L=#J*u4_LB=8w+*{KFK^u00NAmeNN7pr+Pf+N*Zl^dO{LM-hMHyP6N!~`24jd zXYP|Ze;dRXKdF2iJG$U{k=S86l@pytLx}$JFFs8e)*Vi?aVBtGJ3JZUj!~c{(rw5>vuRF$`^p!P8w1B=O!skwkO5yd4_XuG^QVF z`-r5K7(IPSiKQ2|U9+`@Js!g6sfJwAHVd|s?|mnC*q zp|B|z)(8+mxXyxQ{8Pg3F4|tdpgZZSoU4P&9I8)nHo1@)9_9u&NcT^FI)6|hsAZFk zZ+arl&@*>RXBf-OZxhZerOr&dN5LW9@gV=oGFbK*J+m#R-|e6(Loz(;g@T^*oO)0R zN`N=X46b{7yk5FZGr#5&n1!-@j@g02g|X>MOpF3#IjZ_4wg{dX+G9eqS+Es9@6nC7 zD9$NuVJI}6ZlwtUm5cCAiYv0(Yi{%eH+}t)!E^>^KxB5^L~a`4%1~5q6h>d;paC9c zTj0wTCKrhWf+F#5>EgX`sl%POl?oyCq0(w0xoL?L%)|Q7d|Hl92rUYAU#lc**I&^6p=4lNQPa0 znQ|A~i0ip@`B=FW-Q;zh?-wF;Wl5!+q3GXDu-x&}$gUO)NoO7^$BeEIrd~1Dh{Tr` z8s<(Bn@gZ(mkIGnmYh_ehXnq78QL$pNDi)|QcT*|GtS%nz1uKE+E{7jdEBp%h0}%r zD2|KmYGiPa4;md-t_m5YDz#c*oV_FqXd85d@eub?9N61QuYcb3CnVWpM(D-^|CmkL z(F}L&N7qhL2PCq)fRh}XO@U`Yn<?TNGR4L(mF7#4u29{i~@k;pLsgl({YW5`Mo+p=zZn3L*4{JU;++dG9 X@eDJUQo;Ye2mwlRs?y0|+_a0zY+Zo%Dkae}+MySoIppb75o?vUW_?)>@g{U2`ERQIXV zeY$JrWnMZ$QC<=ii4X|@0H8`si75jB(ElJb00HAB%>SlLR{!zO|C9P3zxw_U8?1d8uRZ=({Ga4shyN}3 zAK}WA(ds|``G4jA)9}Bt2Hy0+f3rV1E6b|@?hpGA=PI&r8)ah|)I2s(P5Ic*Ndhn^ z*T&j@gbCTv7+8rpYbR^Ty}1AY)YH;p!m948r#%7x^Z@_-w{pDl|1S4`EM3n_PaXvK z1JF)E3qy$qTj5Xs{jU9k=y%SQ0>8E$;x?p9ayU0bZZeo{5Z@&FKX>}s!0+^>C^D#z z>xsCPvxD3Z=dP}TTOSJhNTPyVt14VCQ9MQFN`rn!c&_p?&4<5_PGm4a;WS&1(!qKE z_H$;dDdiPQ!F_gsN`2>`X}$I=B;={R8%L~`>RyKcS$72ai$!2>d(YkciA^J0@X%G4 z4cu!%Ps~2JuJ8ex`&;Fa0NQOq_nDZ&X;^A=oc1&f#3P1(!5il>6?uK4QpEG8z0Rhu zvBJ+A9RV?z%v?!$=(vcH?*;vRs*+PPbOQ3cdPr5=tOcLqmfx@#hOqX0iN)wTTO21jH<>jpmwRIAGw7`a|sl?9y9zRBh>(_%| zF?h|P7}~RKj?HR+q|4U`CjRmV-$mLW>MScKnNXiv{vD3&2@*u)-6P@h0A`eeZ7}71 zK(w%@R<4lLt`O7fs1E)$5iGb~fPfJ?WxhY7c3Q>T-w#wT&zW522pH-B%r5v#5y^CF zcC30Se|`D2mY$hAlIULL%-PNXgbbpRHgn<&X3N9W!@BUk@9g*P5mz-YnZBb*-$zMM z7Qq}ic0mR8n{^L|=+diODdV}Q!gwr?y+2m=3HWwMq4z)DqYVg0J~^}-%7rMR@S1;9 z7GFj6K}i32X;3*$SmzB&HW{PJ55kT+EI#SsZf}bD7nW^Haf}_gXciYKX{QBxIPSx2Ma? zHQqgzZq!_{&zg{yxqv3xq8YV+`S}F6A>Gtl39_m;K4dA{pP$BW0oIXJ>jEQ!2V3A2 zdpoTxG&V=(?^q?ZTj2ZUpDUdMb)T?E$}CI>r@}PFPWD9@*%V6;4Ag>D#h>!s)=$0R zRXvdkZ%|c}ubej`jl?cS$onl9Tw52rBKT)kgyw~Xy%z62Lr%V6Y=f?2)J|bZJ5(Wx zmji`O;_B+*X@qe-#~`HFP<{8$w@z4@&`q^Q-Zk8JG3>WalhnW1cvnoVw>*R@c&|o8 zZ%w!{Z+MHeZ*OE4v*otkZqz11*s!#s^Gq>+o`8Z5 z^i-qzJLJh9!W-;SmFkR8HEZJWiXk$40i6)7 zZpr=k2lp}SasbM*Nbn3j$sn0;rUI;%EDbi7T1ZI4qL6PNNM2Y%6{LMIKW+FY_yF3) zSKQ2QSujzNMSL2r&bYs`|i2Dnn z=>}c0>a}>|uT!IiMOA~pVT~R@bGlm}Edf}Kq0?*Af6#mW9f9!}RjW7om0c9Qlp;yK z)=XQs(|6GCadQbWIhYF=rf{Y)sj%^Id-ARO0=O^Ad;Ph+ z0?$eE1xhH?{T$QI>0JP75`r)U_$#%K1^BQ8z#uciKf(C701&RyLQWBUp*Q7eyn76} z6JHpC9}R$J#(R0cDCkXoFSp;j6{x{b&0yE@P7{;pCEpKjS(+1RQy38`=&Yxo%F=3y zCPeefABp34U-s?WmU#JJw23dcC{sPPFc2#J$ZgEN%zod}J~8dLm*fx9f6SpO zn^Ww3bt9-r0XaT2a@Wpw;C23XM}7_14#%QpubrIw5aZtP+CqIFmsG4`Cm6rfxl9n5 z7=r2C-+lM2AB9X0T_`?EW&Byv&K?HS4QLoylJ|OAF z`8atBNTzJ&AQ!>sOo$?^0xj~D(;kS$`9zbEGd>f6r`NC3X`tX)sWgWUUOQ7w=$TO&*j;=u%25ay-%>3@81tGe^_z*C7pb9y*Ed^H3t$BIKH2o+olp#$q;)_ zfpjCb_^VFg5fU~K)nf*d*r@BCC>UZ!0&b?AGk_jTPXaSnCuW110wjHPPe^9R^;jo3 zwvzTl)C`Zl5}O2}3lec=hZ*$JnkW#7enKKc)(pM${_$9Hc=Sr_A9Biwe*Y=T?~1CK z6eZ9uPICjy-sMGbZl$yQmpB&`ouS8v{58__t0$JP%i3R&%QR3ianbZqDs<2#5FdN@n5bCn^ZtH992~5k(eA|8|@G9u`wdn7bnpg|@{m z^d6Y`*$Zf2Xr&|g%sai#5}Syvv(>Jnx&EM7-|Jr7!M~zdAyjt*xl;OLhvW-a%H1m0 z*x5*nb=R5u><7lyVpNAR?q@1U59 zO+)QWwL8t zyip?u_nI+K$uh{y)~}qj?(w0&=SE^8`_WMM zTybjG=999h38Yes7}-4*LJ7H)UE8{mE(6;8voE+TYY%33A>S6`G_95^5QHNTo_;Ao ztIQIZ_}49%{8|=O;isBZ?=7kfdF8_@azfoTd+hEJKWE!)$)N%HIe2cplaK`ry#=pV z0q{9w-`i0h@!R8K3GC{ivt{70IWG`EP|(1g7i_Q<>aEAT{5(yD z=!O?kq61VegV+st@XCw475j6vS)_z@efuqQgHQR1T4;|-#OLZNQJPV4k$AX1Uk8Lm z{N*b*ia=I+MB}kWpupJ~>!C@xEN#Wa7V+7{m4j8c?)ChV=D?o~sjT?0C_AQ7B-vxqX30s0I_`2$in86#`mAsT-w?j{&AL@B3$;P z31G4(lV|b}uSDCIrjk+M1R!X7s4Aabn<)zpgT}#gE|mIvV38^ODy@<&yflpCwS#fRf9ZX3lPV_?8@C5)A;T zqmouFLFk;qIs4rA=hh=GL~sCFsXHsqO6_y~*AFt939UYVBSx1s(=Kb&5;j7cSowdE;7()CC2|-i9Zz+_BIw8#ll~-tyH?F3{%`QCsYa*b#s*9iCc`1P1oC26?`g<9))EJ3%xz+O!B3 zZ7$j~To)C@PquR>a1+Dh>-a%IvH_Y7^ys|4o?E%3`I&ADXfC8++hAdZfzIT#%C+Jz z1lU~K_vAm0m8Qk}K$F>|>RPK%<1SI0(G+8q~H zAsjezyP+u!Se4q3GW)`h`NPSRlMoBjCzNPesWJwVTY!o@G8=(6I%4XHGaSiS3MEBK zhgGFv6Jc>L$4jVE!I?TQuwvz_%CyO!bLh94nqK11C2W$*aa2ueGopG8DnBICVUORP zgytv#)49fVXDaR$SukloYC3u7#5H)}1K21=?DKj^U)8G;MS)&Op)g^zR2($<>C*zW z;X7`hLxiIO#J`ANdyAOJle4V%ppa*(+0i3w;8i*BA_;u8gOO6)MY`ueq7stBMJTB; z-a0R>hT*}>z|Gg}@^zDL1MrH+2hsR8 zHc}*9IvuQC^Ju)^#Y{fOr(96rQNPNhxc;mH@W*m206>Lo<*SaaH?~8zg&f&%YiOEG zGiz?*CP>Bci}!WiS=zj#K5I}>DtpregpP_tfZtPa(N<%vo^#WCQ5BTv0vr%Z{)0q+ z)RbfHktUm|lg&U3YM%lMUM(fu}i#kjX9h>GYctkx9Mt_8{@s%!K_EI zScgwy6%_fR?CGJQtmgNAj^h9B#zmaMDWgH55pGuY1Gv7D z;8Psm(vEPiwn#MgJYu4Ty9D|h!?Rj0ddE|&L3S{IP%H4^N!m`60ZwZw^;eg4sk6K{ ziA^`Sbl_4~f&Oo%n;8Ye(tiAdlZKI!Z=|j$5hS|D$bDJ}p{gh$KN&JZYLUjv4h{NY zBJ>X9z!xfDGY z+oh_Z&_e#Q(-}>ssZfm=j$D&4W4FNy&-kAO1~#3Im;F)Nwe{(*75(p=P^VI?X0GFakfh+X-px4a%Uw@fSbmp9hM1_~R>?Z8+ ziy|e9>8V*`OP}4x5JjdWp}7eX;lVxp5qS}0YZek;SNmm7tEeSF*-dI)6U-A%m6YvCgM(}_=k#a6o^%-K4{`B1+}O4x zztDT%hVb;v#?j`lTvlFQ3aV#zkX=7;YFLS$uIzb0E3lozs5`Xy zi~vF+%{z9uLjKvKPhP%x5f~7-Gj+%5N`%^=yk*Qn{`> z;xj&ROY6g`iy2a@{O)V(jk&8#hHACVDXey5a+KDod_Z&}kHM}xt7}Md@pil{2x7E~ zL$k^d2@Ec2XskjrN+IILw;#7((abu;OJii&v3?60x>d_Ma(onIPtcVnX@ELF0aL?T zSmWiL3(dOFkt!x=1O!_0n(cAzZW+3nHJ{2S>tgSK?~cFha^y(l@-Mr2W$%MN{#af8J;V*>hdq!gx=d0h$T7l}>91Wh07)9CTX zh2_ZdQCyFOQ)l(}gft0UZG`Sh2`x-w`5vC2UD}lZs*5 zG76$akzn}Xi))L3oGJ75#pcN=cX3!=57$Ha=hQ2^lwdyU#a}4JJOz6ddR%zae%#4& za)bFj)z=YQela(F#Y|Q#dp}PJghITwXouVaMq$BM?K%cXn9^Y@g43$=O)F&ZlOUom zJiad#dea;-eywBA@e&D6Pdso1?2^(pXiN91?jvcaUyYoKUmvl5G9e$W!okWe*@a<^ z8cQQ6cNSf+UPDx%?_G4aIiybZHHagF{;IcD(dPO!#=u zWfqLcPc^+7Uu#l(Bpxft{*4lv#*u7X9AOzDO z1D9?^jIo}?%iz(_dwLa{ex#T}76ZfN_Z-hwpus9y+4xaUu9cX}&P{XrZVWE{1^0yw zO;YhLEW!pJcbCt3L8~a7>jsaN{V3>tz6_7`&pi%GxZ=V3?3K^U+*ryLSb)8^IblJ0 zSRLNDvIxt)S}g30?s_3NX>F?NKIGrG_zB9@Z>uSW3k2es_H2kU;Rnn%j5qP)!XHKE zPB2mHP~tLCg4K_vH$xv`HbRsJwbZMUV(t=ez;Ec(vyHH)FbfLg`c61I$W_uBB>i^r z&{_P;369-&>23R%qNIULe=1~T$(DA`ev*EWZ6j(B$(te}x1WvmIll21zvygkS%vwG zzkR6Z#RKA2!z!C%M!O>!=Gr0(J0FP=-MN=5t-Ir)of50y10W}j`GtRCsXBakrKtG& zazmITDJMA0C51&BnLY)SY9r)NVTMs);1<=oosS9g31l{4ztjD3#+2H7u_|66b|_*O z;Qk6nalpqdHOjx|K&vUS_6ITgGll;TdaN*ta=M_YtyC)I9Tmr~VaPrH2qb6sd~=AcIxV+%z{E&0@y=DPArw zdV7z(G1hBx7hd{>(cr43^WF%4Y@PXZ?wPpj{OQ#tvc$pABJbvPGvdR`cAtHn)cSEV zrpu}1tJwQ3y!mSmH*uz*x0o|CS<^w%&KJzsj~DU0cLQUxk5B!hWE>aBkjJle8z~;s z-!A=($+}Jq_BTK5^B!`R>!MulZN)F=iXXeUd0w5lUsE5VP*H*oCy(;?S$p*TVvTxwAeWFB$jHyb0593)$zqalVlDX=GcCN1gU0 zlgU)I$LcXZ8Oyc2TZYTPu@-;7<4YYB-``Qa;IDcvydIA$%kHhJKV^m*-zxcvU4viy&Kr5GVM{IT>WRywKQ9;>SEiQD*NqplK-KK4YR`p0@JW)n_{TU3bt0 zim%;(m1=#v2}zTps=?fU5w^(*y)xT%1vtQH&}50ZF!9YxW=&7*W($2kgKyz1mUgfs zfV<*XVVIFnohW=|j+@Kfo!#liQR^x>2yQdrG;2o8WZR+XzU_nG=Ed2rK?ntA;K5B{ z>M8+*A4!Jm^Bg}aW?R?6;@QG@uQ8&oJ{hFixcfEnJ4QH?A4>P=q29oDGW;L;= z9-a0;g%c`C+Ai!UmK$NC*4#;Jp<1=TioL=t^YM)<<%u#hnnfSS`nq63QKGO1L8RzX z@MFDqs1z ztYmxDl@LU)5acvHk)~Z`RW7=aJ_nGD!mOSYD>5Odjn@TK#LY{jf?+piB5AM-CAoT_ z?S-*q7}wyLJzK>N%eMPuFgN)Q_otKP;aqy=D5f!7<=n(lNkYRXVpkB{TAYLYg{|(jtRqYmg$xH zjmq?B(RE4 zQx^~Pt}gxC2~l=K$$-sYy_r$CO(d=+b3H1MB*y_5g6WLaWTXn+TKQ|hNY^>Mp6k*$ zwkovomhu776vQATqT4blf~g;TY(MWCrf^^yfWJvSAB$p5l;jm@o#=!lqw+Lqfq>X= z$6~kxfm7`3q4zUEB;u4qa#BdJxO!;xGm)wwuisj{0y2x{R(IGMrsIzDY9LW>m!Y`= z04sx3IjnYvL<4JqxQ8f7qYd0s2Ig%`ytYPEMKI)s(LD}D@EY>x`VFtqvnADNBdeao zC96X+MxnwKmjpg{U&gP3HE}1=s!lv&D{6(g_lzyF3A`7Jn*&d_kL<;dAFx!UZ>hB8 z5A*%LsAn;VLp>3${0>M?PSQ)9s3}|h2e?TG4_F{}{Cs>#3Q*t$(CUc}M)I}8cPF6% z=+h(Kh^8)}gj(0}#e7O^FQ6`~fd1#8#!}LMuo3A0bN`o}PYsm!Y}sdOz$+Tegc=qT z8x`PH$7lvnhJp{kHWb22l;@7B7|4yL4UOOVM0MP_>P%S1Lnid)+k9{+3D+JFa#Pyf zhVc#&df87APl4W9X)F3pGS>@etfl=_E5tBcVoOfrD4hmVeTY-cj((pkn%n@EgN{0f zwb_^Rk0I#iZuHK!l*lN`ceJn(sI{$Fq6nN& zE<-=0_2WN}m+*ivmIOxB@#~Q-cZ>l136w{#TIJe478`KE7@=a{>SzPHsKLzYAyBQO zAtuuF$-JSDy_S@6GW0MOE~R)b;+0f%_NMrW(+V#c_d&U8Z9+ec4=HmOHw?gdjF(Lu zzra83M_BoO-1b3;9`%&DHfuUY)6YDV21P$C!Rc?mv&{lx#f8oc6?0?x zK08{WP65?#>(vPfA-c=MCY|%*1_<3D4NX zeVTi-JGl2uP_2@0F{G({pxQOXt_d{g_CV6b?jNpfUG9;8yle-^4KHRvZs-_2siata zt+d_T@U$&t*xaD22(fH(W1r$Mo?3dc%Tncm=C6{V9y{v&VT#^1L04vDrLM9qBoZ4@ z6DBN#m57hX7$C(=#$Y5$bJmwA$T8jKD8+6A!-IJwA{WOfs%s}yxUw^?MRZjF$n_KN z6`_bGXcmE#5e4Ym)aQJ)xg3Pg0@k`iGuHe?f(5LtuzSq=nS^5z>vqU0EuZ&75V%Z{ zYyhRLN^)$c6Ds{f7*FBpE;n5iglx5PkHfWrj3`x^j^t z7ntuV`g!9Xg#^3!x)l*}IW=(Tz3>Y5l4uGaB&lz{GDjm2D5S$CExLT`I1#n^lBH7Y zDgpMag@`iETKAI=p<5E#LTkwzVR@=yY|uBVI1HG|8h+d;G-qfuj}-ZR6fN>EfCCW z9~wRQoAPEa#aO?3h?x{YvV*d+NtPkf&4V0k4|L=uj!U{L+oLa(z#&iuhJr3-PjO3R z5s?=nn_5^*^Rawr>>Nr@K(jwkB#JK-=+HqwfdO<+P5byeim)wvqGlP-P|~Nse8=XF zz`?RYB|D6SwS}C+YQv+;}k6$-%D(@+t14BL@vM z2q%q?f6D-A5s$_WY3{^G0F131bbh|g!}#BKw=HQ7mx;Dzg4Z*bTLQSfo{ed{4}NZW zfrRm^Ca$rlE{Ue~uYv>R9{3smwATcdM_6+yWIO z*ZRH~uXE@#p$XTbCt5j7j2=86e{9>HIB6xDzV+vAo&B?KUiMP|ttOElepnl%|DPqL b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN literal 0 HcmV?d00001 diff --git a/demo/react-spa/public/manifest.json b/demo/react-spa/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/demo/react-spa/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/demo/react-spa/public/robots.txt b/demo/react-spa/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/demo/react-spa/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/demo/react-spa/src/App.css b/demo/react-spa/src/App.css new file mode 100644 index 0000000..74b5e05 --- /dev/null +++ b/demo/react-spa/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/demo/react-spa/src/App.js b/demo/react-spa/src/App.js new file mode 100644 index 0000000..70fedad --- /dev/null +++ b/demo/react-spa/src/App.js @@ -0,0 +1,58 @@ +import React, { useState } from 'react'; +import './App.css'; + +function App() { + const [ resp, changeResponse ] = useState(null); + const [ username, changeUsername ] = useState(''); + const [ password, changePassword ] = useState(''); + + function onSubmit(e) { + e.preventDefault(); + return fetch('http://localhost:8000/dj-rest-auth/login/', { + method: 'POST', + credentials: 'omit', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({username, password}) + }).then(resp => resp.json()).then(data => { + changeResponse(data) + }) + } + + return ( +
+
+

+ Login +

+

+ + {resp && + Response: {JSON.stringify(resp)} + } +

+
+
+ changeUsername(e.target.value)} + value={username} + type={'input'} + name={'username'}/> +
+
+ changePassword(e.target.value)} + value={password} + type={'password'} + name={'password'}/> +
+ +
+
+
+ ); +} + +export default App; diff --git a/demo/react-spa/src/App.test.js b/demo/react-spa/src/App.test.js new file mode 100644 index 0000000..4db7ebc --- /dev/null +++ b/demo/react-spa/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + const { getByText } = render(); + const linkElement = getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/demo/react-spa/src/index.css b/demo/react-spa/src/index.css new file mode 100644 index 0000000..ec2585e --- /dev/null +++ b/demo/react-spa/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/demo/react-spa/src/index.js b/demo/react-spa/src/index.js new file mode 100644 index 0000000..f5185c1 --- /dev/null +++ b/demo/react-spa/src/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +ReactDOM.render( + + + , + document.getElementById('root') +); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.unregister(); diff --git a/demo/react-spa/src/logo.svg b/demo/react-spa/src/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/demo/react-spa/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/demo/react-spa/src/serviceWorker.js b/demo/react-spa/src/serviceWorker.js new file mode 100644 index 0000000..b04b771 --- /dev/null +++ b/demo/react-spa/src/serviceWorker.js @@ -0,0 +1,141 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' }, + }) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then(registration => { + registration.unregister(); + }) + .catch(error => { + console.error(error.message); + }); + } +} diff --git a/demo/react-spa/src/setupTests.js b/demo/react-spa/src/setupTests.js new file mode 100644 index 0000000..74b1a27 --- /dev/null +++ b/demo/react-spa/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom/extend-expect'; diff --git a/demo/requirements.pip b/demo/requirements.pip index 64a3488..e9276aa 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -4,4 +4,5 @@ djangorestframework>=3.11.0 djangorestframework-simplejwt==4.4.0 django-allauth>=0.24.1 django-rest-swagger==2.0.7 -coreapi==2.3.3 \ No newline at end of file +django-cors-headers==3.2.1 +coreapi==2.3.3 From a7f54991c1fe4ad675d3d74ab33b40d20272ca3f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 13:51:31 -0500 Subject: [PATCH 110/216] Adds POC Login Form in React --- demo/demo/settings.py | 7 ++++++- demo/react-spa/src/App.css | 2 ++ demo/react-spa/src/App.js | 22 +++++++++++++++------- demo/react-spa/src/index.css | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index c001399..4496f0d 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -116,10 +116,14 @@ ACCOUNT_EMAIL_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = 'username' ACCOUNT_EMAIL_VERIFICATION = 'optional' +REST_USE_JWT = True +JWT_AUTH_COOKIE = 'auth' + REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', + 'dj_rest_auth.utils.JWTCookieAuthentication' ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' } @@ -130,4 +134,5 @@ SWAGGER_SETTINGS = { } -CORS_ORIGIN_ALLOW_ALL = True # For demo purposes only. Use a white list in the real world. \ No newline at end of file +# For demo purposes only. Use a white list in the real world. +CORS_ORIGIN_ALLOW_ALL = True diff --git a/demo/react-spa/src/App.css b/demo/react-spa/src/App.css index 74b5e05..92fd3ac 100644 --- a/demo/react-spa/src/App.css +++ b/demo/react-spa/src/App.css @@ -1,5 +1,6 @@ .App { text-align: center; + width: 100%; } .App-logo { @@ -22,6 +23,7 @@ justify-content: center; font-size: calc(10px + 2vmin); color: white; + width: 100%; } .App-link { diff --git a/demo/react-spa/src/App.js b/demo/react-spa/src/App.js index 70fedad..a8546a4 100644 --- a/demo/react-spa/src/App.js +++ b/demo/react-spa/src/App.js @@ -18,21 +18,28 @@ function App() { body: JSON.stringify({username, password}) }).then(resp => resp.json()).then(data => { changeResponse(data) - }) + }).catch(error => console.log('error ->', error)) } return (
-

+

Login -

-

- +

+
+ Inspect the network requests in your browser to view headers returned by dj-rest-auth. +
+
{resp && - Response: {JSON.stringify(resp)} +
+ + {JSON.stringify(resp)} + +
} -

+
+
+
); diff --git a/demo/react-spa/src/index.css b/demo/react-spa/src/index.css index ec2585e..379ece5 100644 --- a/demo/react-spa/src/index.css +++ b/demo/react-spa/src/index.css @@ -1,13 +1,48 @@ body { margin: 0; + width: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + display: flex; + flex-direction: column; +} + +body div { + flex-direction: row; + text-align: center; + display: flex; + justify-content: center; +} + +ul { + width: 240px; + font-size: 11px; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; + word-break: break-all; + height: 200px; + color: #0f0f0f; +} + +.response { + margin: 20px; + background-color: #eee; + width: 80%; + height: 200px; + overflow: scroll; +} + +.help-text { + font-size: 11px; + margin: 20px; +} + +form > div { + margin: 20px; } From c4130d1812159fe1ea8f4f330d1dedaf716c94b4 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 14:00:06 -0500 Subject: [PATCH 111/216] Adds more help to docs --- docs/installation.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/installation.rst b/docs/installation.rst index fa4345d..867286f 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -269,3 +269,18 @@ By default ``dj-rest-auth`` uses Django's Token-based authentication. If you wan .. code-block:: python REST_USE_JWT = True + +4. Declare what you want the cookie key to be called. + +.. code-block:: python + + JWT_AUTH_COOKIE = 'my-app-auth' + + +This example value above will cause dj-rest-auth to return a `Set-Cookie` header that looks like this: + +.. code-block:: bash + + Set-Cookie: my-app-auth=xxxxxxxxxxxxx; expires=Sat, 28 Mar 2020 18:59:00 GMT; HttpOnly; Max-Age=300; Path=/ + +``JWT_AUTH_COOKIE`` is also used while authenticating each request against protected views. \ No newline at end of file From 66beda5efc9e6354cdbd6f8f9a9f4f1cfdbf673f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 14:05:20 -0500 Subject: [PATCH 112/216] Updates changelog --- docs/changelog.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 405df48..78186af 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,9 +9,5 @@ Welcome Dj-Rest-Auth ----- Replaces `rest_framework_jwt` with `djangorestframework-simplejwt`. - -- rest_framework_jwt is now unmaintained so we've switched to simplewjt, -which is a strong jwt library with a large community. -- This change means you may need to change your client code if you're upgrading - from the previous version. Example: token -> access_token. Please see demo - for more information. \ No newline at end of file +Rest_framework_jwt is now unmaintained so we've switched to simplewjt, which is a strong jwt library with a large community. +This change means you may need to change your client code if you're upgrading from the previous version. \ No newline at end of file From c05903baace80f945be3efa4376b534e6f6bf912 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 14:15:50 -0500 Subject: [PATCH 113/216] Adds note about React SPA --- docs/demo.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/demo.rst b/docs/demo.rst index ecceddd..6c67fe9 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -1,9 +1,9 @@ Demo project ============ -The idea of creating demo project was to show how you can potentially use +This demo project shows how you can potentially use dj-rest-auth app with jQuery on frontend. -Do these steps to make it running (ideally in virtualenv). +To run this locally follow the steps below. .. code-block:: python @@ -14,4 +14,14 @@ Do these steps to make it running (ideally in virtualenv). python manage.py migrate --settings=demo.settings --noinput python manage.py runserver --settings=demo.settings -Now, go to ``http://127.0.0.1:8000/`` in your browser. + +Now, go to ``http://127.0.0.1:8000/`` in your browser. There is also a +Single Page Application (SPA) in React within the ``demo/`` directory. To run this do: + +.. code-block:: python + cd react-spa/ + yarn # or npm install + yarn run start + + +Now, go to ``https://localhost:3000`` in your browser to view it. From 53ca547ed2fa925ec9f4d1ae0e451f9bde3d1fca Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 14:19:46 -0500 Subject: [PATCH 114/216] Updates RST Docs --- docs/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 7730562..1f57578 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,7 +44,7 @@ master_doc = 'index' # General information about the project. project = u'dj-rest-auth' -copyright = u'2018, iMerica Inc.' +copyright = u'2020, @iMerica' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -227,7 +227,7 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'dj-rest-auth', u'dj-rest-auth Documentation', - [u'iMerica Inc.'], 1) + [u'@iMerica'], 1) ] # If true, show URL addresses after external links. @@ -241,7 +241,7 @@ man_pages = [ # dir menu entry, description, category) texinfo_documents = [ ('index', 'dj-rest-auth', u'dj-rest-auth Documentation', - u'iMerica Inc.', 'dj-rest-auth', 'One line description of project.', + u'@iMerica', 'dj-rest-auth', 'One line description of project.', 'Miscellaneous'), ] From 68dbdf7e3e4215ba1e8bd1d078a6d9eb0731eb2b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 28 Mar 2020 14:24:21 -0500 Subject: [PATCH 115/216] Fixes docs code sample --- docs/demo.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/demo.rst b/docs/demo.rst index 6c67fe9..b8bc2f1 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -19,6 +19,7 @@ Now, go to ``http://127.0.0.1:8000/`` in your browser. There is also a Single Page Application (SPA) in React within the ``demo/`` directory. To run this do: .. code-block:: python + cd react-spa/ yarn # or npm install yarn run start From de25807805e98db988c6198a7a65bfef2efeb6e9 Mon Sep 17 00:00:00 2001 From: Anuj Sharma Date: Mon, 30 Mar 2020 22:02:12 +0530 Subject: [PATCH 116/216] Note in docs to add allauth urls if account email verification is mandatory Update docs to add `account_email_verification_sent` endpoint while using `registration`. Without this endpoint, if email verification is set to **MANDATORY** , it gives error ``` Reverse for 'account_email_verification_sent' not found. 'account_email_verification_sent' is not a valid view function or pattern name. ``` This is a copy PR of [#577](https://github.com/Tivix/django-rest-auth/pull/577) in in upstream project. --- docs/api_endpoints.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index a4e602a..be3b096 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -61,6 +61,11 @@ Registration - key + .. note:: If you set account email verification as mandatory, you have to add the VerifyEmailView with the used `name`. + You need to import the view: ``from rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name: + ``url(r'^rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. + + Social Media Authentication --------------------------- From 3c896603ade6fbabe3c734688b16bcd3afa02ba0 Mon Sep 17 00:00:00 2001 From: Anuj Sharma Date: Tue, 31 Mar 2020 07:57:14 +0530 Subject: [PATCH 117/216] Update module name Changed module name to `dj_rest_auth` --- docs/api_endpoints.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index be3b096..c253f7b 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -62,8 +62,8 @@ Registration - key .. note:: If you set account email verification as mandatory, you have to add the VerifyEmailView with the used `name`. - You need to import the view: ``from rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name: - ``url(r'^rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. + You need to import the view: ``from dj_rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name: + ``url(r'^dj-rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. From 1c485bcbce3024d7b2e97e062c90c8371823f2c9 Mon Sep 17 00:00:00 2001 From: Anuj Sharma Date: Tue, 31 Mar 2020 16:24:43 +0530 Subject: [PATCH 118/216] Update documentation Update documentation for `old_password` validation skip. --- docs/api_endpoints.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index c253f7b..614c21e 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -35,7 +35,7 @@ Basic - new_password2 - old_password - .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. + .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. If user has no usable password set (registration using social account), validation will be skipped for `old_password` to allow to set a new password. .. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change - /dj-rest-auth/user/ (GET, PUT, PATCH) From 26b6e220437b3900e96303a9e80e1034f6b3688e Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Wed, 1 Apr 2020 18:54:16 -0400 Subject: [PATCH 119/216] blacklist refresh token on logout if REST_USE_JWT and added .idea to gitignore --- .gitignore | 3 +++ dj_rest_auth/views.py | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 84cc2de..136132c 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,9 @@ target/ # Jupyter Notebook .ipynb_checkpoints +# IDE +.idea + # pyenv .python-version diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index c5ba7fc..7f2e651 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -11,6 +11,8 @@ from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView +from rest_framework_simplejwt.exceptions import TokenError +from rest_framework_simplejwt.tokens import RefreshToken from .app_settings import (JWTSerializer, LoginSerializer, PasswordChangeSerializer, @@ -134,13 +136,29 @@ class LogoutView(APIView): pass if getattr(settings, 'REST_SESSION_LOGIN', True): django_logout(request) - response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) + # add refresh token to blacklist + try: + token = RefreshToken(request.data['refresh']) + token.blacklist() + except KeyError: + response = Response({"detail": _("Refresh token was not included.")}, + status=status.HTTP_401_UNAUTHORIZED) + except TokenError as e: + if e.args[0] == 'Token is blacklisted': + response = Response({"detail": _("Token is already blacklisted.")}, + status=status.HTTP_404_NOT_FOUND) + except AttributeError as e: + # warn user blacklist is not enabled if not using JWT_AUTH_COOKIE + if not cookie_name: + if e.args[0] == "'RefreshToken' object has no attribute 'blacklist'": + response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, + status=status.HTTP_501_NOT_IMPLEMENTED) return response From 241011a353e0a3f4b7a62890bda71deb803c78bc Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Wed, 1 Apr 2020 18:56:41 -0400 Subject: [PATCH 120/216] attempt to blacklist token if no JWT_AUTH_COOKIE is found --- dj_rest_auth/views.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 7f2e651..365545e 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -142,20 +142,20 @@ class LogoutView(APIView): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) - # add refresh token to blacklist - try: - token = RefreshToken(request.data['refresh']) - token.blacklist() - except KeyError: - response = Response({"detail": _("Refresh token was not included.")}, - status=status.HTTP_401_UNAUTHORIZED) - except TokenError as e: - if e.args[0] == 'Token is blacklisted': - response = Response({"detail": _("Token is already blacklisted.")}, - status=status.HTTP_404_NOT_FOUND) - except AttributeError as e: - # warn user blacklist is not enabled if not using JWT_AUTH_COOKIE - if not cookie_name: + else: + # add refresh token to blacklist + try: + token = RefreshToken(request.data['refresh']) + token.blacklist() + except KeyError: + response = Response({"detail": _("Refresh token was not included.")}, + status=status.HTTP_401_UNAUTHORIZED) + except TokenError as e: + if e.args[0] == 'Token is blacklisted': + response = Response({"detail": _("Token is already blacklisted.")}, + status=status.HTTP_404_NOT_FOUND) + except AttributeError as e: + # warn user blacklist is not enabled if e.args[0] == "'RefreshToken' object has no attribute 'blacklist'": response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, status=status.HTTP_501_NOT_IMPLEMENTED) From 9180f3967a17051b6c9d633300a972050ea4d374 Mon Sep 17 00:00:00 2001 From: Michael <487897+iMerica@users.noreply.github.com> Date: Wed, 1 Apr 2020 18:41:23 -0500 Subject: [PATCH 121/216] Revert "Update documentation" This reverts commit 1c485bcbce3024d7b2e97e062c90c8371823f2c9. --- docs/api_endpoints.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index 614c21e..c253f7b 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -35,7 +35,7 @@ Basic - new_password2 - old_password - .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. If user has no usable password set (registration using social account), validation will be skipped for `old_password` to allow to set a new password. + .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. .. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change - /dj-rest-auth/user/ (GET, PUT, PATCH) From aaab91f82bb81c74f8df99c274983f5be27cfefc Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Wed, 1 Apr 2020 21:28:02 -0400 Subject: [PATCH 122/216] updated exceptions to raise error if not not handled --- dj_rest_auth/tests/test_api.py | 11 +++++++++++ dj_rest_auth/views.py | 14 +++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 0134560..f373dcc 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -555,3 +555,14 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) resp = self.get('/protected-view/') self.assertEquals(resp.status_code, 200) + + @override_settings(REST_USE_JWT=True) + def test_blacklisting(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + self.post(self.login_url, data=payload, status_code=200) + resp = self.post(self.logout_url, status=200) + pass diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 365545e..c79423f 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -147,18 +147,26 @@ class LogoutView(APIView): try: token = RefreshToken(request.data['refresh']) token.blacklist() + except KeyError: - response = Response({"detail": _("Refresh token was not included.")}, + response = Response({"detail": _("Refresh token was not included in request data.")}, status=status.HTTP_401_UNAUTHORIZED) + except TokenError as e: - if e.args[0] == 'Token is blacklisted': + if hasattr(e, 'args') and 'Token is blacklisted' in e.args: response = Response({"detail": _("Token is already blacklisted.")}, status=status.HTTP_404_NOT_FOUND) + else: + raise + except AttributeError as e: # warn user blacklist is not enabled - if e.args[0] == "'RefreshToken' object has no attribute 'blacklist'": + if hasattr(e, 'args') and "'RefreshToken' object has no attribute 'blacklist'" in e.args: response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, status=status.HTTP_501_NOT_IMPLEMENTED) + else: + raise + return response From 8f97cbc6179675bd14a587c8c471ff574d446710 Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Thu, 2 Apr 2020 10:01:07 -0400 Subject: [PATCH 123/216] added rest_framework_simplejwt.token_blacklist to settings for tests, return 500 if error occurs instead of raising, added unit tests for blacklist --- Makefile | 2 ++ dj_rest_auth/tests/settings.py | 2 ++ dj_rest_auth/tests/test_api.py | 34 ++++++++++++++++++++++++++++++---- dj_rest_auth/views.py | 28 +++++++++++++++------------- 4 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..103ee60 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +test: + coverage run --source=dj_rest_auth setup.py test diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index 3d02309..5f57f91 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -94,6 +94,8 @@ INSTALLED_APPS = [ 'dj_rest_auth', 'dj_rest_auth.registration', + + 'rest_framework_simplejwt.token_blacklist' ] SECRET_KEY = "38dh*skf8sjfhs287dh&^hd8&3hdg*j2&sd" diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index f373dcc..0e5a3c6 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -1,6 +1,7 @@ +import json +from unittest.mock import patch + from allauth.account import app_settings as account_app_settings -from dj_rest_auth.registration.app_settings import register_permission_classes -from dj_rest_auth.registration.views import RegisterView from django.conf import settings from django.contrib.auth import get_user_model from django.core import mail @@ -9,6 +10,8 @@ from django.utils.encoding import force_text from rest_framework import status from rest_framework.test import APIRequestFactory +from dj_rest_auth.registration.app_settings import register_permission_classes +from dj_rest_auth.registration.views import RegisterView from .mixins import CustomPermissionClass, TestsMixin try: @@ -556,6 +559,20 @@ class APIBasicTests(TestsMixin, TestCase): resp = self.get('/protected-view/') self.assertEquals(resp.status_code, 200) + @override_settings(REST_USE_JWT=True) + @patch('rest_framework_simplejwt.tokens.BlacklistMixin.blacklist') + def test_blacklisting_not_installed(self, mocked_blacklist): + mocked_blacklist.side_effect = AttributeError(f"'RefreshToken' object has no attribute 'blacklist'") + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + token = resp.data['refresh_token'] + resp = self.post(self.logout_url, status=200, data={'refresh': token}) + self.assertEqual(resp.status_code, 501) + @override_settings(REST_USE_JWT=True) def test_blacklisting(self): payload = { @@ -563,6 +580,15 @@ class APIBasicTests(TestsMixin, TestCase): "password": self.PASS } get_user_model().objects.create_user(self.USERNAME, '', self.PASS) - self.post(self.login_url, data=payload, status_code=200) + resp = self.post(self.login_url, data=payload, status_code=200) + token = resp.data['refresh_token'] resp = self.post(self.logout_url, status=200) - pass + self.assertEqual(resp.status_code, 401) + resp = self.post(self.logout_url, status=200, data={'refresh': '1'}) + self.assertEqual(resp.status_code, 404) + resp = self.post(self.logout_url, status=200, data={'refresh': token}) + self.assertEqual(resp.status_code, 200) + resp = self.post(self.logout_url, status=200, data={'refresh': token}) + self.assertEqual(resp.status_code, 404) + resp = self.post(self.logout_url, status=200, data=json.dumps({'refresh': token})) + self.assertEqual(resp.status_code, 500) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index c79423f..f3bb3fe 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -147,25 +147,27 @@ class LogoutView(APIView): try: token = RefreshToken(request.data['refresh']) token.blacklist() - except KeyError: response = Response({"detail": _("Refresh token was not included in request data.")}, status=status.HTTP_401_UNAUTHORIZED) - except TokenError as e: - if hasattr(e, 'args') and 'Token is blacklisted' in e.args: - response = Response({"detail": _("Token is already blacklisted.")}, - status=status.HTTP_404_NOT_FOUND) - else: - raise + except (TokenError, AttributeError, TypeError) as error: + if hasattr(error, 'args'): + if 'Token is blacklisted' in error.args or 'Token is invalid or expired' in error.args: + response = Response({"detail": _(error.args[0])}, + status=status.HTTP_404_NOT_FOUND) + + # warn user blacklist is not enabled + elif "'RefreshToken' object has no attribute 'blacklist'" in error.args: + response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, + status=status.HTTP_501_NOT_IMPLEMENTED) + else: + response = Response({"detail": _("An error has occurred.")}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) - except AttributeError as e: - # warn user blacklist is not enabled - if hasattr(e, 'args') and "'RefreshToken' object has no attribute 'blacklist'" in e.args: - response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, - status=status.HTTP_501_NOT_IMPLEMENTED) else: - raise + response = Response({"detail": _("No attr error has occurred.")}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response From 8b284f8adf86b2ff29c49aa4c66aaa26325d67f9 Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Thu, 2 Apr 2020 10:07:23 -0400 Subject: [PATCH 124/216] fixed typo in 500 response --- dj_rest_auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index f3bb3fe..f3d6c72 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -166,7 +166,7 @@ class LogoutView(APIView): status=status.HTTP_500_INTERNAL_SERVER_ERROR) else: - response = Response({"detail": _("No attr error has occurred.")}, + response = Response({"detail": _("An error has occurred.")}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response From 3304a6b3d39b2b02af5806617d1ec0d6b4d4f1f4 Mon Sep 17 00:00:00 2001 From: Jonathan Henrique Maia de Moraes Date: Fri, 3 Apr 2020 14:50:02 -0300 Subject: [PATCH 125/216] Fix JWTSerializer USER_DETAILS_SERIALIZER import Related to #30 --- dj_rest_auth/serializers.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index 3e0132d..efd455e 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -4,6 +4,7 @@ from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm from django.contrib.auth.tokens import default_token_generator from django.utils.encoding import force_text from django.utils.http import urlsafe_base64_decode as uid_decoder +from django.utils.module_loading import import_string from django.utils.translation import ugettext_lazy as _ from rest_framework import exceptions, serializers from rest_framework.exceptions import ValidationError @@ -145,7 +146,14 @@ class JWTSerializer(serializers.Serializer): JWTSerializer. Defining it here to avoid circular imports """ rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {}) - JWTUserDetailsSerializer = rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer) + + JWTUserDetailsSerializer = import_string( + rest_auth_serializers.get( + 'USER_DETAILS_SERIALIZER', + 'dj_rest_auth.serializers.UserDetailsSerializer' + ) + ) + user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data return user_data From 058df2b1ce58bc6b1302e17aa05445c8139a511b Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Apr 2020 20:39:11 -0500 Subject: [PATCH 126/216] Bumps version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index da11337..f3c7f8c 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='1.0.0', + version='1.0.1', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From b55fcc2361f0e0ff46933cbed79b0851675d924a Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Tue, 7 Apr 2020 20:24:15 -0400 Subject: [PATCH 127/216] deleted make file and adding testing section to README --- Makefile | 2 -- README.md | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 103ee60..0000000 --- a/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - coverage run --source=dj_rest_auth setup.py test diff --git a/README.md b/README.md index b87ba30..deefdb5 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,12 @@ REST_USE_JWT = True JWT_AUTH_COOKIE = 'jwt-auth' ``` +### Testing +To run the tests within a virtualenv, run `python runtests.py` from the repository directory. +The easiest way to run test coverage is with [`coverage`](https://pypi.org/project/coverage/), +which runs the tests against all supported Django installs. To run the test coverage +within a virtualenv, run `coverage run ./runtests.py` from the repository directory then run `coverage report`. ### Documentation From d5d9c69aa3aaea8c1a5d77d20439bb62f8420a03 Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Thu, 9 Apr 2020 20:53:04 -0400 Subject: [PATCH 128/216] check if blacklist is installed and warn user to delete client side if cookies and blacklist are not enabled --- dj_rest_auth/tests/test_api.py | 11 ++++++----- dj_rest_auth/views.py | 16 +++++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 0e5a3c6..4c4de9e 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -1,5 +1,4 @@ import json -from unittest.mock import patch from allauth.account import app_settings as account_app_settings from django.conf import settings @@ -560,9 +559,8 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEquals(resp.status_code, 200) @override_settings(REST_USE_JWT=True) - @patch('rest_framework_simplejwt.tokens.BlacklistMixin.blacklist') - def test_blacklisting_not_installed(self, mocked_blacklist): - mocked_blacklist.side_effect = AttributeError(f"'RefreshToken' object has no attribute 'blacklist'") + def test_blacklisting_not_installed(self): + settings.INSTALLED_APPS.remove('rest_framework_simplejwt.token_blacklist') payload = { "username": self.USERNAME, "password": self.PASS @@ -571,7 +569,10 @@ class APIBasicTests(TestsMixin, TestCase): resp = self.post(self.login_url, data=payload, status_code=200) token = resp.data['refresh_token'] resp = self.post(self.logout_url, status=200, data={'refresh': token}) - self.assertEqual(resp.status_code, 501) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.data["detail"], + "Neither cookies or blacklist are enabled, so the token has not been deleted server side. " + "Please make sure the token is deleted client side.") @override_settings(REST_USE_JWT=True) def test_blacklisting(self): diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index f3d6c72..325466e 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -134,19 +134,23 @@ class LogoutView(APIView): request.user.auth_token.delete() except (AttributeError, ObjectDoesNotExist): pass + if getattr(settings, 'REST_SESSION_LOGIN', True): django_logout(request) response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) + if getattr(settings, 'REST_USE_JWT', False): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) - else: + + elif 'rest_framework_simplejwt.token_blacklist' in settings.INSTALLED_APPS: # add refresh token to blacklist try: token = RefreshToken(request.data['refresh']) token.blacklist() + except KeyError: response = Response({"detail": _("Refresh token was not included in request data.")}, status=status.HTTP_401_UNAUTHORIZED) @@ -157,10 +161,6 @@ class LogoutView(APIView): response = Response({"detail": _(error.args[0])}, status=status.HTTP_404_NOT_FOUND) - # warn user blacklist is not enabled - elif "'RefreshToken' object has no attribute 'blacklist'" in error.args: - response = Response({"detail": _("Blacklist is not enabled in INSTALLED_APPS.")}, - status=status.HTTP_501_NOT_IMPLEMENTED) else: response = Response({"detail": _("An error has occurred.")}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -169,6 +169,12 @@ class LogoutView(APIView): response = Response({"detail": _("An error has occurred.")}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + else: + response = Response({ + "detail": _("Neither cookies or blacklist are enabled, so the token has not been deleted server " + "side. Please make sure the token is deleted client side." + )}, status=status.HTTP_200_OK) + return response From 91c052fe47c1d98579260e6606fb254a5e6c34db Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Thu, 9 Apr 2020 21:00:48 -0400 Subject: [PATCH 129/216] changed invalid or expired and blacklisted errors to 401 --- dj_rest_auth/tests/test_api.py | 9 +++++++-- dj_rest_auth/views.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 4c4de9e..c53be66 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -583,13 +583,18 @@ class APIBasicTests(TestsMixin, TestCase): get_user_model().objects.create_user(self.USERNAME, '', self.PASS) resp = self.post(self.login_url, data=payload, status_code=200) token = resp.data['refresh_token'] + # test refresh token not included in request data resp = self.post(self.logout_url, status=200) self.assertEqual(resp.status_code, 401) + # test token is invalid or expired resp = self.post(self.logout_url, status=200, data={'refresh': '1'}) - self.assertEqual(resp.status_code, 404) + self.assertEqual(resp.status_code, 401) + # test successful logout resp = self.post(self.logout_url, status=200, data={'refresh': token}) self.assertEqual(resp.status_code, 200) + # test token is blacklisted resp = self.post(self.logout_url, status=200, data={'refresh': token}) - self.assertEqual(resp.status_code, 404) + self.assertEqual(resp.status_code, 401) + # test other TokenError, AttributeError, TypeError (invalid format) resp = self.post(self.logout_url, status=200, data=json.dumps({'refresh': token})) self.assertEqual(resp.status_code, 500) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 325466e..25ebe31 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -159,7 +159,7 @@ class LogoutView(APIView): if hasattr(error, 'args'): if 'Token is blacklisted' in error.args or 'Token is invalid or expired' in error.args: response = Response({"detail": _(error.args[0])}, - status=status.HTTP_404_NOT_FOUND) + status=status.HTTP_401_UNAUTHORIZED) else: response = Response({"detail": _("An error has occurred.")}, From 1c64c0d398615b3a9590658837a7e7a68ea051ac Mon Sep 17 00:00:00 2001 From: Marc LaBelle Date: Thu, 9 Apr 2020 21:03:41 -0400 Subject: [PATCH 130/216] changed spacing for better readability --- dj_rest_auth/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 25ebe31..114856b 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -137,6 +137,7 @@ class LogoutView(APIView): if getattr(settings, 'REST_SESSION_LOGIN', True): django_logout(request) + response = Response({"detail": _("Successfully logged out.")}, status=status.HTTP_200_OK) From 40125b15c44aaa440fa457e4a25b1c99191159d0 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 13 Apr 2020 23:05:06 -0500 Subject: [PATCH 131/216] Bumps version for release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f3c7f8c..6e897fc 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='1.0.1', + version='1.0.2', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From 40208ea0b63ab6ad7cc454d43cf9eabc09f9f8b6 Mon Sep 17 00:00:00 2001 From: Rami Chowdhury Date: Tue, 14 Apr 2020 13:26:52 -0400 Subject: [PATCH 132/216] Don't _require_ rest_framework_simplejwt Rather than importing it at the top level (which breaks dj-rest-auth entirely if you aren't using JWTs and don't have the library installed), only do the import if the user has the relevant setting enabled. --- dj_rest_auth/views.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 114856b..674c9b8 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -11,8 +11,20 @@ from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework_simplejwt.exceptions import TokenError -from rest_framework_simplejwt.tokens import RefreshToken + +if getattr(settings, 'REST_USE_JWT'): + from rest_framework_simplejwt.exceptions import TokenError + from rest_framework_simplejwt.tokens import RefreshToken +else: + # NOTE: these are not actually used except if `REST_USE_JWT` is True, but + # ensuring they're defined anyway in case + + class TokenError(Exception): + pass + + class RefreshToken: + pass + from .app_settings import (JWTSerializer, LoginSerializer, PasswordChangeSerializer, From 506912f83245ad6844527a5839bec6e34dc2a065 Mon Sep 17 00:00:00 2001 From: Rami Chowdhury Date: Tue, 14 Apr 2020 15:20:43 -0400 Subject: [PATCH 133/216] Move import inside response method This is not idiomatic, but I don't see another neat way to move it out of the top level and still handle testing / other situations where the settings are modified on-the-fly. --- dj_rest_auth/views.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 674c9b8..b5fcdb8 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -12,20 +12,6 @@ from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -if getattr(settings, 'REST_USE_JWT'): - from rest_framework_simplejwt.exceptions import TokenError - from rest_framework_simplejwt.tokens import RefreshToken -else: - # NOTE: these are not actually used except if `REST_USE_JWT` is True, but - # ensuring they're defined anyway in case - - class TokenError(Exception): - pass - - class RefreshToken: - pass - - from .app_settings import (JWTSerializer, LoginSerializer, PasswordChangeSerializer, PasswordResetConfirmSerializer, @@ -154,6 +140,13 @@ class LogoutView(APIView): status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): + # NOTE: this import occurs here rather than at the top level + # because JWT support is optional, and if `REST_USE_JWT` isn't + # True we shouldn't need the dependency + from rest_framework_simplejwt.exceptions import TokenError + from rest_framework_simplejwt.tokens import RefreshToken + + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) From 8583c5597e4435daaca987bfae363d14032b4f4f Mon Sep 17 00:00:00 2001 From: VolkerSchiewe Date: Wed, 15 Apr 2020 10:44:54 +0200 Subject: [PATCH 134/216] Add token endpoints from rest_framework_simplejwt to url config --- dj_rest_auth/urls.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index d3bfc42..3ff64c6 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -2,6 +2,7 @@ from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView, PasswordResetConfirmView, PasswordResetView, UserDetailsView) from django.conf.urls import url +from django.conf import settings urlpatterns = [ # URLs that do not require a session or valid token @@ -16,3 +17,13 @@ urlpatterns = [ url(r'^password/change/$', PasswordChangeView.as_view(), name='rest_password_change'), ] + +if getattr(settings, 'REST_USE_JWT', True): + from rest_framework_simplejwt.views import ( + TokenRefreshView, TokenVerifyView, + ) + + urlpatterns += [ + url(r'token/verify/$', TokenVerifyView.as_view(), name='token_verify'), + url(r'^token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'), + ] From 5e8cca163374a5006ca650ec9ceb17aab6c1f5d6 Mon Sep 17 00:00:00 2001 From: Serhiy Romanov Date: Wed, 15 Apr 2020 16:26:54 +0300 Subject: [PATCH 135/216] Use import_string for getting TokenModel instead of passing class --- dj_rest_auth/models.py | 6 ++---- docs/configuration.rst | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/dj_rest_auth/models.py b/dj_rest_auth/models.py index 654c0ae..8410821 100644 --- a/dj_rest_auth/models.py +++ b/dj_rest_auth/models.py @@ -1,6 +1,4 @@ from django.conf import settings -from rest_framework.authtoken.models import Token as DefaultTokenModel +from django.utils.module_loading import import_string -# Register your models here. - -TokenModel = getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel) +TokenModel = import_string(getattr(settings, 'REST_AUTH_TOKEN_MODEL', 'rest_framework.authtoken.models.Token')) diff --git a/docs/configuration.rst b/docs/configuration.rst index c841e60..aac74c2 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -40,9 +40,9 @@ Configuration .. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance -- **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models`` +- **REST_AUTH_TOKEN_MODEL** - path to model class for tokens, default value ``'rest_framework.authtoken.models.Token'`` -- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``dj_rest_auth.utils.default_create_token``. +- **REST_AUTH_TOKEN_CREATOR** - path to callable or callable for creating tokens, default value ``dj_rest_auth.utils.default_create_token``. - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) From d882edcf10f2a5c6c537a40b85e1b719a5b015f0 Mon Sep 17 00:00:00 2001 From: Michael <487897+iMerica@users.noreply.github.com> Date: Thu, 16 Apr 2020 00:28:05 -0500 Subject: [PATCH 136/216] Update dj_rest_auth/urls.py Co-Authored-By: Daniele Tricoli --- dj_rest_auth/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 3ff64c6..2fc1694 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -24,6 +24,6 @@ if getattr(settings, 'REST_USE_JWT', True): ) urlpatterns += [ - url(r'token/verify/$', TokenVerifyView.as_view(), name='token_verify'), + url(r'^token/verify/$', TokenVerifyView.as_view(), name='token_verify'), url(r'^token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'), ] From 17e92304977c05c1aae6da4a7d31d5ce8bc28231 Mon Sep 17 00:00:00 2001 From: Michael <487897+iMerica@users.noreply.github.com> Date: Thu, 16 Apr 2020 00:28:14 -0500 Subject: [PATCH 137/216] Update dj_rest_auth/urls.py Co-Authored-By: Daniele Tricoli --- dj_rest_auth/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 2fc1694..9c79691 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -18,7 +18,7 @@ urlpatterns = [ name='rest_password_change'), ] -if getattr(settings, 'REST_USE_JWT', True): +if getattr(settings, 'REST_USE_JWT', False): from rest_framework_simplejwt.views import ( TokenRefreshView, TokenVerifyView, ) From a190e036d2c1b4f6668e4bbe790175f51d4711b5 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 16 Apr 2020 01:59:04 -0500 Subject: [PATCH 138/216] Bug fixes related to Simple JWT integrations --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6e897fc..5885ea9 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='1.0.2', + version='1.0.3', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From 4dcca581784571ccb449afad17ff77acfbd9623b Mon Sep 17 00:00:00 2001 From: Francesco Pinzauti Date: Thu, 16 Apr 2020 15:38:03 +0200 Subject: [PATCH 139/216] changed url to path --- docs/api_endpoints.rst | 2 +- docs/installation.rst | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index c253f7b..dc159ce 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -63,7 +63,7 @@ Registration .. note:: If you set account email verification as mandatory, you have to add the VerifyEmailView with the used `name`. You need to import the view: ``from dj_rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name: - ``url(r'^dj-rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. + ``path('dj-rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. diff --git a/docs/installation.rst b/docs/installation.rst index 867286f..6a7d83f 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -28,7 +28,7 @@ Installation urlpatterns = [ ..., - url(r'^dj-rest-auth/', include('dj_rest_auth.urls')) + path('dj-rest-auth/', include('dj_rest_auth.urls')) ] 4. Migrate your database @@ -68,8 +68,8 @@ Registration (optional) urlpatterns = [ ..., - url(r'^dj-rest-auth/', include('dj_rest_auth.urls')), - url(r'^dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')) + path('dj-rest-auth/', include('dj_rest_auth.urls')), + path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')) ] @@ -122,7 +122,7 @@ Facebook urlpatterns += [ ..., - url(r'^dj-rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login') + path('dj-rest-auth/facebook/', FacebookLogin.as_view(), name='fb_login') ] @@ -149,7 +149,7 @@ If you are using Twitter for your social authentication, it is a bit different s urlpatterns += [ ..., - url(r'^dj-rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login') + path('dj-rest-auth/twitter/', TwitterLogin.as_view(), name='twitter_login') ] .. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details. @@ -179,7 +179,7 @@ If you are using GitHub for your social authentication, it uses code and not Acc urlpatterns += [ ..., - url(r'^dj-rest-auth/github/$', GitHubLogin.as_view(), name='github_login') + path('dj-rest-auth/github/', GitHubLogin.as_view(), name='github_login') ] Additional Social Connect Views @@ -215,9 +215,9 @@ In urls.py: urlpatterns += [ ..., - url(r'^dj-rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect') - url(r'^dj-rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect') - url(r'^dj-rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect') + path('dj-rest-auth/facebook/connect/', FacebookConnect.as_view(), name='fb_connect') + path('dj-rest-auth/twitter/connect/', TwitterConnect.as_view(), name='twitter_connect') + path('dj-rest-auth/github/connect/', GithubConnect.as_view(), name='github_connect') ] You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts: @@ -230,13 +230,13 @@ You can also use the following views to check all social accounts attached to th urlpatterns += [ ..., - url( - r'^socialaccounts/$', + path( + 'socialaccounts/', SocialAccountListView.as_view(), name='social_account_list' ), - url( - r'^socialaccounts/(?P\d+)/disconnect/$', + path( + 'socialaccounts//disconnect/', SocialAccountDisconnectView.as_view(), name='social_account_disconnect' ) From 64e07ec755e4ce77b260b64099bf98e645fd550a Mon Sep 17 00:00:00 2001 From: Serhiy Romanov Date: Fri, 17 Apr 2020 11:27:24 +0300 Subject: [PATCH 140/216] Fix missed import_callable --- dj_rest_auth/app_settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index 16c3888..784a691 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -29,9 +29,9 @@ PasswordResetSerializer = import_callable(serializers.get( 'PASSWORD_RESET_SERIALIZER', DefaultPasswordResetSerializer )) -PasswordResetConfirmSerializer = serializers.get( +PasswordResetConfirmSerializer = import_callable(serializers.get( 'PASSWORD_RESET_CONFIRM_SERIALIZER', DefaultPasswordResetConfirmSerializer -) +)) PasswordChangeSerializer = import_callable(serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)) From 4a46807a1f7a9484c157e545dba983b8d0ce0e8e Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 18 Apr 2020 12:58:50 -0500 Subject: [PATCH 141/216] Bumps version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5885ea9..9c98f60 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ f.close() setup( name='dj-rest-auth', - version='1.0.3', + version='1.0.4', author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From 2602d66fefa5e8e96da25a7bd37e1c7fdba2cd87 Mon Sep 17 00:00:00 2001 From: Ranet P Date: Tue, 21 Apr 2020 18:17:57 +0300 Subject: [PATCH 142/216] Pass context to JWTSerializer and TokenSerializer --- dj_rest_auth/registration/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index e9577a1..937f327 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -52,9 +52,9 @@ class RegisterView(CreateAPIView): 'access_token': self.access_token, 'refresh_token': self.refresh_token } - return JWTSerializer(data).data + return JWTSerializer(data, context=self.get_serializer_context()).data else: - return TokenSerializer(user.auth_token).data + return TokenSerializer(user.auth_token, context=self.get_serializer_context()).data def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) From 23bef47110afdbf7f81ba89f85808121cbf8467c Mon Sep 17 00:00:00 2001 From: Rafael Laranja Date: Sun, 26 Apr 2020 09:52:10 -0300 Subject: [PATCH 143/216] Compile pt_BR language messages --- dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.mo | Bin 0 -> 2358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.mo diff --git a/dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.mo b/dj_rest_auth/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..64a4e314ea34fc303d0ee0d01b0cfb45de7c0ebe GIT binary patch literal 2358 zcma)7OK)366uv-tnRlU3#Ou_8wovZHX-k#5O=;4)C6L4+O(MZ28s9s%hm2>;%)L&_ zf*lLCNL|6EVo@Q%iVb3gWEMy)*deh&@B@$#e*nI7AFRj zJPF))M`5Q8jIh^0*82pwANVcs1>n!XBf!6aPXdqZDX;}(KU+YU3_b>agxIbEU&H>n zyMo|ZJ_m9hAC&khkmLRa$a+5kInKxLF8mz?9>#tNcnp{U4*)+09t8dX41s?F*)H7^ z1TO*402hD?SO>08dUk|w?BUaN2dcgChP zl1_D%Orl`X#MU_(r?4{2(uhPHBZ{rmZc9VfQEU^*DLDCFrV#k_m66by43;y`w_}|_ zvo1NAIti0deTc|+tV`PTeZ#fW2G zEhCv6pw=?2x**9+-JVh}w8{=mjH13#a4E}6)y=fNLfZCv=&D5tgY~|objMDjL8*1( zDN%_zl+r+?aX$(+jOb`6TE5FY%qL>#>_{cB6rB);ks>7ZMD4~p2M7TDB*dL$|fCc z%$y7x$HSQu)HvBZJ{vY>8x1IiYjUL6c&YbxYknGgJVdGW|Q?Uhz-N%%Be zcfxorQtO(u;4))rL117}whIpPfkaMs_;aWD+AThwMI*Ge+fi%>XJE+mGSQRax)g&Z zEzPf7+~9;xFD;$bDzdIO(Lo~1i_5J^_A^nVc8)7$5X_Y!vf`q>GSotuQxx}w!ywIV ztX~LcCwd%oSGur;=aneaYtn2-rL|R^IibS~)(w1<%rM{jxud73_&Imj(1AIcdGS;& zcw>Bx zc$!K6;dF{iCZ{EtnDJ+px>l8Rg2-$Xv5jle5drB0p=*p5>@ zk&eGYb{O?dq4CJ8+ZKd3lA#9$F~O+G^9R*buO0Mqi`IlP{RkGKOcUJ635FS-u z3?2qFksj}TgoaNgSNwO0MUmWYK6Pd!3=v0D-7ZR1 c@RAJknpuoHW)z$>zQ&=#X-QNzXm1C912@mNTL1t6 literal 0 HcmV?d00001 From 7b1bfecdd955a2ea37ba087ac55b7f6daac49787 Mon Sep 17 00:00:00 2001 From: Francesco Pinzauti Date: Thu, 7 May 2020 10:26:48 +0200 Subject: [PATCH 144/216] added italian language --- dj_rest_auth/locale/it/LC_MESSAGES/django.po | 123 +++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 dj_rest_auth/locale/it/LC_MESSAGES/django.po diff --git a/dj_rest_auth/locale/it/LC_MESSAGES/django.po b/dj_rest_auth/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000..d901fa7 --- /dev/null +++ b/dj_rest_auth/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,123 @@ +# Italian language. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-07 09:46+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Francesco Pinzauti \n" +"Language-Team: \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: .\registration\serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "\"view\" non è definito, passalo come variabile di contesto" + +#: .\registration\serializers.py:72 +msgid "Define adapter_class in view" +msgstr "Definisci \"adapter_class\" in view" + +#: .\registration\serializers.py:91 +msgid "Define callback_url in view" +msgstr "Definisci \"callback_url\" in view" + +#: .\registration\serializers.py:95 +msgid "Define client_class in view" +msgstr "Definisci \"client_class\" in view" + +#: .\registration\serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "Input errato. È richiesto \"access_token\" o \"code\"." + +#: .\registration\serializers.py:125 +msgid "Incorrect value" +msgstr "Valore errato" + +#: .\registration\serializers.py:139 +msgid "User is already registered with this e-mail address." +msgstr "Un altro utente è già registrato con questo indirizzo e-mail." + +#: .\registration\serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "Un altro utente è già registrato con questo indirizzo e-mail." + +#: .\registration\serializers.py:193 +msgid "The two password fields didn't match." +msgstr "Le password non corrispondono." + +#: .\registration\views.py:47 +msgid "Verification e-mail sent." +msgstr "E-mail di verifica inviata." + +#: .\registration\views.py:95 +msgid "ok" +msgstr "ok" + +#: .\serializers.py:32 +msgid "Must include \"email\" and \"password\"." +msgstr "Deve includere \"email\" e \"password\"." + +#: .\serializers.py:43 +msgid "Must include \"username\" and \"password\"." +msgstr "Deve includere \"email\" e \"password\"." + +#: .\serializers.py:56 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Deve includere o \"username\" o \"email\" e \"password\"." + +#: .\serializers.py:97 +msgid "User account is disabled." +msgstr "L'account è disabilitato." + +#: .\serializers.py:100 +msgid "Unable to log in with provided credentials." +msgstr "Impossibile accedere con le credenziali fornite." + +#: .\serializers.py:109 +msgid "E-mail is not verified." +msgstr "L'e-mail non è verificata." + +#: .\serializers.py:264 +msgid "Your old password was entered incorrectly. Please enter it again." +msgstr "La tua password precedente non è corretta. Inseriscila nuovamente." + +#: .\views.py:139 +msgid "Successfully logged out." +msgstr "Disconnesso con successo." + +#: .\views.py:161 +msgid "Refresh token was not included in request data." +msgstr "Il \"Refresh token\" non è presente nei dati della richiesta." + +#: .\views.py:171 .\views.py:175 +msgid "An error has occurred." +msgstr "Si è verificato un errore." + +#: .\views.py:180 +msgid "" +"Neither cookies or blacklist are enabled, so the token has not been deleted " +"server side. Please make sure the token is deleted client side." +msgstr "" +"Né i cookies né la blacklist sono abilitati, quindi il token non è stato eliminato " +"lato server. Assicurarsi che il token sia eliminato lato client." + +#: .\views.py:230 +msgid "Password reset e-mail has been sent." +msgstr "L'e-mail per il recupero della password è stata inviata." + +#: .\views.py:256 +msgid "Password has been reset with the new password." +msgstr "Password aggiornata." + +#: .\views.py:278 +msgid "New password has been saved." +msgstr "Nuova password salvata." From 3b0e95cee731e4c0ac0d7810b2a371504faeccff Mon Sep 17 00:00:00 2001 From: Francesco Pinzauti Date: Thu, 7 May 2020 10:35:22 +0200 Subject: [PATCH 145/216] Compile italian language --- dj_rest_auth/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 3001 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dj_rest_auth/locale/it/LC_MESSAGES/django.mo diff --git a/dj_rest_auth/locale/it/LC_MESSAGES/django.mo b/dj_rest_auth/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e6874866ec7d4849042403c15d01d1b41c9272b9 GIT binary patch literal 3001 zcmbtWOKcoP5N$~KneYqWkSMCGKn5i<`G6p7VuBMp!jeCWaV!N6QG2F$w{dUx(mk`r zzT_H-Lr!o4!4WPTIB*IA#W$`#i!U1Hi)=p9Ss%THuSo zEA{wmAn*Spa2hyqw-5+P%ma@irzPMSj4$6)#s3ZP5XLuv1pK4MgZEbRXMiu@{oB9? zfLDPW-^VpxujhXSeu($`@2hzD68IR#-vK$_Ux259`zETmSAhpH?gNhjuL8LS-vT+l z8$jlF|NTNVfiDBk0X>lO`3i`11k#CP=6VlqzK}w^Ktc3b4+TPuTs|^<0mL@(0?p!a z+?*p{kK*2o`(fN%cZ4rcs(4{*@nHSTHQ>7Q#rcY9DueQ*14-kR%s0uajt+(LDyI!y zbgAfKQYAg94aq$BDuh%_TTgqx_Tk}DW@HGYEe*8V7*1x= zm^GQLUn;%%%bd~57PqXMt@cI~))h2RUbi)GHfJ-3ZLEZ?t3}O{v5}8F+PON?0}&=hz@=b87Sv`G)g(BfZ6l>9Vq?{=rUxI`G;U znIoXv?XXx|XU?r_1wuWo8BkdAFQp@gH+V(>Ctl10|5C1O!+&@lN}-RM2Y0aM~zKOg>7Nse`w8azS5pHq7Qu7sR>fup_ligaY7+E;qr1N;j!OR@BwB3?rq3N`?ZTDKg9;SuLy02oP?Ub^kk`*O;*l;**BIb#O zxrNzLjK|Ys6X%!_i>)^Mh=s{H+BZn-6lGoM(UnsdR?a6UM|K=iTlr)b+~nGJnsjmv zo?E8$(j@1d?}aAWejJ9W6Q`(poO;gEp(#54{HX~v4=P@GMO-*S!1dUG}x(gdYZFUw1EpJ^@iE1hqOE-|CLmH$RL>b$WQrYQf zhffM?+fIG@{7p9KtE|MMW2r_qLmIhs9H<1_107e+8EV|5qz#BktZ|>kmz&ip%@T^A z=xkVCY&(Oda@OMGS@mzIB-SAyHQJQ@v8w3McQyx|=$T&MffKNbk3M8Mhxo)3fN`ay zTToI>Z6v4*H2M7GP)?CTl+&sp@b!PsR{b{tH65O>5jzb&KRb*>h1G?tBo-} Date: Sat, 9 May 2020 17:32:05 -0500 Subject: [PATCH 146/216] Adds centralized version store --- dj_rest_auth/__version__.py | 8 ++++++++ docs/conf.py | 8 ++++++-- setup.py | 6 +++++- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 dj_rest_auth/__version__.py diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py new file mode 100644 index 0000000..dd67bed --- /dev/null +++ b/dj_rest_auth/__version__.py @@ -0,0 +1,8 @@ +__title__ = 'dj-rest-auth' +__description__ = 'Authentication and Registration in Django Rest Framework.' +__url__ = 'http://github.com/jazzband/dj-rest-auth' +__version__ = '1.0.5' +__author__ = '@iMerica https://github.com/iMerica' +__author_email__ = 'imichael@pm.me' +__license__ = 'MIT' +__copyright__ = 'Copyright 2020 @iMerica https://github.com/iMerica' \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 1f57578..97831a7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,10 @@ import os import sys +about = {} +with open('../dj_rest_auth/__version__.py', 'r', encoding="utf8") as f: + exec(f.read(), about) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -51,9 +55,9 @@ copyright = u'2020, @iMerica' # built documents. # # The short X.Y version. -version = '0.9.5' +version = about['__version__'] # The full version, including alpha/beta/rc tags. -release = '0.9.5' +release = about['__version__'] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 9c98f60..fac004b 100644 --- a/setup.py +++ b/setup.py @@ -10,9 +10,13 @@ long_description = f.read().strip() f.close() +about = {} +with open('dj_rest_auth/__version__.py', 'r', encoding="utf8") as f: + exec(f.read(), about) + setup( name='dj-rest-auth', - version='1.0.4', + version=about['__version__'], author='iMerica', author_email='imichael@pm.me', url='http://github.com/jazzband/dj-rest-auth', From b3758c9c267538f717fc63ed6f552abc209ab929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Lide=CC=81n?= Date: Sun, 10 May 2020 15:08:00 +0200 Subject: [PATCH 147/216] Added swedish (sv) translations --- rest_auth/locale/sv/LC_MESSAGES/django.mo | Bin 0 -> 2565 bytes rest_auth/locale/sv/LC_MESSAGES/django.po | 107 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 rest_auth/locale/sv/LC_MESSAGES/django.mo create mode 100644 rest_auth/locale/sv/LC_MESSAGES/django.po diff --git a/rest_auth/locale/sv/LC_MESSAGES/django.mo b/rest_auth/locale/sv/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..185c73cf39038920d95bde4095978f1c0c02c91f GIT binary patch literal 2565 zcmbVN&5smC6fY1JM)3nhB^rE=8Zgl9?7A3SvI@G3Az@(yyQ>}ysqL=mDW|4-tg7yD zZrt?OQa3H%lK8t@O`G2r2cgm?$I z0AxD@U<|wgWW5pa1>kSM*MWQX32_2=40r^16*vd%jo04++20-DIpFU=xDqoD3(-XE zbHKA$fAokDuL8dYHi37>co)cd?0r;-w}3~1PXVt0TfhX!{%!y-1Ahdv{*nE4Jx-0$ z01sgQd*E^4t?~ZPz@u0ngz#P9Ng&s?3*>r!349Ou1CZn1+d$61$1(9&9K=Kl;xOhj zn5=UMlLtyv4X!iC{6xJJ2yuJB?DlvL|M-p&QZ=5&FVYt%nRpEISxj+`3a=b#PtrIg z(;+#PX&;nRDGhY!Q0PFYqMp=-WSTnVeJmDLTU&*->_hchVx;$^EtOggCc;D-vmul2 zwZfUd$c$Dt+;?uNb^>=c4^%3r+ghcuxL}jqIh6!h=@%g;nIwqfTFAS~Qtl|pQ^hGb z^?9KY_|7AxG=&n&h3C_WDWKU@oJ^CXO{v*O>WZ-4VF|UjxnF>&A6(+Z!$nH43L%r4--_X=3>KluzMOCVHVa$+B zo@Kbz93>R19YtY~PoqJpP3kGtsXZ2`CqvSS#hR5H28ubKI<}xbedxjpX7z3+@#ZV2T+8ys?E_Cb$^**Oe;o7uWDIkFq7KGBJYY7mw$#P zj4q@Rg7b)Lo*GwFKX)No_L)wj_lwL&t2wq;E=N~XsaYvnltInYY-_d^wN6DdEt)ws z-5>iUF&F1O!h7OGtQ#fg&^SSH!d9wX#=@(|tQ2lq|xTRMXXy%PGh{(eq z+c7fa4!KNXj8>KGVf}IRp|Z-=(v@7LDEn+Y8_zYwlEtGcN1Ha4PSI%7;Yp^_jyc8Q zP)a>C4!VXqELKrJ_d!;yqEP0FS2XnK-t}*GvCF;d-;$;}ypkB4AU$NM-(8G~l8Xs7E&n(Y1`}HO_lG1Nq|H!Z*xz}&jv1SO8^ony2xLaL z@zg+ypdv@UFLBvO@#16~q{M>J7T%8!qfKLiAKz;rJCsuc3RE+$bbEAr*AXr&$#SY& zJL~GCTX|ax%vXFJi(sH~v^CZAZTQ5)sA)t&GLFNy~Qe+(0Van6l)=Y=-!^#c=pPTDm4OUN&%LtE1r zw>^JEgE~pR5?AlU=RL3yacp@1HKi#d7B$k#WDjjJy)LAOz^Og%UwkUpk%ZCQ4v;Ar K1UF+<5!#=x2OS^) literal 0 HcmV?d00001 diff --git a/rest_auth/locale/sv/LC_MESSAGES/django.po b/rest_auth/locale/sv/LC_MESSAGES/django.po new file mode 100644 index 0000000..747f5af --- /dev/null +++ b/rest_auth/locale/sv/LC_MESSAGES/django.po @@ -0,0 +1,107 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-10 12:48+0000\n" +"PO-Revision-Date: 2020-05-10 15:04+0200\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: \n" +"Language-Team: \n" +"X-Generator: Poedit 2.2.4\n" + +#: rest_auth/rest_auth/registration/serializers.py:67 +msgid "View is not defined, pass it as a context variable" +msgstr "Vyn definieras inte, skicka den som en kontextvariabel" + +#: rest_auth/rest_auth/registration/serializers.py:72 +msgid "Define adapter_class in view" +msgstr "Definiera “adapter_class” i vyn" + +#: rest_auth/rest_auth/registration/serializers.py:91 +msgid "Define callback_url in view" +msgstr "Definiera “callback_url” i vyn" + +#: rest_auth/rest_auth/registration/serializers.py:95 +msgid "Define client_class in view" +msgstr "Definiera “client_class” i vyn" + +#: rest_auth/rest_auth/registration/serializers.py:116 +msgid "Incorrect input. access_token or code is required." +msgstr "Felaktig inmatning. access_token eller code krävs." + +#: rest_auth/rest_auth/registration/serializers.py:125 +msgid "Incorrect value" +msgstr "Felaktigt värde" + +#: rest_auth/rest_auth/registration/serializers.py:139 +msgid "User is already registered with this e-mail address." +msgstr "Användaren är redan registrerad med den här e-postadressen." + +#: rest_auth/rest_auth/registration/serializers.py:185 +msgid "A user is already registered with this e-mail address." +msgstr "En användare är redan registrerad med den här e-postadressen." + +#: rest_auth/rest_auth/registration/serializers.py:193 +msgid "The two password fields didn't match." +msgstr "De två lösenordsfälten matchade inte." + +#: rest_auth/rest_auth/registration/views.py:51 +msgid "Verification e-mail sent." +msgstr "Verifikationsmail har skickats." + +#: rest_auth/rest_auth/registration/views.py:98 +msgid "ok" +msgstr "ok" + +#: rest_auth/rest_auth/serializers.py:33 +msgid "Must include \"email\" and \"password\"." +msgstr "Måste inkludera “email” och “password”." + +#: rest_auth/rest_auth/serializers.py:44 +msgid "Must include \"username\" and \"password\"." +msgstr "Måste innehålla “username” och “password”." + +#: rest_auth/rest_auth/serializers.py:57 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Måste innehålla antingen “username” eller “email” och “password”." + +#: rest_auth/rest_auth/serializers.py:98 +msgid "User account is disabled." +msgstr "Användarkontot är avstängt." + +#: rest_auth/rest_auth/serializers.py:101 +msgid "Unable to log in with provided credentials." +msgstr "Det går inte att logga in med de angivna uppgifterna." + +#: rest_auth/rest_auth/serializers.py:110 +msgid "E-mail is not verified." +msgstr "E-post är inte verifierad." + +#: rest_auth/rest_auth/serializers.py:259 +msgid "Your old password was entered incorrectly. Please enter it again." +msgstr "Ditt gamla lösenord angavs felaktigt. Vänligen ange det igen." + +#: rest_auth/rest_auth/views.py:137 +msgid "Successfully logged out." +msgstr "Utloggad." + +#: rest_auth/rest_auth/views.py:190 +msgid "Password reset e-mail has been sent." +msgstr "E-post för återställning av lösenord har skickats." + +#: rest_auth/rest_auth/views.py:216 +msgid "Password has been reset with the new password." +msgstr "Lösenordet har återställts med det nya lösenordet." + +#: rest_auth/rest_auth/views.py:238 +msgid "New password has been saved." +msgstr "Nytt lösenord har sparats." From 5f137da9306d63fb1730119ca739c775bc63faac Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Sun, 10 May 2020 18:05:30 +0200 Subject: [PATCH 148/216] make token validation in PasswordResetConfirmSerializer is the first thing to do in validate() method --- dj_rest_auth/serializers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index efd455e..f05d143 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -208,6 +208,9 @@ class PasswordResetConfirmSerializer(serializers.Serializer): def validate(self, attrs): self._errors = {} + if not default_token_generator.check_token(self.user, attrs['token']): + raise ValidationError({'token': ['Invalid value']}) + # Decode the uidb64 to uid to get User object try: uid = force_text(uid_decoder(attrs['uid'])) @@ -222,8 +225,6 @@ class PasswordResetConfirmSerializer(serializers.Serializer): ) if not self.set_password_form.is_valid(): raise serializers.ValidationError(self.set_password_form.errors) - if not default_token_generator.check_token(self.user, attrs['token']): - raise ValidationError({'token': ['Invalid value']}) return attrs From 0be5b2dd156c13dc1cc4cb49c853b48f5606d461 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 May 2020 19:39:33 -0500 Subject: [PATCH 149/216] Fixes no-user issue --- dj_rest_auth/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index f05d143..16ebebc 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -208,9 +208,6 @@ class PasswordResetConfirmSerializer(serializers.Serializer): def validate(self, attrs): self._errors = {} - if not default_token_generator.check_token(self.user, attrs['token']): - raise ValidationError({'token': ['Invalid value']}) - # Decode the uidb64 to uid to get User object try: uid = force_text(uid_decoder(attrs['uid'])) @@ -218,6 +215,9 @@ class PasswordResetConfirmSerializer(serializers.Serializer): except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist): raise ValidationError({'uid': ['Invalid value']}) + if not default_token_generator.check_token(self.user, attrs['token']): + raise ValidationError({'token': ['Invalid value']}) + self.custom_validation(attrs) # Construct SetPasswordForm instance self.set_password_form = self.set_password_form_class( From 0bc943ff25ce6f0e9eda9295c8c5c629faa870d2 Mon Sep 17 00:00:00 2001 From: Robert Wells Date: Sat, 16 May 2020 13:41:45 -0700 Subject: [PATCH 150/216] Adds a tox.ini file and instructions in the readme for how to use it. --- README.md | 17 ++++++++++- dj_rest_auth/__version__.py | 2 +- dj_rest_auth/app_settings.py | 4 ++- dj_rest_auth/registration/serializers.py | 1 - dj_rest_auth/tests/urls.py | 1 - dj_rest_auth/utils.py | 2 +- dj_rest_auth/views.py | 1 - tox.ini | 37 ++++++++++++++++++++++++ 8 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 tox.ini diff --git a/README.md b/README.md index deefdb5..0430a08 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,21 @@ The easiest way to run test coverage is with [`coverage`](https://pypi.org/proje which runs the tests against all supported Django installs. To run the test coverage within a virtualenv, run `coverage run ./runtests.py` from the repository directory then run `coverage report`. +#### Tox + +Testing may also be done using [`tox`](https://pypi.org/project/tox/), which +will run the tests against all supported combinations of python and django. + +Install tox, either globally or within a virtualenv, and then simply run `tox` +from the repository directory. As there are many combinations, you may run them +in [`parallel`](https://tox.readthedocs.io/en/latest/config.html#cmdoption-tox-p) +using `tox --parallel`. + +The `tox.ini` includes an environment for testing code [`coverage`](https://pypi.org/project/coverage/) +and you can run it and view this report with `tox -e coverage`. + +Linting may also be performed via [`flake8`](https://pypi.org/project/flake8/) +by running `tox -e flake8`. ### Documentation @@ -59,4 +74,4 @@ View the full documentation here: https://dj-rest-auth.readthedocs.io/en/latest/ ### Acknowledgements -This project began as a fork of `django-rest-auth`. Big thanks to everyone who contributed to that repo! \ No newline at end of file +This project began as a fork of `django-rest-auth`. Big thanks to everyone who contributed to that repo! diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index dd67bed..5b7a5aa 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -5,4 +5,4 @@ __version__ = '1.0.5' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' -__copyright__ = 'Copyright 2020 @iMerica https://github.com/iMerica' \ No newline at end of file +__copyright__ = 'Copyright 2020 @iMerica https://github.com/iMerica' diff --git a/dj_rest_auth/app_settings.py b/dj_rest_auth/app_settings.py index 784a691..fe6e6a2 100644 --- a/dj_rest_auth/app_settings.py +++ b/dj_rest_auth/app_settings.py @@ -33,6 +33,8 @@ PasswordResetConfirmSerializer = import_callable(serializers.get( 'PASSWORD_RESET_CONFIRM_SERIALIZER', DefaultPasswordResetConfirmSerializer )) -PasswordChangeSerializer = import_callable(serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)) +PasswordChangeSerializer = import_callable( + serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer) +) JWT_AUTH_COOKIE = getattr(settings, 'JWT_AUTH_COOKIE', None) diff --git a/dj_rest_auth/registration/serializers.py b/dj_rest_auth/registration/serializers.py index fc7c92b..7d9d4a0 100644 --- a/dj_rest_auth/registration/serializers.py +++ b/dj_rest_auth/registration/serializers.py @@ -17,7 +17,6 @@ except ImportError: raise ImportError("allauth needs to be added to INSTALLED_APPS.") - class SocialAccountSerializer(serializers.ModelSerializer): """ serialize allauth SocialAccounts for use with a REST API diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index e2c786e..f1796d6 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -21,7 +21,6 @@ from . import django_urls class ExampleProtectedView(APIView): permission_classes = [permissions.IsAuthenticated] - def get(self, *args, **kwargs): return Response(dict(success=True)) diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 7cbf3ad..e1ef77a 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -45,7 +45,7 @@ try: return None else: raw_token = self.get_raw_token(header) - + if raw_token is None: return None diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index b5fcdb8..c968334 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -146,7 +146,6 @@ class LogoutView(APIView): from rest_framework_simplejwt.exceptions import TokenError from rest_framework_simplejwt.tokens import RefreshToken - cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) if cookie_name: response.delete_cookie(cookie_name) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..484802b --- /dev/null +++ b/tox.ini @@ -0,0 +1,37 @@ +# tox (https://tox.readthedocs.io/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +# Running this tox will test against all supported version +# combinations of python and django as described at the following +# https://docs.djangoproject.com/en/3.0/faq/install/#what-python-version-can-i-use-with-django +# https://endoflife.date/django +[tox] +skipsdist = true +envlist = + python{3.5,3.6,3.7,3.8}-django22 + python{3.6,3.7,3.8}-django30 + +[testenv] +commands = + python ./runtests.py +deps = + -rdev-requirements.txt + django22: Django>=2.2,<2.3 + django30: Django>=3.0,<3.1 + +# Configuration for coverage and flake8 is being set in `./setup.cfg` +[testenv:coverage] +commands = + coverage run ./runtests.py + coverage report +deps = + -rdev-requirements.txt + +[testenv:flake8] +changedir = {toxinidir}/dj_rest_auth +commands = + flake8 . +deps = + flake8==3.8.1 From 860c350ac939256c4b477198df66046e50826e7a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 16 May 2020 15:58:57 -0500 Subject: [PATCH 151/216] Fixes the Circle CI Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0430a08..06d9953 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Dj-Rest-Auth -[![](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/github/jazzband/dj-rest-auth/pipelines) +[![](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/pipelines/github/jazzband/dj-rest-auth) [![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/) [![Coverage Status](https://coveralls.io/repos/github/jazzband/dj-rest-auth/badge.svg?branch=master)](https://coveralls.io/github/jazzband/dj-rest-auth?branch=master) From 2a6fb3a87321ebcf6c0ea4c3b1d0d66285309198 Mon Sep 17 00:00:00 2001 From: Sean Farley Date: Tue, 19 May 2020 19:21:11 -0700 Subject: [PATCH 152/216] serializers: import gettext_lazy; fixes #70 Per Django's warning, ugettext_lazy will be removed in a future version. --- dj_rest_auth/serializers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index 16ebebc..302be84 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -5,7 +5,10 @@ from django.contrib.auth.tokens import default_token_generator from django.utils.encoding import force_text from django.utils.http import urlsafe_base64_decode as uid_decoder from django.utils.module_loading import import_string -from django.utils.translation import ugettext_lazy as _ +try: + from django.utils.translation import gettext_lazy as _ +except ImportError: + from django.utils.translation import ugettext_lazy as _ from rest_framework import exceptions, serializers from rest_framework.exceptions import ValidationError From 1fe4ba7d3435e2d74c2ed3e63cf28caed59237fd Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Thu, 28 May 2020 00:13:43 +0200 Subject: [PATCH 153/216] Updated PasswordResetConfirmSerializer docstring --- dj_rest_auth/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/serializers.py b/dj_rest_auth/serializers.py index 302be84..a65f765 100644 --- a/dj_rest_auth/serializers.py +++ b/dj_rest_auth/serializers.py @@ -196,7 +196,7 @@ class PasswordResetSerializer(serializers.Serializer): class PasswordResetConfirmSerializer(serializers.Serializer): """ - Serializer for requesting a password reset e-mail. + Serializer for confirming a password reset attempt. """ new_password1 = serializers.CharField(max_length=128) new_password2 = serializers.CharField(max_length=128) From 9a75a153456c7afa826f99eb8556fa540214eb08 Mon Sep 17 00:00:00 2001 From: erdaltsksn Date: Sat, 30 May 2020 04:33:40 +0300 Subject: [PATCH 154/216] docs: Update registration install command for zsh why: The zsh cannot process [] character correctly. iss: https://github.com/Tivix/django-rest-auth/issues/402 --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 6a7d83f..94579ee 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -44,7 +44,7 @@ You're good to go now! Registration (optional) ----------------------- -1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install dj-rest-auth[with_social]``. +1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install 'dj-rest-auth[with_social]'``. 2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: @@ -283,4 +283,4 @@ This example value above will cause dj-rest-auth to return a `Set-Cookie` header Set-Cookie: my-app-auth=xxxxxxxxxxxxx; expires=Sat, 28 Mar 2020 18:59:00 GMT; HttpOnly; Max-Age=300; Path=/ -``JWT_AUTH_COOKIE`` is also used while authenticating each request against protected views. \ No newline at end of file +``JWT_AUTH_COOKIE`` is also used while authenticating each request against protected views. From 202b5e8d4df459a22e4f618fd353cfa56444ff17 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:16:02 -0500 Subject: [PATCH 155/216] Adds vulnerability disclosure --- docs/disclosure.rst | 17 +++++++++++++++++ docs/index.rst | 1 + 2 files changed, 18 insertions(+) create mode 100644 docs/disclosure.rst diff --git a/docs/disclosure.rst b/docs/disclosure.rst new file mode 100644 index 0000000..c4e2ae5 --- /dev/null +++ b/docs/disclosure.rst @@ -0,0 +1,17 @@ +Vulnerability Disclosure +======================== + +Attn: Developers and Security Researchers. + +Please observe the standard best practices of responsible disclosure, especially considering that this is OSS. +See OWASP's disclosure `cheat sheet `_. + +Some basic rules: + +- Keep it legal. +- Respect everyone's privacy. +- Contact the core maintainer(s) immediately if you discover a security vulnerability (imichael@pm.me for now). + + + + diff --git a/docs/index.rst b/docs/index.rst index 10eb7cb..2084a26 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,3 +26,4 @@ Contents Demo project FAQ Changelog + Security Disclosure From c18ccf57fd1f02dc15962f61289a09f21e7d9d3e Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:25:20 -0500 Subject: [PATCH 156/216] Improves link in docs --- docs/disclosure.rst | 6 ++---- docs/index.rst | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/disclosure.rst b/docs/disclosure.rst index c4e2ae5..4e7d494 100644 --- a/docs/disclosure.rst +++ b/docs/disclosure.rst @@ -1,16 +1,14 @@ Vulnerability Disclosure ======================== -Attn: Developers and Security Researchers. - Please observe the standard best practices of responsible disclosure, especially considering that this is OSS. -See OWASP's disclosure `cheat sheet `_. +See OWASP's disclosure `cheat sheet `_. Some basic rules: - Keep it legal. - Respect everyone's privacy. -- Contact the core maintainer(s) immediately if you discover a security vulnerability (imichael@pm.me for now). +- Contact the core maintainer(s) immediately if you discover a serious security vulnerability (imichael@pm.me for now). diff --git a/docs/index.rst b/docs/index.rst index 2084a26..1d5ac3b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,4 +26,4 @@ Contents Demo project FAQ Changelog - Security Disclosure + Vulnerability Disclosure From 24413e4a4400aee9744379cc41463a960fa4247b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:30:16 -0500 Subject: [PATCH 157/216] Removes changelog. Refer to Github instead --- docs/changelog.rst | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 docs/changelog.rst diff --git a/docs/changelog.rst b/docs/changelog.rst deleted file mode 100644 index 78186af..0000000 --- a/docs/changelog.rst +++ /dev/null @@ -1,13 +0,0 @@ -Changelog -========= - -0.1.2 ------ -Welcome Dj-Rest-Auth - -1.0.0 ------ -Replaces `rest_framework_jwt` with `djangorestframework-simplejwt`. - -Rest_framework_jwt is now unmaintained so we've switched to simplewjt, which is a strong jwt library with a large community. -This change means you may need to change your client code if you're upgrading from the previous version. \ No newline at end of file From 3ac4251233f30a4aa320201b1a79af4b738dff76 Mon Sep 17 00:00:00 2001 From: Dmitriy Kalinin Date: Sat, 30 May 2020 09:30:49 +0300 Subject: [PATCH 158/216] Added ukrainian locale --- dj_rest_auth/locale/uk/django.po | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 dj_rest_auth/locale/uk/django.po diff --git a/dj_rest_auth/locale/uk/django.po b/dj_rest_auth/locale/uk/django.po new file mode 100644 index 0000000..519c59f --- /dev/null +++ b/dj_rest_auth/locale/uk/django.po @@ -0,0 +1,101 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-23 21:56-0800\n" +"PO-Revision-Date: 2020-05-23 00:56+0300\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" +"X-Generator: Poedit 2.3.1\n" + +#: registration/serializers.py:53 +msgid "View is not defined, pass it as a context variable" +msgstr "View невідомий, передайте його як змінну контексту" + +#: registration/serializers.py:58 +msgid "Define adapter_class in view" +msgstr "Встановіть adapter_class у view" + +#: registration/serializers.py:77 +msgid "Define callback_url in view" +msgstr "Встановіть callback_url у view" + +#: registration/serializers.py:81 +msgid "Define client_class in view" +msgstr "Встановіть client_class у view" + +#: registration/serializers.py:102 +msgid "Incorrect input. access_token or code is required." +msgstr "Некоректне введення. Необхідний access_token або code." + +#: registration/serializers.py:111 +msgid "Incorrect value" +msgstr "Некоректне значення" + +#: registration/serializers.py:140 +msgid "A user is already registered with this e-mail address." +msgstr "Користувач з таким e-mail адресою вже зареєстрований." + +#: registration/serializers.py:148 +msgid "The two password fields didn't match." +msgstr "Паролі не збігаються." + +#: registration/views.py:44 +msgid "Verification e-mail sent." +msgstr "Лист з підтвердженням вислано на email." + +#: registration/views.py:91 +msgid "ok" +msgstr "добре" + +#: serializers.py:30 +msgid "Must include \"email\" and \"password\"." +msgstr "Має включати \"email\" и \"пароль\"." + +#: serializers.py:41 +msgid "Must include \"username\" and \"password\"." +msgstr "Має включати \"юзернейм\" и \"пароль\"." + +#: serializers.py:54 +msgid "Must include either \"username\" or \"email\" and \"password\"." +msgstr "Повинно включати або \"юзернейм\" либо \"email\" и \"пароль\"." + +#: serializers.py:95 +msgid "User account is disabled." +msgstr "Користувач вимкнений." + +#: serializers.py:98 +msgid "Unable to log in with provided credentials." +msgstr "Неможливо увійти в систему з зазначеними обліковими даними." + +#: serializers.py:107 +msgid "E-mail is not verified." +msgstr "E-mail не підтверджено." + +#: views.py:126 +msgid "Successfully logged out." +msgstr "Успішно вийшли." + +#: views.py:174 +msgid "Password reset e-mail has been sent." +msgstr "Лист з інструкціями по відновленню пароля вислано." + +#: views.py:200 +msgid "Password has been reset with the new password." +msgstr "Пароль змінено на новий." + +#: views.py:222 +msgid "New password has been saved." +msgstr "Новий пароль збережений." From 13a241f0b295847b2da81c2aa92326265ad077f7 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:34:42 -0500 Subject: [PATCH 159/216] Updates index --- docs/disclosure.rst | 4 ++-- docs/index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/disclosure.rst b/docs/disclosure.rst index 4e7d494..5b7619a 100644 --- a/docs/disclosure.rst +++ b/docs/disclosure.rst @@ -1,5 +1,5 @@ -Vulnerability Disclosure -======================== +Vulnerability Disclosure Policy +=============================== Please observe the standard best practices of responsible disclosure, especially considering that this is OSS. See OWASP's disclosure `cheat sheet `_. diff --git a/docs/index.rst b/docs/index.rst index 1d5ac3b..00bdad9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,4 +26,4 @@ Contents Demo project FAQ Changelog - Vulnerability Disclosure + Disclosure Policy From 099e61e5f11887d3424f2fad69e29aa033ef9875 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:37:05 -0500 Subject: [PATCH 160/216] Removes reference tot changelog --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 00bdad9..3a96902 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,7 @@ Welcome to dj-rest-auth's documentation! ============================================ -.. note:: dj-rest-auth version 1.0.0 now uses Django Simple JWT. Please see changelog. +.. note:: dj-rest-auth version 1.0.0 now uses Django Simple JWT. .. image:: https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg From 62e291ba779641fa7244569fdcc8b42ad60dee9d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:38:03 -0500 Subject: [PATCH 161/216] Fixes docs --- docs/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 3a96902..8569e55 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,5 +25,4 @@ Contents Configuration Demo project FAQ - Changelog Disclosure Policy From 073ea5536e1589d3e11c18519aa6fe349d428e84 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 30 May 2020 01:41:58 -0500 Subject: [PATCH 162/216] Bumps to 1.0.6 --- dj_rest_auth/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index 5b7a5aa..c61dbeb 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.0.5' +__version__ = '1.0.6' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' From 6cdcbfacd22d219234e2f8abaf42ea922786b434 Mon Sep 17 00:00:00 2001 From: Bruno Michetti Date: Mon, 1 Jun 2020 17:53:33 -0300 Subject: [PATCH 163/216] Make verify email browsable --- dj_rest_auth/registration/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index 937f327..dd5bc4c 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -19,7 +19,7 @@ from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.decorators.debug import sensitive_post_parameters from rest_framework import status -from rest_framework.exceptions import NotFound +from rest_framework.exceptions import NotFound, MethodNotAllowed from rest_framework.generics import CreateAPIView, GenericAPIView, ListAPIView from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response @@ -86,6 +86,9 @@ class VerifyEmailView(APIView, ConfirmEmailView): def get_serializer(self, *args, **kwargs): return VerifyEmailSerializer(*args, **kwargs) + def get(self, *args, **kwargs): + raise MethodNotAllowed('GET') + def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) From 9e8c98e89271d90ca486aa450a4b11bfaf2ea3c5 Mon Sep 17 00:00:00 2001 From: Bruno Michetti Date: Tue, 2 Jun 2020 13:25:00 -0300 Subject: [PATCH 164/216] Add test of browsable endpoint to maintain coverage --- dj_rest_auth/tests/test_api.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index c53be66..2115415 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -466,6 +466,13 @@ class APIBasicTests(TestsMixin, TestCase): new_user = get_user_model().objects.latest('id') self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) + # test browsable endpoint + result = self.get( + self.verify_email_url + ) + self.assertEqual(result.status_code, 405) + self.assertEqual(result.json['detail'], 'Method "GET" not allowed.') + # email is not verified yet payload = { "username": self.USERNAME, From 2daa44e5f416e7d876a52b4fbd82a6ef63b7e4ed Mon Sep 17 00:00:00 2001 From: Steve Recio Date: Wed, 3 Jun 2020 09:17:15 -0400 Subject: [PATCH 165/216] change throttle scope naming (rest_auth -> dj_rest_auth) --- dj_rest_auth/registration/views.py | 2 +- dj_rest_auth/views.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index 02c73b9..d3c0de8 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -36,7 +36,7 @@ class RegisterView(CreateAPIView): serializer_class = RegisterSerializer permission_classes = register_permission_classes() token_model = TokenModel - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index e68b2ac..dc3dea8 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -40,7 +40,7 @@ class LoginView(GenericAPIView): permission_classes = (AllowAny,) serializer_class = LoginSerializer token_model = TokenModel - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): @@ -116,7 +116,7 @@ class LogoutView(APIView): Accepts/Returns nothing. """ permission_classes = (AllowAny,) - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' def get(self, request, *args, **kwargs): if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False): @@ -219,7 +219,7 @@ class PasswordResetView(GenericAPIView): """ serializer_class = PasswordResetSerializer permission_classes = (AllowAny,) - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' def post(self, request, *args, **kwargs): # Create a serializer with request.data @@ -245,7 +245,7 @@ class PasswordResetConfirmView(GenericAPIView): """ serializer_class = PasswordResetConfirmSerializer permission_classes = (AllowAny,) - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): @@ -269,7 +269,7 @@ class PasswordChangeView(GenericAPIView): """ serializer_class = PasswordChangeSerializer permission_classes = (IsAuthenticated,) - throttle_scope = 'rest_auth' + throttle_scope = 'dj_rest_auth' @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): From ab9d6a96aec3af5fe8cf7a0c3c070c10c3c9c9a0 Mon Sep 17 00:00:00 2001 From: Michael Gecht Date: Wed, 3 Jun 2020 17:18:27 +0200 Subject: [PATCH 166/216] Return refresh_token and expires_in --- dj_rest_auth/registration/serializers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/registration/serializers.py b/dj_rest_auth/registration/serializers.py index 7d9d4a0..b2a102e 100644 --- a/dj_rest_auth/registration/serializers.py +++ b/dj_rest_auth/registration/serializers.py @@ -79,6 +79,7 @@ class SocialLoginSerializer(serializers.Serializer): # Case 1: We received the access_token if attrs.get('access_token'): access_token = attrs.get('access_token') + tokens_to_parse = {'access_token': access_token} # Case 2: We received the authorization code elif attrs.get('code'): @@ -109,12 +110,17 @@ class SocialLoginSerializer(serializers.Serializer): ) token = client.get_access_token(code) access_token = token['access_token'] + tokens_to_parse = {'access_token': access_token} + # If available we add additional data to the dictionary + for key in ["refresh_token", adapter.expires_in_key]: + if key in token: + tokens_to_parse[key] = token[key] else: raise serializers.ValidationError( _("Incorrect input. access_token or code is required.")) - social_token = adapter.parse_token({'access_token': access_token}) + social_token = adapter.parse_token(tokens_to_parse) social_token.app = app try: From 75dd6250bcec2212a1fe87aeda3013987d7368f5 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 3 Jun 2020 22:59:59 -0500 Subject: [PATCH 167/216] Bumps version --- dj_rest_auth/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index c61dbeb..b597e79 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.0.6' +__version__ = '1.0.7' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' From 9e905fc8e47ab360fb9337f93f1f4463bc60068b Mon Sep 17 00:00:00 2001 From: alichass Date: Sun, 14 Jun 2020 17:26:28 -0400 Subject: [PATCH 168/216] added the ability to customise claims in the jwt token - has tests JWT claim serializer now can be set to something custom in settings: JWT_TOKEN_CLAIMS_SERIALIZER = myTokenObtainSerializer Ideally JWT_TOKEN_CLAIMS_SERIALIZER would be a key in REST_AUTH_SERIALIZERS and assigned through import_callable, as with the other serializers; however, I could not quite figure out how to implement it that way --- dj_rest_auth/tests/test_api.py | 66 ++++++++++++++++++++++++++++++++++ dj_rest_auth/utils.py | 20 +++++------ 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 2115415..9554d05 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -18,6 +18,9 @@ try: except ImportError: from django.core.urlresolvers import reverse +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer +from jwt import decode as decode_jwt + @override_settings(ROOT_URLCONF="tests.urls") class APIBasicTests(TestsMixin, TestCase): @@ -605,3 +608,66 @@ class APIBasicTests(TestsMixin, TestCase): # test other TokenError, AttributeError, TypeError (invalid format) resp = self.post(self.logout_url, status=200, data=json.dumps({'refresh': token})) self.assertEqual(resp.status_code, 500) + + + + class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): + @classmethod + def get_token(cls, user): + token = super().get_token(user) + # Add custom claims + token['name'] = user.username + token['email'] = user.email + + return token + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE=None) + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + def test_custom_jwt_claims(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('access_token' in self.response.json.keys(), True) + self.token = self.response.json['access_token'] + claims = decode_jwt(self.token, settings.SECRET_KEY, algorithms='HS256') + self.assertEquals(claims['user_id'], 1) + self.assertEquals(claims['name'], 'person') + self.assertEquals(claims['email'], 'person1@world.com') + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + def test_custom_jwt_claims_cookie_w_authentication(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) + token = resp.cookies.get('jwt-auth').value + claims = decode_jwt(token, settings.SECRET_KEY, algorithms='HS256') + self.assertEquals(claims['user_id'], 1) + self.assertEquals(claims['name'], 'person') + self.assertEquals(claims['email'], 'person1@world.com') + resp = self.get('/protected-view/') + self.assertEquals(resp.status_code, 200) \ No newline at end of file diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index e1ef77a..5f229af 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -15,18 +15,15 @@ def default_create_token(token_model, user, serializer): return token -def jwt_encode(user): - try: - from rest_framework_simplejwt.serializers import TokenObtainPairSerializer - except ImportError: - raise ImportError("rest-framework-simplejwt needs to be installed") - - refresh = TokenObtainPairSerializer.get_token(user) - return refresh.access_token, refresh - - try: + from django.conf import settings from rest_framework_simplejwt.authentication import JWTAuthentication + from rest_framework_simplejwt.serializers import TokenObtainPairSerializer + + def jwt_encode(user): + TOPS = getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer) + refresh = TOPS.get_token(user) + return refresh.access_token, refresh class JWTCookieAuthentication(JWTAuthentication): """ @@ -35,7 +32,6 @@ try: preference to the header). """ def authenticate(self, request): - from django.conf import settings cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) header = self.get_header(request) if header is None: @@ -53,4 +49,4 @@ try: return self.get_user(validated_token), validated_token except ImportError: - pass + raise ImportError("rest-framework-simplejwt needs to be installed") From 15ad7f4c737a63545901e500e2e2b93fac3864a9 Mon Sep 17 00:00:00 2001 From: alichass Date: Sun, 14 Jun 2020 19:15:22 -0400 Subject: [PATCH 169/216] made JWT_TOKEN_CLAIMS_SERIALIZER setting value a callable string rather than a function --- dj_rest_auth/tests/test_api.py | 26 ++++++++++++-------------- dj_rest_auth/utils.py | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 9554d05..f25f5fc 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -21,6 +21,16 @@ except ImportError: from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from jwt import decode as decode_jwt +class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): + @classmethod + def get_token(cls, user): + token = super().get_token(user) + # Add custom claims + token['name'] = user.username + token['email'] = user.email + + return token + @override_settings(ROOT_URLCONF="tests.urls") class APIBasicTests(TestsMixin, TestCase): @@ -610,18 +620,6 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEqual(resp.status_code, 500) - - class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): - @classmethod - def get_token(cls, user): - token = super().get_token(user) - # Add custom claims - token['name'] = user.username - token['email'] = user.email - - return token - - @override_settings(REST_USE_JWT=True) @override_settings(JWT_AUTH_COOKIE=None) @override_settings(REST_FRAMEWORK=dict( @@ -630,7 +628,7 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') def test_custom_jwt_claims(self): payload = { "username": self.USERNAME, @@ -655,7 +653,7 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') def test_custom_jwt_claims_cookie_w_authentication(self): payload = { "username": self.USERNAME, diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 5f229af..fa971de 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -21,7 +21,7 @@ try: from rest_framework_simplejwt.serializers import TokenObtainPairSerializer def jwt_encode(user): - TOPS = getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer) + TOPS = import_callable(getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer)) refresh = TOPS.get_token(user) return refresh.access_token, refresh From 5a751e241ca14b8db6a53decc79b37327d457d6d Mon Sep 17 00:00:00 2001 From: cbomprezzi Date: Mon, 15 Jun 2020 17:12:41 +0200 Subject: [PATCH 170/216] add secure and samesite jwt cookie support --- .gitignore | 5 ++++- dj_rest_auth/views.py | 7 ++++++- docs/configuration.rst | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 136132c..886268d 100644 --- a/.gitignore +++ b/.gitignore @@ -106,4 +106,7 @@ venv.bak/ # mypy .mypy_cache/ demo/react-spa/node_modules/ -demo/react-spa/yarn.lock \ No newline at end of file +demo/react-spa/yarn.lock + +# Visual Studio Code +.vscode/ diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index dc3dea8..6387de6 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -86,6 +86,9 @@ class LoginView(GenericAPIView): response = Response(serializer.data, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) + cookie_secure = getattr(settings, 'JWT_AUTH_SECURE', False) + cookie_samesite = getattr(settings, 'JWT_AUTH_HTTPONLY', True) + cookie_samesite = getattr(settings, 'JWT_AUTH_SAMESITE', 'Lax') from rest_framework_simplejwt.settings import api_settings as jwt_settings if cookie_name: from datetime import datetime @@ -94,7 +97,9 @@ class LoginView(GenericAPIView): cookie_name, self.access_token, expires=expiration, - httponly=True + secure=cookie_secure, + httponly=True, + samesite=cookie_samesite ) return response diff --git a/docs/configuration.rst b/docs/configuration.rst index aac74c2..3b363a8 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -48,6 +48,9 @@ Configuration - **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of djangorestframework-simplejwt https://github.com/SimpleJWT/django-rest-framework-simplejwt, which must also be installed. (default: False) - **JWT_AUTH_COOKIE** - The cookie name/key. +- **JWT_AUTH_SECURE** - If you want the cookie to be only sent to the server when a request is made with the https scheme (default: False). +- **JWT_AUTH_HTTPONLY** - If you want to prevent client-side JavaScript from having access to the cookie (default: True). +- **JWT_AUTH_SAMESITE** - To tell the browser not to send this cookie when performing a cross-origin request (default: 'Lax'). SameSite isn’t supported by all browsers. - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) - **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change From f05abda5b067a73b7011cd00827c85ae511754c5 Mon Sep 17 00:00:00 2001 From: cbomprezzi Date: Mon, 15 Jun 2020 17:57:59 +0200 Subject: [PATCH 171/216] fix distraction errors --- dj_rest_auth/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 6387de6..21e064c 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -87,7 +87,7 @@ class LoginView(GenericAPIView): if getattr(settings, 'REST_USE_JWT', False): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) cookie_secure = getattr(settings, 'JWT_AUTH_SECURE', False) - cookie_samesite = getattr(settings, 'JWT_AUTH_HTTPONLY', True) + cookie_httponly = getattr(settings, 'JWT_AUTH_HTTPONLY', True) cookie_samesite = getattr(settings, 'JWT_AUTH_SAMESITE', 'Lax') from rest_framework_simplejwt.settings import api_settings as jwt_settings if cookie_name: @@ -98,7 +98,7 @@ class LoginView(GenericAPIView): self.access_token, expires=expiration, secure=cookie_secure, - httponly=True, + httponly=cookie_httponly, samesite=cookie_samesite ) return response From 3c86fd9abb9fd0d3db7ef4132db9f5a5ad089526 Mon Sep 17 00:00:00 2001 From: cbomprezzi Date: Mon, 15 Jun 2020 18:27:57 +0200 Subject: [PATCH 172/216] add drf login/logout/registration/user customization --- demo/templates/rest_framework/api.html | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 demo/templates/rest_framework/api.html diff --git a/demo/templates/rest_framework/api.html b/demo/templates/rest_framework/api.html new file mode 100644 index 0000000..57f02c9 --- /dev/null +++ b/demo/templates/rest_framework/api.html @@ -0,0 +1,52 @@ +{% extends "rest_framework/base.html" %} + +{% block style %} + {{ block.super }} + +{% endblock %} + +{% block userlinks %} + {% if user.is_authenticated or response.data.access_token %} + + {% else %} + {% url 'rest_login' as login_url %} +
  • Login
  • + {% url 'rest_register' as register_url %} +
  • Register
  • + {% endif %} +{% endblock %} From bea6e3d229d615568db597f77b4cffc4b768120a Mon Sep 17 00:00:00 2001 From: cbomprezzi Date: Mon, 15 Jun 2020 19:28:23 +0200 Subject: [PATCH 173/216] aligned requirements to tox.ini --- demo/requirements.pip | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/requirements.pip b/demo/requirements.pip index e9276aa..4a0061a 100644 --- a/demo/requirements.pip +++ b/demo/requirements.pip @@ -1,5 +1,5 @@ -django>=1.9.0 -git+https://github.com/jazzband/dj-rest-auth.git@master +django>=2.2 +dj-rest-auth @ git+https://github.com/jazzband/dj-rest-auth.git@master djangorestframework>=3.11.0 djangorestframework-simplejwt==4.4.0 django-allauth>=0.24.1 From 034a8bcc410db798c9d1098cf4f3a96d3b7bf0f1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:13:50 -0500 Subject: [PATCH 174/216] Adds store test results --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index efcf792..6305453 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,6 +21,7 @@ jobs: - run: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage + - store_test_results test-django-2: <<: *template environment: From 095b1cacda2fd4fe1db9164285c4315256a36f89 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:25:55 -0500 Subject: [PATCH 175/216] Adds xml outputs --- .circleci/config.yml | 3 ++- .gitignore | 1 + dj_rest_auth/tests/settings.py | 3 +++ setup.py | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6305453..7faac87 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,8 @@ jobs: - run: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage - - store_test_results + - store_test_results: + path: ~/test-results/ test-django-2: <<: *template environment: diff --git a/.gitignore b/.gitignore index 136132c..4b70f55 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ coverage.xml *.cover .hypothesis/ .pytest_cache/ +test-results/ # Translations *.mo diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index 5f57f91..56f0e94 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -72,6 +72,9 @@ REST_FRAMEWORK = { ) } +TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' +TEST_OUTPUT_DIR = 'test-results' + INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.admin', diff --git a/setup.py b/setup.py index fac004b..fc9811d 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,7 @@ setup( 'with_social': ['django-allauth>=0.25.0'], }, tests_require=[ + 'unittest-xml-reporting>=3.0.2', 'responses>=0.5.0', 'django-allauth>=0.25.0', 'djangorestframework-simplejwt>=4.4.0 ', From ec3cf1cd144e55573cd94257da7f86775254273a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:31:16 -0500 Subject: [PATCH 176/216] Creates test output directory --- .circleci/config.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7faac87..12e3c37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,13 +16,15 @@ jobs: - run: pip install --user -r dj_rest_auth/tests/requirements.pip - run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION - run: - command: coverage run --source=dj_rest_auth setup.py test + command: | + mkdir -p test-results/ + coverage run --source=dj_rest_auth setup.py test name: Test - run: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage - store_test_results: - path: ~/test-results/ + path: test-results/ test-django-2: <<: *template environment: From e913ed7f4dce283e6f3b1573d74325aef44e42b3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:36:30 -0500 Subject: [PATCH 177/216] Coverage.pt report + html out --- .circleci/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 12e3c37..500d811 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,12 +19,16 @@ jobs: command: | mkdir -p test-results/ coverage run --source=dj_rest_auth setup.py test + coverage report + coverage html name: Test - run: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage - store_test_results: path: test-results/ + - store_artifacts: + path: htmlcov/ test-django-2: <<: *template environment: From 6598cdc32373260de1262508c81626c5f08b85d3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:42:11 -0500 Subject: [PATCH 178/216] Builds artifacts --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 500d811..91c0aff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,15 +20,16 @@ jobs: mkdir -p test-results/ coverage run --source=dj_rest_auth setup.py test coverage report - coverage html name: Test - run: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage + - run: + - command: python3 setup.py sdist - store_test_results: path: test-results/ - store_artifacts: - path: htmlcov/ + path: dist/ test-django-2: <<: *template environment: From 3bd8a225d4bdee7343777a821be8b83bb8f49b0f Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:43:07 -0500 Subject: [PATCH 179/216] Adds Build Step --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 91c0aff..e80fac2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,7 +25,8 @@ jobs: command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls name: Coverage - run: - - command: python3 setup.py sdist + command: python3 setup.py sdist + name: Build - store_test_results: path: test-results/ - store_artifacts: From 3f0796647767e18cd665d78f40e59e442e08c680 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:53:16 -0500 Subject: [PATCH 180/216] Simplfies CI config + Pins dep versions --- .circleci/config.yml | 9 ++++++--- dev-requirements.txt | 2 +- dj_rest_auth/tests/requirements.pip | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e80fac2..59f7b6a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,9 +12,12 @@ jobs: executor: docker/docker steps: - checkout - - run: pip install --user -r dev-requirements.txt - - run: pip install --user -r dj_rest_auth/tests/requirements.pip - - run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION + - run: + command: cat dj_rest_auth/tests/requirements.pip dev-requirements.txt | pip install --user -r /dev/stdin + name: Install Static Test Dependencies + - run: + command: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION + name: Install Specific Django + DRF Deps. - run: command: | mkdir -p test-results/ diff --git a/dev-requirements.txt b/dev-requirements.txt index cee8ea6..73b9db0 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,5 +1,5 @@ --editable . responses>=0.5.0 djangorestframework-simplejwt==4.4.0 -django-allauth +django-allauth>=0.25.0 coveralls>=1.11.1 \ No newline at end of file diff --git a/dj_rest_auth/tests/requirements.pip b/dj_rest_auth/tests/requirements.pip index 9f28d70..66af74f 100644 --- a/dj_rest_auth/tests/requirements.pip +++ b/dj_rest_auth/tests/requirements.pip @@ -1,4 +1,4 @@ django-allauth>=0.25.0 -responses>=0.3.0 +responses>=0.5.0 flake8==2.4.0 djangorestframework-simplejwt==4.4.0 From c167e8c5ae2cfbeac29c401e50a88501b7d3da94 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:54:54 -0500 Subject: [PATCH 181/216] Quotes YAML --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 59f7b6a..f815af5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,10 +14,10 @@ jobs: - checkout - run: command: cat dj_rest_auth/tests/requirements.pip dev-requirements.txt | pip install --user -r /dev/stdin - name: Install Static Test Dependencies + name: "Install Static Test Dependencies" - run: command: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION - name: Install Specific Django + DRF Deps. + name: "Install Django + DRF Deps" - run: command: | mkdir -p test-results/ From 476c0bb1e28c1d1c48109c2b8b4eea3309362c30 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 12:57:30 -0500 Subject: [PATCH 182/216] Updates format --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f815af5..c445f6b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,8 +13,9 @@ jobs: steps: - checkout - run: - command: cat dj_rest_auth/tests/requirements.pip dev-requirements.txt | pip install --user -r /dev/stdin - name: "Install Static Test Dependencies" + command: | + cat dj_rest_auth/tests/requirements.pip dev-requirements.txt | pip install --user -r /dev/stdin + name: Install - run: command: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION name: "Install Django + DRF Deps" From 89573f6e68e0d60f5e59fef1db5956c0c165e827 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 13:02:48 -0500 Subject: [PATCH 183/216] Adds run step names --- .circleci/config.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c445f6b..7032790 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,12 +13,11 @@ jobs: steps: - checkout - run: - command: | - cat dj_rest_auth/tests/requirements.pip dev-requirements.txt | pip install --user -r /dev/stdin - name: Install + command: pip install --user -r dev-requirements.txt + name: "Pip Install dev requirements" - run: - command: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION - name: "Install Django + DRF Deps" + command: pip install --user -r dj_rest_auth/tests/requirements.pip + name: "Pip Install test requirements" - run: command: | mkdir -p test-results/ From 0722ec4aeeefeae08a8e9a801394b4a09ee7670c Mon Sep 17 00:00:00 2001 From: alichass Date: Sun, 14 Jun 2020 17:26:28 -0400 Subject: [PATCH 184/216] added the ability to customise claims in the jwt token - has tests JWT claim serializer now can be set to something custom in settings: JWT_TOKEN_CLAIMS_SERIALIZER = myTokenObtainSerializer Ideally JWT_TOKEN_CLAIMS_SERIALIZER would be a key in REST_AUTH_SERIALIZERS and assigned through import_callable, as with the other serializers; however, I could not quite figure out how to implement it that way --- dj_rest_auth/tests/test_api.py | 66 ++++++++++++++++++++++++++++++++++ dj_rest_auth/utils.py | 20 +++++------ 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 2115415..9554d05 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -18,6 +18,9 @@ try: except ImportError: from django.core.urlresolvers import reverse +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer +from jwt import decode as decode_jwt + @override_settings(ROOT_URLCONF="tests.urls") class APIBasicTests(TestsMixin, TestCase): @@ -605,3 +608,66 @@ class APIBasicTests(TestsMixin, TestCase): # test other TokenError, AttributeError, TypeError (invalid format) resp = self.post(self.logout_url, status=200, data=json.dumps({'refresh': token})) self.assertEqual(resp.status_code, 500) + + + + class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): + @classmethod + def get_token(cls, user): + token = super().get_token(user) + # Add custom claims + token['name'] = user.username + token['email'] = user.email + + return token + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE=None) + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + def test_custom_jwt_claims(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('access_token' in self.response.json.keys(), True) + self.token = self.response.json['access_token'] + claims = decode_jwt(self.token, settings.SECRET_KEY, algorithms='HS256') + self.assertEquals(claims['user_id'], 1) + self.assertEquals(claims['name'], 'person') + self.assertEquals(claims['email'], 'person1@world.com') + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.utils.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + def test_custom_jwt_claims_cookie_w_authentication(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + resp = self.post(self.login_url, data=payload, status_code=200) + self.assertEqual(['jwt-auth'], list(resp.cookies.keys())) + token = resp.cookies.get('jwt-auth').value + claims = decode_jwt(token, settings.SECRET_KEY, algorithms='HS256') + self.assertEquals(claims['user_id'], 1) + self.assertEquals(claims['name'], 'person') + self.assertEquals(claims['email'], 'person1@world.com') + resp = self.get('/protected-view/') + self.assertEquals(resp.status_code, 200) \ No newline at end of file diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index e1ef77a..5f229af 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -15,18 +15,15 @@ def default_create_token(token_model, user, serializer): return token -def jwt_encode(user): - try: - from rest_framework_simplejwt.serializers import TokenObtainPairSerializer - except ImportError: - raise ImportError("rest-framework-simplejwt needs to be installed") - - refresh = TokenObtainPairSerializer.get_token(user) - return refresh.access_token, refresh - - try: + from django.conf import settings from rest_framework_simplejwt.authentication import JWTAuthentication + from rest_framework_simplejwt.serializers import TokenObtainPairSerializer + + def jwt_encode(user): + TOPS = getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer) + refresh = TOPS.get_token(user) + return refresh.access_token, refresh class JWTCookieAuthentication(JWTAuthentication): """ @@ -35,7 +32,6 @@ try: preference to the header). """ def authenticate(self, request): - from django.conf import settings cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) header = self.get_header(request) if header is None: @@ -53,4 +49,4 @@ try: return self.get_user(validated_token), validated_token except ImportError: - pass + raise ImportError("rest-framework-simplejwt needs to be installed") From 1dce78194241112f9b0829b26b710c5354248b5d Mon Sep 17 00:00:00 2001 From: alichass Date: Sun, 14 Jun 2020 19:15:22 -0400 Subject: [PATCH 185/216] made JWT_TOKEN_CLAIMS_SERIALIZER setting value a callable string rather than a function --- dj_rest_auth/tests/test_api.py | 26 ++++++++++++-------------- dj_rest_auth/utils.py | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 9554d05..f25f5fc 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -21,6 +21,16 @@ except ImportError: from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from jwt import decode as decode_jwt +class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): + @classmethod + def get_token(cls, user): + token = super().get_token(user) + # Add custom claims + token['name'] = user.username + token['email'] = user.email + + return token + @override_settings(ROOT_URLCONF="tests.urls") class APIBasicTests(TestsMixin, TestCase): @@ -610,18 +620,6 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEqual(resp.status_code, 500) - - class TESTTokenObtainPairSerializer(TokenObtainPairSerializer): - @classmethod - def get_token(cls, user): - token = super().get_token(user) - # Add custom claims - token['name'] = user.username - token['email'] = user.email - - return token - - @override_settings(REST_USE_JWT=True) @override_settings(JWT_AUTH_COOKIE=None) @override_settings(REST_FRAMEWORK=dict( @@ -630,7 +628,7 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') def test_custom_jwt_claims(self): payload = { "username": self.USERNAME, @@ -655,7 +653,7 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = TESTTokenObtainPairSerializer) + @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') def test_custom_jwt_claims_cookie_w_authentication(self): payload = { "username": self.USERNAME, diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 5f229af..fa971de 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -21,7 +21,7 @@ try: from rest_framework_simplejwt.serializers import TokenObtainPairSerializer def jwt_encode(user): - TOPS = getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer) + TOPS = import_callable(getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer)) refresh = TOPS.get_token(user) return refresh.access_token, refresh From ed99925d724f53e9cc515335def0810be531fe11 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 13:35:16 -0500 Subject: [PATCH 186/216] Adds docs --- docs/configuration.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/configuration.rst b/docs/configuration.rst index 3b363a8..f421d76 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -12,6 +12,8 @@ Configuration - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.JWTSerializer`` + - JWT_TOKEN_CLAIMS_SERIALIZER - A custom JWT Claim serializer. Default is `rest_framework_simplejwt.serializers.TokenObtainPairSerializer` + - USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``dj_rest_auth.serializers.UserDetailsSerializer`` - PASSWORD_RESET_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetView``, default value ``dj_rest_auth.serializers.PasswordResetSerializer`` From 68f35c22e681ecddf4d3ced2e9e00152a52d73e6 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 13:56:29 -0500 Subject: [PATCH 187/216] Bumps version for release --- dj_rest_auth/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index b597e79..514748c 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.0.7' +__version__ = '1.0.8' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' From de089672106bd2709e90758fd9cc9414777e1e6c Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 20 Jun 2020 13:57:51 -0500 Subject: [PATCH 188/216] Fixes docs --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index f421d76..2d98190 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -12,7 +12,7 @@ Configuration - JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.JWTSerializer`` - - JWT_TOKEN_CLAIMS_SERIALIZER - A custom JWT Claim serializer. Default is `rest_framework_simplejwt.serializers.TokenObtainPairSerializer` + - JWT_TOKEN_CLAIMS_SERIALIZER - A custom JWT Claim serializer. Default is ``rest_framework_simplejwt.serializers.TokenObtainPairSerializer`` - USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``dj_rest_auth.serializers.UserDetailsSerializer`` From ca355baf7ad5206521ae7c738c5972438fcc58ad Mon Sep 17 00:00:00 2001 From: Dhaval Mehta <20968146+dhaval-mehta@users.noreply.github.com> Date: Tue, 23 Jun 2020 13:20:22 +0530 Subject: [PATCH 189/216] Add compatibility for DRF 3.12 --- dj_rest_auth/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index 21e064c..a5d06d7 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -78,10 +78,10 @@ class LoginView(GenericAPIView): 'refresh_token': self.refresh_token } serializer = serializer_class(instance=data, - context={'request': self.request}) + context=self.get_serializer_context()) else: serializer = serializer_class(instance=self.token, - context={'request': self.request}) + context=self.get_serializer_context()) response = Response(serializer.data, status=status.HTTP_200_OK) if getattr(settings, 'REST_USE_JWT', False): @@ -106,7 +106,7 @@ class LoginView(GenericAPIView): def post(self, request, *args, **kwargs): self.request = request self.serializer = self.get_serializer(data=self.request.data, - context={'request': request}) + context=self.get_serializer_context()) self.serializer.is_valid(raise_exception=True) self.login() From 1b2073a1872c2e22426746dc2c27a734e83462b7 Mon Sep 17 00:00:00 2001 From: Dhaval Mehta <20968146+dhaval-mehta@users.noreply.github.com> Date: Tue, 23 Jun 2020 15:28:03 +0530 Subject: [PATCH 190/216] no need to pass context to get_serializer --- dj_rest_auth/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dj_rest_auth/views.py b/dj_rest_auth/views.py index a5d06d7..28b472d 100644 --- a/dj_rest_auth/views.py +++ b/dj_rest_auth/views.py @@ -105,8 +105,7 @@ class LoginView(GenericAPIView): def post(self, request, *args, **kwargs): self.request = request - self.serializer = self.get_serializer(data=self.request.data, - context=self.get_serializer_context()) + self.serializer = self.get_serializer(data=self.request.data) self.serializer.is_valid(raise_exception=True) self.login() From 8568c8221b7d970e9cdbabf60974ec3b9fc8fa1c Mon Sep 17 00:00:00 2001 From: Noam Date: Tue, 23 Jun 2020 20:27:58 +0300 Subject: [PATCH 191/216] Added missing requirement for tox. --- dev-requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 73b9db0..8ecc9c6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,4 +2,5 @@ responses>=0.5.0 djangorestframework-simplejwt==4.4.0 django-allauth>=0.25.0 -coveralls>=1.11.1 \ No newline at end of file +coveralls>=1.11.1 +unittest-xml-reporting>=3.0.2 \ No newline at end of file From b2c06fa18ac4bd232e31c0cac5e08a423c8f91e4 Mon Sep 17 00:00:00 2001 From: Noam Date: Tue, 23 Jun 2020 20:28:18 +0300 Subject: [PATCH 192/216] Moved jwt auth class to separate file to avoid hard dependency. --- demo/demo/settings.py | 2 +- dj_rest_auth/jwt_auth.py | 27 +++++++++++++++++++++++ dj_rest_auth/tests/settings.py | 2 +- dj_rest_auth/tests/test_api.py | 6 ++--- dj_rest_auth/utils.py | 40 ++++++++-------------------------- docs/installation.rst | 14 ++++++------ 6 files changed, 48 insertions(+), 43 deletions(-) create mode 100644 dj_rest_auth/jwt_auth.py diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 4496f0d..03de0a1 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -123,7 +123,7 @@ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', - 'dj_rest_auth.utils.JWTCookieAuthentication' + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' } diff --git a/dj_rest_auth/jwt_auth.py b/dj_rest_auth/jwt_auth.py new file mode 100644 index 0000000..39f9c78 --- /dev/null +++ b/dj_rest_auth/jwt_auth.py @@ -0,0 +1,27 @@ +from django.conf import settings +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class JWTCookieAuthentication(JWTAuthentication): + """ + An authentication plugin that hopefully authenticates requests through a JSON web + token provided in a request cookie (and through the header as normal, with a + preference to the header). + """ + + def authenticate(self, request): + cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) + header = self.get_header(request) + if header is None: + if cookie_name: + raw_token = request.COOKIES.get(cookie_name) + else: + return None + else: + raw_token = self.get_raw_token(header) + + if raw_token is None: + return None + + validated_token = self.get_validated_token(raw_token) + return self.get_user(validated_token), validated_token diff --git a/dj_rest_auth/tests/settings.py b/dj_rest_auth/tests/settings.py index 56f0e94..e038c45 100644 --- a/dj_rest_auth/tests/settings.py +++ b/dj_rest_auth/tests/settings.py @@ -68,7 +68,7 @@ TEMPLATES = [ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', - 'dj_rest_auth.utils.JWTCookieAuthentication', + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', ) } diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index f25f5fc..3c1ff0e 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -563,7 +563,7 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(JWT_AUTH_COOKIE='jwt-auth') @override_settings(REST_FRAMEWORK=dict( DEFAULT_AUTHENTICATION_CLASSES=[ - 'dj_rest_auth.utils.JWTCookieAuthentication' + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' ] )) @override_settings(REST_SESSION_LOGIN=False) @@ -624,7 +624,7 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(JWT_AUTH_COOKIE=None) @override_settings(REST_FRAMEWORK=dict( DEFAULT_AUTHENTICATION_CLASSES=[ - 'dj_rest_auth.utils.JWTCookieAuthentication' + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' ] )) @override_settings(REST_SESSION_LOGIN=False) @@ -649,7 +649,7 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(JWT_AUTH_COOKIE='jwt-auth') @override_settings(REST_FRAMEWORK=dict( DEFAULT_AUTHENTICATION_CLASSES=[ - 'dj_rest_auth.utils.JWTCookieAuthentication' + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' ] )) @override_settings(REST_SESSION_LOGIN=False) diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index fa971de..7011c8a 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -1,5 +1,7 @@ from importlib import import_module +from django.conf import settings + def import_callable(path_or_callable): if hasattr(path_or_callable, '__call__'): @@ -15,38 +17,14 @@ def default_create_token(token_model, user, serializer): return token -try: - from django.conf import settings - from rest_framework_simplejwt.authentication import JWTAuthentication +def jwt_encode(user): from rest_framework_simplejwt.serializers import TokenObtainPairSerializer + TOPS = import_callable(getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer)) + refresh = TOPS.get_token(user) + return refresh.access_token, refresh - def jwt_encode(user): - TOPS = import_callable(getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer)) - refresh = TOPS.get_token(user) - return refresh.access_token, refresh - - class JWTCookieAuthentication(JWTAuthentication): - """ - An authentication plugin that hopefully authenticates requests through a JSON web - token provided in a request cookie (and through the header as normal, with a - preference to the header). - """ - def authenticate(self, request): - cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) - header = self.get_header(request) - if header is None: - if cookie_name: - raw_token = request.COOKIES.get(cookie_name) - else: - return None - else: - raw_token = self.get_raw_token(header) - - if raw_token is None: - return None - - validated_token = self.get_validated_token(raw_token) - return self.get_user(validated_token), validated_token +try: + from .jwt_auth import JWTCookieAuthentication except ImportError: - raise ImportError("rest-framework-simplejwt needs to be installed") + pass diff --git a/docs/installation.rst b/docs/installation.rst index 94579ee..95de78f 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -35,9 +35,9 @@ Installation .. code-block:: python - python manage.py migrate - - + python manage.py migrate + + You're good to go now! @@ -59,7 +59,7 @@ Registration (optional) 'allauth.account', 'dj_rest_auth.registration', ) - + SITE_ID = 1 3. Add dj_rest_auth.registration urls: @@ -76,7 +76,7 @@ Registration (optional) Social Authentication (optional) -------------------------------- -Using ``django-allauth``, ``dj-rest-auth`` provides helpful class for creating social media authentication view. +Using ``django-allauth``, ``dj-rest-auth`` provides helpful class for creating social media authentication view. .. note:: Points 1 and 2 are related to ``django-allauth`` configuration, so if you have already configured social authentication, then please go to step 3. See ``django-allauth`` documentation for more details. @@ -223,7 +223,7 @@ In urls.py: You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts: .. code-block:: python - + from dj_rest_auth.registration.views import ( SocialAccountListView, SocialAccountDisconnectView ) @@ -259,7 +259,7 @@ By default ``dj-rest-auth`` uses Django's Token-based authentication. If you wan ... 'DEFAULT_AUTHENTICATION_CLASSES': ( ... - 'dj_rest_auth.utils.JWTCookieAuthentication', + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', ) ... } From ee3f3710e2f9d2b0812229fb2201e934ea874d8f Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 24 Jun 2020 01:33:52 -0500 Subject: [PATCH 193/216] Bumps version --- dj_rest_auth/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index 514748c..d9b45c6 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.0.8' +__version__ = '1.0.9' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' From 0bf711166eda2c50a27ea6c399872100075b9046 Mon Sep 17 00:00:00 2001 From: alichass Date: Sat, 27 Jun 2020 05:58:47 -0400 Subject: [PATCH 194/216] Added CSRF checks on authenticated views when client uses JWT-cookie auth Setting can also be set to true that turns on csrf checks on unauthenticated views --- dj_rest_auth/jwt_auth.py | 18 +++++- dj_rest_auth/tests/test_api.py | 100 ++++++++++++++++++++++++++++++++- dj_rest_auth/tests/urls.py | 13 ++++- 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/dj_rest_auth/jwt_auth.py b/dj_rest_auth/jwt_auth.py index 39f9c78..1611cf5 100644 --- a/dj_rest_auth/jwt_auth.py +++ b/dj_rest_auth/jwt_auth.py @@ -1,6 +1,7 @@ from django.conf import settings from rest_framework_simplejwt.authentication import JWTAuthentication - +from rest_framework import exceptions +from rest_framework.authentication import CSRFCheck class JWTCookieAuthentication(JWTAuthentication): """ @@ -8,6 +9,17 @@ class JWTCookieAuthentication(JWTAuthentication): token provided in a request cookie (and through the header as normal, with a preference to the header). """ + def enforce_csrf(self, request): + """ + Enforce CSRF validation for session based authentication. + """ + check = CSRFCheck() + # populates request.META['CSRF_COOKIE'], which is used in process_view() + check.process_request(request) + reason = check.process_view(request, None, (), {}) + if reason: + # CSRF failed, bail with explicit error message + raise exceptions.PermissionDenied('CSRF Failed: %s' % reason) def authenticate(self, request): cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None) @@ -15,6 +27,10 @@ class JWTCookieAuthentication(JWTAuthentication): if header is None: if cookie_name: raw_token = request.COOKIES.get(cookie_name) + if getattr(settings, 'JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED', False): #True at your own risk + self.enforce_csrf(request) + elif raw_token is not None and getattr(settings, 'JWT_AUTH_COOKIE_USE_CSRF', False): + self.enforce_csrf(request) else: return None else: diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index 3c1ff0e..a8c2048 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -668,4 +668,102 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEquals(claims['name'], 'person') self.assertEquals(claims['email'], 'person1@world.com') resp = self.get('/protected-view/') - self.assertEquals(resp.status_code, 200) \ No newline at end of file + self.assertEquals(resp.status_code, 200) + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(JWT_AUTH_COOKIE_USE_CSRF=True) + @override_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=False) + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(CSRF_COOKIE_SECURE =True) + @override_settings(CSRF_COOKIE_HTTPONLY =True) + def test_csrf_wo_login_csrf_enforcement(self): + from .mixins import APIClient + payload = { + "username": self.USERNAME, + "password": self.PASS + } + client = APIClient(enforce_csrf_checks=True) + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + + response = client.get(reverse("getcsrf")) + csrftoken = client.cookies['csrftoken'].value + + resp = client.post(self.login_url, payload) + self.assertTrue('jwt-auth' in list(client.cookies.keys())) + self.assertTrue('csrftoken' in list(client.cookies.keys())) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH JWT AUTH HEADER + jwtclient = APIClient(enforce_csrf_checks=True) + token = resp.data['access_token'] + resp = jwtclient.get('/protected-view/') + self.assertEquals(resp.status_code, 403) + resp = jwtclient.get('/protected-view/', HTTP_AUTHORIZATION='Bearer '+token) + self.assertEquals(resp.status_code, 200) + resp = jwtclient.post('/protected-view/', {}) + self.assertEquals(resp.status_code, 403) + resp = jwtclient.post('/protected-view/', {}, HTTP_AUTHORIZATION='Bearer '+token) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH COOKIES + #fail w/o csrftoken in payload + resp = client.post('/protected-view/', {}) + self.assertEquals(resp.status_code, 403) + + csrfparam = {"csrfmiddlewaretoken": csrftoken} + resp = client.post('/protected-view/', csrfparam) + self.assertEquals(resp.status_code, 200) + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(JWT_AUTH_COOKIE_USE_CSRF=True) + @override_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) #True at your own risk + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(CSRF_COOKIE_SECURE =True) + @override_settings(CSRF_COOKIE_HTTPONLY =True) + def test_csrf_w_login_csrf_enforcement(self): + from .mixins import APIClient + payload = { + "username": self.USERNAME, + "password": self.PASS + } + client = APIClient(enforce_csrf_checks=True) + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + + response = client.get(reverse("getcsrf")) + csrftoken = client.cookies['csrftoken'].value + + #fail w/o csrftoken in payload + resp = client.post(self.login_url, payload) + self.assertEquals(resp.status_code, 403) + + payload['csrfmiddlewaretoken'] = csrftoken + resp = client.post(self.login_url, payload) + self.assertTrue('jwt-auth' in list(client.cookies.keys())) + self.assertTrue('csrftoken' in list(client.cookies.keys())) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH JWT AUTH HEADER does not make sense + + ## TEST WITH COOKIES + #fail w/o csrftoken in payload + resp = client.post('/protected-view/', {}) + self.assertEquals(resp.status_code, 403) + + csrfparam = {"csrfmiddlewaretoken": csrftoken} + resp = client.post('/protected-view/', csrfparam) + self.assertEquals(resp.status_code, 200) + diff --git a/dj_rest_auth/tests/urls.py b/dj_rest_auth/tests/urls.py index f1796d6..3e3e28e 100644 --- a/dj_rest_auth/tests/urls.py +++ b/dj_rest_auth/tests/urls.py @@ -10,6 +10,8 @@ from dj_rest_auth.social_serializers import (TwitterConnectSerializer, from dj_rest_auth.urls import urlpatterns from django.conf.urls import include, url from django.views.generic import TemplateView +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import ensure_csrf_cookie from rest_framework import permissions from rest_framework.decorators import api_view from rest_framework.response import Response @@ -24,6 +26,9 @@ class ExampleProtectedView(APIView): def get(self, *args, **kwargs): return Response(dict(success=True)) + def post(self, *args, **kwargs): + return Response(dict(success=True)) + class FacebookLogin(SocialLoginView): adapter_class = FacebookOAuth2Adapter @@ -59,6 +64,11 @@ def twitter_login_view(request): class TwitterLoginNoAdapter(SocialLoginView): serializer_class = TwitterLoginSerializer +@ensure_csrf_cookie +@api_view(['GET']) +def get_csrf_cookie(request): + return Response() + urlpatterns += [ url(r'^rest-registration/', include('dj_rest_auth.registration.urls')), @@ -77,5 +87,6 @@ urlpatterns += [ url(r'^protected-view/$', ExampleProtectedView.as_view()), url(r'^socialaccounts/(?P\d+)/disconnect/$', SocialAccountDisconnectView.as_view(), name='social_account_disconnect'), - url(r'^accounts/', include('allauth.socialaccount.urls')) + url(r'^accounts/', include('allauth.socialaccount.urls')), + url(r'^getcsrf/', get_csrf_cookie, name='getcsrf'), ] From 909ed75d519d20f644de6e971455319e22326169 Mon Sep 17 00:00:00 2001 From: alichass Date: Sat, 27 Jun 2020 14:58:29 -0400 Subject: [PATCH 195/216] Update test_api.py s'more tests for my sanity --- dj_rest_auth/tests/test_api.py | 93 ++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index a8c2048..c9141d9 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -671,6 +671,47 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEquals(resp.status_code, 200) + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(JWT_AUTH_COOKIE_USE_CSRF=False) + @override_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=False) + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(CSRF_COOKIE_SECURE =True) + @override_settings(CSRF_COOKIE_HTTPONLY =True) + def test_wo_csrf_enforcement(self): + from .mixins import APIClient + payload = { + "username": self.USERNAME, + "password": self.PASS + } + client = APIClient(enforce_csrf_checks=True) + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + + resp = client.post(self.login_url, payload) + self.assertTrue('jwt-auth' in list(client.cookies.keys())) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH JWT AUTH HEADER + jwtclient = APIClient(enforce_csrf_checks=True) + token = resp.data['access_token'] + resp = jwtclient.get('/protected-view/', HTTP_AUTHORIZATION='Bearer '+token) + self.assertEquals(resp.status_code, 200) + resp = jwtclient.post('/protected-view/', {}, HTTP_AUTHORIZATION='Bearer '+token) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH COOKIES + resp = client.get('/protected-view/') + self.assertEquals(resp.status_code, 200) + + resp = client.post('/protected-view/', {}) + self.assertEquals(resp.status_code, 200) + + @override_settings(REST_USE_JWT=True) @override_settings(JWT_AUTH_COOKIE='jwt-auth') @override_settings(JWT_AUTH_COOKIE_USE_CSRF=True) @@ -713,6 +754,8 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEquals(resp.status_code, 200) ## TEST WITH COOKIES + resp = client.get('/protected-view/') + self.assertEquals(resp.status_code, 200) #fail w/o csrftoken in payload resp = client.post('/protected-view/', {}) self.assertEquals(resp.status_code, 403) @@ -759,6 +802,56 @@ class APIBasicTests(TestsMixin, TestCase): ## TEST WITH JWT AUTH HEADER does not make sense ## TEST WITH COOKIES + resp = client.get('/protected-view/') + self.assertEquals(resp.status_code, 200) + #fail w/o csrftoken in payload + resp = client.post('/protected-view/', {}) + self.assertEquals(resp.status_code, 403) + + csrfparam = {"csrfmiddlewaretoken": csrftoken} + resp = client.post('/protected-view/', csrfparam) + self.assertEquals(resp.status_code, 200) + + + @override_settings(REST_USE_JWT=True) + @override_settings(JWT_AUTH_COOKIE='jwt-auth') + @override_settings(JWT_AUTH_COOKIE_USE_CSRF=False) + @override_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) #True at your own risk + @override_settings(REST_FRAMEWORK=dict( + DEFAULT_AUTHENTICATION_CLASSES=[ + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication' + ] + )) + @override_settings(REST_SESSION_LOGIN=False) + @override_settings(CSRF_COOKIE_SECURE =True) + @override_settings(CSRF_COOKIE_HTTPONLY =True) + def test_csrf_w_login_csrf_enforcement_2(self): + from .mixins import APIClient + payload = { + "username": self.USERNAME, + "password": self.PASS + } + client = APIClient(enforce_csrf_checks=True) + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + + response = client.get(reverse("getcsrf")) + csrftoken = client.cookies['csrftoken'].value + + #fail w/o csrftoken in payload + resp = client.post(self.login_url, payload) + self.assertEquals(resp.status_code, 403) + + payload['csrfmiddlewaretoken'] = csrftoken + resp = client.post(self.login_url, payload) + self.assertTrue('jwt-auth' in list(client.cookies.keys())) + self.assertTrue('csrftoken' in list(client.cookies.keys())) + self.assertEquals(resp.status_code, 200) + + ## TEST WITH JWT AUTH HEADER does not make sense + + ## TEST WITH COOKIES + resp = client.get('/protected-view/') + self.assertEquals(resp.status_code, 200) #fail w/o csrftoken in payload resp = client.post('/protected-view/', {}) self.assertEquals(resp.status_code, 403) From b15400e9c48a1e262a01fc043ae8ba552694a236 Mon Sep 17 00:00:00 2001 From: Adrian Gonzalez Date: Thu, 2 Jul 2020 23:26:48 -0500 Subject: [PATCH 196/216] Fixes JWT_TOKEN_CLAIMS_SERIALIZER get attribute --- dj_rest_auth/utils.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dj_rest_auth/utils.py b/dj_rest_auth/utils.py index 7011c8a..4ecfbc1 100644 --- a/dj_rest_auth/utils.py +++ b/dj_rest_auth/utils.py @@ -19,7 +19,14 @@ def default_create_token(token_model, user, serializer): def jwt_encode(user): from rest_framework_simplejwt.serializers import TokenObtainPairSerializer - TOPS = import_callable(getattr(settings, 'JWT_TOKEN_CLAIMS_SERIALIZER', TokenObtainPairSerializer)) + rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {}) + + JWTTokenClaimsSerializer = rest_auth_serializers.get( + 'JWT_TOKEN_CLAIMS_SERIALIZER', + TokenObtainPairSerializer + ) + + TOPS = import_callable(JWTTokenClaimsSerializer) refresh = TOPS.get_token(user) return refresh.access_token, refresh From 8e939e30ed0e8efb775e3d6214572a90c3e42d59 Mon Sep 17 00:00:00 2001 From: Aprimus Date: Tue, 7 Jul 2020 18:29:18 +0200 Subject: [PATCH 197/216] fix tests override settings for TokenObtainPairSerializer --- dj_rest_auth/tests/test_api.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index c9141d9..b6bba96 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -628,7 +628,11 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') + @override_settings( + REST_AUTH_SERIALIZERS={ + "JWT_TOKEN_CLAIMS_SERIALIZER": TESTTokenObtainPairSerializer + } + ) def test_custom_jwt_claims(self): payload = { "username": self.USERNAME, @@ -653,7 +657,11 @@ class APIBasicTests(TestsMixin, TestCase): ] )) @override_settings(REST_SESSION_LOGIN=False) - @override_settings(JWT_TOKEN_CLAIMS_SERIALIZER = 'tests.test_api.TESTTokenObtainPairSerializer') + @override_settings( + REST_AUTH_SERIALIZERS={ + "JWT_TOKEN_CLAIMS_SERIALIZER": TESTTokenObtainPairSerializer + } + ) def test_custom_jwt_claims_cookie_w_authentication(self): payload = { "username": self.USERNAME, From 12173461ac6ecaecb11e06b1ede570965bcda306 Mon Sep 17 00:00:00 2001 From: Aprimus Date: Tue, 7 Jul 2020 20:27:01 +0200 Subject: [PATCH 198/216] Change to string import instead of serializer class --- dj_rest_auth/tests/test_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dj_rest_auth/tests/test_api.py b/dj_rest_auth/tests/test_api.py index b6bba96..0f8ee42 100644 --- a/dj_rest_auth/tests/test_api.py +++ b/dj_rest_auth/tests/test_api.py @@ -630,7 +630,7 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(REST_SESSION_LOGIN=False) @override_settings( REST_AUTH_SERIALIZERS={ - "JWT_TOKEN_CLAIMS_SERIALIZER": TESTTokenObtainPairSerializer + "JWT_TOKEN_CLAIMS_SERIALIZER": 'tests.test_api.TESTTokenObtainPairSerializer' } ) def test_custom_jwt_claims(self): @@ -659,7 +659,7 @@ class APIBasicTests(TestsMixin, TestCase): @override_settings(REST_SESSION_LOGIN=False) @override_settings( REST_AUTH_SERIALIZERS={ - "JWT_TOKEN_CLAIMS_SERIALIZER": TESTTokenObtainPairSerializer + "JWT_TOKEN_CLAIMS_SERIALIZER": 'tests.test_api.TESTTokenObtainPairSerializer' } ) def test_custom_jwt_claims_cookie_w_authentication(self): From e530ca71ee7d26d7dddd632fd159ea69576399b9 Mon Sep 17 00:00:00 2001 From: Patrick Steadman Date: Tue, 7 Jul 2020 22:32:37 -0400 Subject: [PATCH 199/216] Update install docs to prevent error on user deletion If using `django-allauth`, the `allauth.socialaccount` app is *required*, or else errors will occur when deleting users (and possibly in other places). The `allauth.socialaccount` app cannot be left out even if you're just doing email registration and not using the social auth providers. See: https://github.com/pennersr/django-allauth/issues/1975#issuecomment-384075169 Another user of this library also got tripped up here: https://github.com/jazzband/dj-rest-auth/issues/18#issue-590399626 --- docs/installation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 95de78f..effb2bb 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -46,7 +46,7 @@ Registration (optional) 1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install 'dj-rest-auth[with_social]'``. -2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: +2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account``, ``authauth.socialaccount`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: 3. Add ``SITE_ID = 1`` to your django settings.py @@ -57,6 +57,7 @@ Registration (optional) 'django.contrib.sites', 'allauth', 'allauth.account', + 'allauth.socialaccount', 'dj_rest_auth.registration', ) From 19a188df621ede4ca27022b6838b75b20b763efd Mon Sep 17 00:00:00 2001 From: Patrick Steadman Date: Tue, 7 Jul 2020 22:35:01 -0400 Subject: [PATCH 200/216] fix typo --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index effb2bb..3b69fbf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -46,7 +46,7 @@ Registration (optional) 1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install 'dj-rest-auth[with_social]'``. -2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account``, ``authauth.socialaccount`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: +2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account``, ``allauth.socialaccount`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py: 3. Add ``SITE_ID = 1`` to your django settings.py From 7397ffd45011414448ba9f58146ed6863cac18e7 Mon Sep 17 00:00:00 2001 From: "Mahmoud.Adel" Date: Thu, 9 Jul 2020 10:53:41 +0200 Subject: [PATCH 201/216] do token generation only when allauth_settings.EMAIL_VERIFICATION is not set to 'MANDATORY' --- dj_rest_auth/registration/views.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dj_rest_auth/registration/views.py b/dj_rest_auth/registration/views.py index cdd5b94..5f338bd 100644 --- a/dj_rest_auth/registration/views.py +++ b/dj_rest_auth/registration/views.py @@ -69,10 +69,12 @@ class RegisterView(CreateAPIView): def perform_create(self, serializer): user = serializer.save(self.request) - if getattr(settings, 'REST_USE_JWT', False): - self.access_token, self.refresh_token = jwt_encode(user) - else: - create_token(self.token_model, user, serializer) + if allauth_settings.EMAIL_VERIFICATION != \ + allauth_settings.EmailVerificationMethod.MANDATORY: + if getattr(settings, 'REST_USE_JWT', False): + self.access_token, self.refresh_token = jwt_encode(user) + else: + create_token(self.token_model, user, serializer) complete_signup(self.request._request, user, allauth_settings.EMAIL_VERIFICATION, From 26482ccb2d3f336dc5d0f3f1f678a82f2b0f638e Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 9 Jul 2020 23:26:53 -0500 Subject: [PATCH 202/216] Updates Docs, Bumps Version --- dj_rest_auth/__version__.py | 2 +- docs/configuration.rst | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index d9b45c6..6a0c7e6 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.0.9' +__version__ = '1.1.0' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' diff --git a/docs/configuration.rst b/docs/configuration.rst index 2d98190..12d9ad2 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -41,18 +41,15 @@ Configuration - REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``dj_rest_auth.registration.serializers.RegisterSerializer`` .. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance - - **REST_AUTH_TOKEN_MODEL** - path to model class for tokens, default value ``'rest_framework.authtoken.models.Token'`` - - **REST_AUTH_TOKEN_CREATOR** - path to callable or callable for creating tokens, default value ``dj_rest_auth.utils.default_create_token``. - - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) - - **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of djangorestframework-simplejwt https://github.com/SimpleJWT/django-rest-framework-simplejwt, which must also be installed. (default: False) - **JWT_AUTH_COOKIE** - The cookie name/key. - **JWT_AUTH_SECURE** - If you want the cookie to be only sent to the server when a request is made with the https scheme (default: False). - **JWT_AUTH_HTTPONLY** - If you want to prevent client-side JavaScript from having access to the cookie (default: True). - **JWT_AUTH_SAMESITE** - To tell the browser not to send this cookie when performing a cross-origin request (default: 'Lax'). SameSite isn’t supported by all browsers. - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) - - **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change +- **JWT_AUTH_COOKIE_USE_CSRF** - Enables CSRF checks for only authenticated views when using the JWT cookie for auth. Does not effect a client's ability to authenticate using a JWT Bearer Auth header without a CSRF token. +- **JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED** - Enables CSRF checks for authenticated and unauthenticated views when using the JWT cookie for auth. It does not effect a client's ability to authenticate using a JWT Bearer Auth header without a CSRF token (though getting the JWT token in the first place without passing a CSRF token isnt possible). From 140112927fc9b8e5eba908fb4b98032b5d28ecec Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Sat, 8 Aug 2020 01:59:10 +0200 Subject: [PATCH 203/216] switch to using path() instead of deprecated url() --- dj_rest_auth/urls.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 9c79691..92b99d2 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -1,21 +1,21 @@ from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView, PasswordResetConfirmView, PasswordResetView, UserDetailsView) -from django.conf.urls import url +from django.urls import path from django.conf import settings urlpatterns = [ # URLs that do not require a session or valid token - url(r'^password/reset/$', PasswordResetView.as_view(), - name='rest_password_reset'), - url(r'^password/reset/confirm/$', PasswordResetConfirmView.as_view(), - name='rest_password_reset_confirm'), - url(r'^login/$', LoginView.as_view(), name='rest_login'), + path('password/reset/', PasswordResetView.as_view(), + name='rest_password_reset'), + path('password/reset/confirm/', PasswordResetConfirmView.as_view(), + name='rest_password_reset_confirm'), + path('login/', LoginView.as_view(), name='rest_login'), # URLs that require a user to be logged in with a valid session / token. - url(r'^logout/$', LogoutView.as_view(), name='rest_logout'), - url(r'^user/$', UserDetailsView.as_view(), name='rest_user_details'), - url(r'^password/change/$', PasswordChangeView.as_view(), - name='rest_password_change'), + path('logout/', LogoutView.as_view(), name='rest_logout'), + path('user/', UserDetailsView.as_view(), name='rest_user_details'), + path('password/change/', PasswordChangeView.as_view(), + name='rest_password_change'), ] if getattr(settings, 'REST_USE_JWT', False): @@ -24,6 +24,6 @@ if getattr(settings, 'REST_USE_JWT', False): ) urlpatterns += [ - url(r'^token/verify/$', TokenVerifyView.as_view(), name='token_verify'), - url(r'^token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'), + path('token/verify/', TokenVerifyView.as_view(), name='token_verify'), + path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), ] From a67cdb5a52e2bae6102d558074b4d2ba59c04907 Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Sat, 8 Aug 2020 01:59:23 +0200 Subject: [PATCH 204/216] switch to using path() and re_path() instead of deprecated url() --- dj_rest_auth/registration/urls.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dj_rest_auth/registration/urls.py b/dj_rest_auth/registration/urls.py index c42cec6..04fc7f4 100644 --- a/dj_rest_auth/registration/urls.py +++ b/dj_rest_auth/registration/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import url +from django.urls import path, re_path from django.views.generic import TemplateView from .views import RegisterView, VerifyEmailView urlpatterns = [ - url(r'^$', RegisterView.as_view(), name='rest_register'), - url(r'^verify-email/$', VerifyEmailView.as_view(), name='rest_verify_email'), + path('', RegisterView.as_view(), name='rest_register'), + path('verify-email/', VerifyEmailView.as_view(), name='rest_verify_email'), # This url is used by django-allauth and empty TemplateView is # defined just to allow reverse() call inside app, for example when email @@ -18,6 +18,6 @@ urlpatterns = [ # If you don't want to use API on that step, then just use ConfirmEmailView # view from: # django-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py - url(r'^account-confirm-email/(?P[-:\w]+)/$', TemplateView.as_view(), + re_path(r'^account-confirm-email/(?P[-:\w]+)/$', TemplateView.as_view(), name='account_confirm_email'), ] From 854834a8cfb3ee72dff6f35c1a0422c847b80ab9 Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Sat, 8 Aug 2020 02:01:21 +0200 Subject: [PATCH 205/216] At install_requires, changed the versions of Django and djangorestframework to 2.0 and 3.7.0 respectively as path() wasn't introduced before it --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index fc9811d..8e706f5 100644 --- a/setup.py +++ b/setup.py @@ -27,8 +27,8 @@ setup( keywords='django rest auth registration rest-framework django-registration api', zip_safe=False, install_requires=[ - 'Django>=1.11', - 'djangorestframework>=3.1.3', + 'Django>=2.0', + 'djangorestframework>=3.7.0', ], extras_require={ 'with_social': ['django-allauth>=0.25.0'], From 32892f3177de396c52dc669c4caed82b68fdc175 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 9 Aug 2020 13:59:28 -0500 Subject: [PATCH 206/216] Fixes tests not running explicitly declared versions --- .circleci/config.yml | 8 ++++---- dev-requirements.txt | 6 ------ dj_rest_auth/tests/requirements.pip | 2 ++ dj_rest_auth/urls.py | 9 +++------ 4 files changed, 9 insertions(+), 16 deletions(-) delete mode 100644 dev-requirements.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index 7032790..8745182 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,14 +7,14 @@ jobs: docker: - image: circleci/python:3.8.0 environment: - DJANGO_VERSION: 3.0.3 - DRF: 3.11 + DJANGO_VERSION: 3.1 + DRF: 3.11.1 executor: docker/docker steps: - checkout - run: - command: pip install --user -r dev-requirements.txt - name: "Pip Install dev requirements" + command: pip install --user Django==$DJANGO_VERSION djangorestframework==$DRF + name: "Pip install version-specific Django + DRF" - run: command: pip install --user -r dj_rest_auth/tests/requirements.pip name: "Pip Install test requirements" diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index 8ecc9c6..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ ---editable . -responses>=0.5.0 -djangorestframework-simplejwt==4.4.0 -django-allauth>=0.25.0 -coveralls>=1.11.1 -unittest-xml-reporting>=3.0.2 \ No newline at end of file diff --git a/dj_rest_auth/tests/requirements.pip b/dj_rest_auth/tests/requirements.pip index 66af74f..0692df1 100644 --- a/dj_rest_auth/tests/requirements.pip +++ b/dj_rest_auth/tests/requirements.pip @@ -2,3 +2,5 @@ django-allauth>=0.25.0 responses>=0.5.0 flake8==2.4.0 djangorestframework-simplejwt==4.4.0 +unittest-xml-reporting>=3.0.2 +coveralls>=1.11.1 diff --git a/dj_rest_auth/urls.py b/dj_rest_auth/urls.py index 92b99d2..81c6111 100644 --- a/dj_rest_auth/urls.py +++ b/dj_rest_auth/urls.py @@ -6,16 +6,13 @@ from django.conf import settings urlpatterns = [ # URLs that do not require a session or valid token - path('password/reset/', PasswordResetView.as_view(), - name='rest_password_reset'), - path('password/reset/confirm/', PasswordResetConfirmView.as_view(), - name='rest_password_reset_confirm'), + path('password/reset/', PasswordResetView.as_view(), name='rest_password_reset'), + path('password/reset/confirm/', PasswordResetConfirmView.as_view(), name='rest_password_reset_confirm'), path('login/', LoginView.as_view(), name='rest_login'), # URLs that require a user to be logged in with a valid session / token. path('logout/', LogoutView.as_view(), name='rest_logout'), path('user/', UserDetailsView.as_view(), name='rest_user_details'), - path('password/change/', PasswordChangeView.as_view(), - name='rest_password_change'), + path('password/change/', PasswordChangeView.as_view(), name='rest_password_change'), ] if getattr(settings, 'REST_USE_JWT', False): From d30bcb191e125fad77bf485732f73272345eab95 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 9 Aug 2020 14:07:00 -0500 Subject: [PATCH 207/216] Bumps version for release --- dj_rest_auth/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/__version__.py b/dj_rest_auth/__version__.py index 6a0c7e6..0744496 100644 --- a/dj_rest_auth/__version__.py +++ b/dj_rest_auth/__version__.py @@ -1,7 +1,7 @@ __title__ = 'dj-rest-auth' __description__ = 'Authentication and Registration in Django Rest Framework.' __url__ = 'http://github.com/jazzband/dj-rest-auth' -__version__ = '1.1.0' +__version__ = '1.1.1' __author__ = '@iMerica https://github.com/iMerica' __author_email__ = 'imichael@pm.me' __license__ = 'MIT' From 90d76179db967352bded357922a8bc2106d02cdb Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 9 Aug 2020 14:30:52 -0500 Subject: [PATCH 208/216] Fixes tox config --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 484802b..528cbdf 100644 --- a/tox.ini +++ b/tox.ini @@ -11,15 +11,15 @@ skipsdist = true envlist = python{3.5,3.6,3.7,3.8}-django22 - python{3.6,3.7,3.8}-django30 + python{3.6,3.7,3.8}-django31 [testenv] commands = python ./runtests.py deps = - -rdev-requirements.txt + -rdj_rest_auth/tests/requirements.pip django22: Django>=2.2,<2.3 - django30: Django>=3.0,<3.1 + django31: Django>=3.1 # Configuration for coverage and flake8 is being set in `./setup.cfg` [testenv:coverage] @@ -27,7 +27,7 @@ commands = coverage run ./runtests.py coverage report deps = - -rdev-requirements.txt + -rdj_rest_auth/tests/requirements.pip [testenv:flake8] changedir = {toxinidir}/dj_rest_auth From 73d26c502bf90b5ce76256b49acdf2f164334e01 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 9 Aug 2020 20:03:55 -0500 Subject: [PATCH 209/216] Fixes docs --- docs/introduction.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/introduction.rst b/docs/introduction.rst index 6f4d354..951e10f 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -22,13 +22,9 @@ Apps structure * ``dj_rest_auth.registration`` has logic related with registration and social media authentication -Angular app ------------ -- iMerica has also created angular module which uses API endpoints from this app - `angular-django-registration-auth `_ - - -Demo project +Demo projects ------------ - You can also check our :doc:`Demo Project
    ` which is using jQuery on frontend. +- There is also a React demo project based on Create-React-App in demo/react-spa/ From 11e34167d2c7c8e6777f57f5471227f875972942 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 16 Aug 2020 11:10:25 -0500 Subject: [PATCH 210/216] Adds pypi Github action --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..01b2ef6 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,6 @@ +- name: Publish package to Pypi + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} \ No newline at end of file From bdc2a5c213962cf0b8daa197c883498d0ab33d73 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 16 Aug 2020 11:23:11 -0500 Subject: [PATCH 211/216] Workflow tweak --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 01b2ef6..74769f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,6 @@ -- name: Publish package to Pypi +- name: Publish package if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@master with: user: __token__ - password: ${{ secrets.pypi_password }} \ No newline at end of file + password: ${{ secrets.pypi_password }} From d37bcab8dc010ab673cd1beb182d28a0bfb3914a Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 16 Aug 2020 11:25:48 -0500 Subject: [PATCH 212/216] Adds complete yaml for GH Action --- .github/workflows/main.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 74769f7..5f4b43c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,14 @@ -- name: Publish package - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.pypi_password }} +name: Greet Everyone +on: [push] + +jobs: + build: + name: Publish + runs-on: ubuntu-latest + steps: + - name: Publish package + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} From 33fbff3ea3cf6bf28f5e23ebefa09947a7f63571 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 17 Aug 2020 00:29:29 -0500 Subject: [PATCH 213/216] Updates action --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f4b43c..39feedd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: Greet Everyone +name: Release to PyPi on: [push] jobs: From 8fa6fc59ce8483c900085d8501c23143e3378c55 Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Fri, 21 Aug 2020 01:02:09 +0200 Subject: [PATCH 214/216] use import_callable() to correctly import classes in REST_AUTH_REGISTER_PERMISSION_CLASSES --- dj_rest_auth/registration/app_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dj_rest_auth/registration/app_settings.py b/dj_rest_auth/registration/app_settings.py index bbc7075..f0b6c62 100644 --- a/dj_rest_auth/registration/app_settings.py +++ b/dj_rest_auth/registration/app_settings.py @@ -13,5 +13,5 @@ RegisterSerializer = import_callable(serializers.get('REGISTER_SERIALIZER', Defa def register_permission_classes(): permission_classes = [AllowAny, ] for klass in getattr(settings, 'REST_AUTH_REGISTER_PERMISSION_CLASSES', tuple()): - permission_classes.append(klass) + permission_classes.append(import_callable(klass)) return tuple(permission_classes) From 7e5b3db2a1a03a48e5875a346db1037b2fed09fb Mon Sep 17 00:00:00 2001 From: Mahmoud Adel Date: Fri, 21 Aug 2020 01:30:53 +0200 Subject: [PATCH 215/216] add REST_AUTH_REGISTER_PERMISSION_CLASSES --- docs/configuration.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/configuration.rst b/docs/configuration.rst index 12d9ad2..5ab8156 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -41,6 +41,17 @@ Configuration - REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``dj_rest_auth.registration.serializers.RegisterSerializer`` .. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance +- **REST_AUTH_REGISTER_PERMISSION_CLASSES** - A tuple contains paths of another permission classes you wish to be used in ``RegisterView``, ``AllowAny`` is included by default. + + Example : + + .. code-block:: python + + REST_AUTH_REGISTER_PERMISSION_CLASSES = ( + 'rest_framework.permissions.IsAuthenticated', + 'path.to.another.permission.class', + ... + ) - **REST_AUTH_TOKEN_MODEL** - path to model class for tokens, default value ``'rest_framework.authtoken.models.Token'`` - **REST_AUTH_TOKEN_CREATOR** - path to callable or callable for creating tokens, default value ``dj_rest_auth.utils.default_create_token``. - **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True) From 4453096993fe4a52c4c5591d324ae3edc905fe60 Mon Sep 17 00:00:00 2001 From: Sagar Chavan Date: Tue, 8 Sep 2020 00:27:45 -0400 Subject: [PATCH 216/216] add documentation for token verify & refresh --- docs/api_endpoints.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index dc159ce..5f6c474 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -47,6 +47,25 @@ Basic Returns pk, username, email, first_name, last_name +- /dj-rest-auth/token/verify/ (POST) + + - token + + Returns an empty JSON object. + + .. note:: ``REST_USE_JWT = True`` to use token/verify/ route. + .. note:: Takes a token and indicates if it is valid. This view provides no information about a token's fitness for a particular use. Will return a ``HTTP 200 OK`` in case of a valid token and ``HTTP 401 Unauthorized`` with ``{"detail": "Token is invalid or expired", "code": "token_not_valid"}`` in case of a invalid or expired token. + + +- /dj-rest-auth/token/refresh/ (POST) (`see also `_) + + - refresh + + Returns access + + .. note:: ``REST_USE_JWT = True`` to use token/refresh/ route. + .. note:: Takes a refresh type JSON web token and returns an access type JSON web token if the refresh token is valid. ``HTTP 401 Unauthorized`` with ``{"detail": "Token is invalid or expired", "code": "token_not_valid"}`` in case of a invalid or expired token. + Registration ------------ @@ -64,7 +83,7 @@ Registration .. note:: If you set account email verification as mandatory, you have to add the VerifyEmailView with the used `name`. You need to import the view: ``from dj_rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name: ``path('dj-rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list. - + Social Media Authentication