django-session-security-continued 3.0.0a1__py3-none-any.whl → 3.0.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {django_session_security_continued-3.0.0a1.dist-info → django_session_security_continued-3.0.0a2.dist-info}/METADATA +5 -3
  2. django_session_security_continued-3.0.0a2.dist-info/RECORD +40 -0
  3. session_security/locale/ca/LC_MESSAGES/django.po +30 -0
  4. session_security/locale/cs/LC_MESSAGES/django.po +30 -0
  5. session_security/locale/de/LC_MESSAGES/django.po +29 -0
  6. session_security/locale/es/LC_MESSAGES/django.po +31 -0
  7. session_security/locale/fr/LC_MESSAGES/django.po +29 -0
  8. session_security/locale/it/LC_MESSAGES/django.po +31 -0
  9. session_security/locale/nl/LC_MESSAGES/django.po +31 -0
  10. session_security/locale/pl/LC_MESSAGES/django.po +35 -0
  11. session_security/locale/pt_BR/LC_MESSAGES/django.po +28 -0
  12. session_security/locale/pt_PT/LC_MESSAGES/django.po +28 -0
  13. session_security/static/session_security/script.js +282 -0
  14. session_security/static/session_security/style.css +30 -0
  15. session_security/templates/session_security/all.html +42 -0
  16. session_security/templates/session_security/dialog.html +9 -0
  17. session_security/tests/conftest.py +12 -3
  18. session_security/tests/test_packaging.py +15 -0
  19. session_security/tests/test_script.py +10 -10
  20. django_session_security_continued-3.0.0a1.dist-info/RECORD +0 -25
  21. {django_session_security_continued-3.0.0a1.dist-info → django_session_security_continued-3.0.0a2.dist-info}/WHEEL +0 -0
  22. {django_session_security_continued-3.0.0a1.dist-info → django_session_security_continued-3.0.0a2.dist-info}/licenses/LICENSE +0 -0
  23. {django_session_security_continued-3.0.0a1.dist-info → django_session_security_continued-3.0.0a2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-session-security-continued
3
- Version: 3.0.0a1
3
+ Version: 3.0.0a2
4
4
  Summary: Client and server-side session timeout enforcement with warnings for Django 4.2+.
5
5
  Author: Matt Bosworth (https://github.com/mattbo), Fabio Caritas Barrionuevo da Luz (https://github.com/luzfcb), Pēteris Caune (https://github.com/cuu508), John David Giese (https://github.com/johndgiese), Jose Antonio Martin Prieto (https://github.com/jantoniomartin), Richard Moorhead (https://github.com/autodidacticon), Jean-Michel Nirgal Vourgère (https://github.com/nirgal), Michał Pasternak (https://github.com/mpasternak), James Pic (https://github.com/jpic), Matthew Schettler (https://github.com/mschettler), Scott Sexton (https://github.com/scottsexton), Jacek Ostański (https://github.com/jacoor), Aaron Krill (https://github.com/krillr), @yscumc (https://github.com/yscumc), Marco Fucci (https://github.com/marcofucci), Andrei Coman (https://github.com/comandrei), Ali Hasan Imam (https://github.com/alihasanimam), Joel Hillacre (https://github.com/jhillacre), Peter Mack (https://github.com/pmack)
6
6
  Maintainer-email: Arrai Innovations <support@arrai.com>
@@ -36,7 +36,8 @@ Dynamic: license-file
36
36
  ![python 3.10 status][]
37
37
  ![python 3.11 status][]
38
38
  ![python 3.12 status][]
39
- ![coverage status][]
39
+ ![python coverage status][]
40
+ ![javascript coverage status][]
40
41
 
41
42
  <!--prettier-ignore-start-->
42
43
  <!--TOC-->
@@ -203,7 +204,8 @@ Contributions are welcome. Please fork the repository and create a pull request
203
204
  [python 3.10 status]: https://docs.arrai.dev/dssc/artifacts/main/python_3.10.svg
204
205
  [python 3.11 status]: https://docs.arrai.dev/dssc/artifacts/main/python_3.11.svg
205
206
  [python 3.12 status]: https://docs.arrai.dev/dssc/artifacts/main/python_3.12.svg
206
- [coverage status]: https://docs.arrai.dev/dssc/artifacts/main/python_3.9.coverage.svg
207
+ [python coverage status]: https://docs.arrai.dev/dssc/artifacts/main/python_3.9.coverage.svg
208
+ [javascript coverage status]: https://docs.arrai.dev/dssc/artifacts/main/js-coverage.svg
207
209
  [ruff status]: https://docs.arrai.dev/dssc/artifacts/main/ruff.svg
208
210
  [pipenv]: https://github.com/pypa/pipenv
209
211
  [pip-audit status]: https://docs.arrai.dev/dssc/artifacts/main/pip-audit.svg
@@ -0,0 +1,40 @@
1
+ django_session_security_continued-3.0.0a2.dist-info/licenses/LICENSE,sha256=sTEwnChiEDBXv8ZDFVYDAhXfIA1wjpwuIhTVDhGLssw,1107
2
+ session_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ session_security/middleware.py,sha256=matyK1lCSv5ZeIRWoxj-yThKNDMHRUM1Xf929pWTVmE,4008
4
+ session_security/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ session_security/settings.py,sha256=pIxklXg3F1uyvsb0dl7ArQ0vquWLCie0CC5vy_fICas,2242
6
+ session_security/urls.py,sha256=QK_diUsqjyQkU6UQpUW9SV_3kpf0223glrtnM7jft7M,510
7
+ session_security/utils.py,sha256=d19NpP7f5kEdrVdZIae95c-Oeuw9gk0m4pATzuzlw3w,466
8
+ session_security/views.py,sha256=ktla3T5Pk8qajdVTIhatWKprm10iIjM-Ek495APDBLs,879
9
+ session_security/locale/ca/LC_MESSAGES/django.po,sha256=8YFDOajFwTFzf9CCl72LgWNs_qCaE6qEk6o1kgGG-7A,1131
10
+ session_security/locale/cs/LC_MESSAGES/django.po,sha256=9Pm6VHWXAqJiKKiblsIkm90WmnWmH2nolLjRRpKZsUU,1087
11
+ session_security/locale/de/LC_MESSAGES/django.po,sha256=apFmNzpW05ifHi1b_gDjKgxqbtrwz0TvtmvbTJrRPxw,1041
12
+ session_security/locale/es/LC_MESSAGES/django.po,sha256=c4cjeFUCCdQ5tJ9h44MrHAJnorsCGy6-ccjscrIteIA,1113
13
+ session_security/locale/fr/LC_MESSAGES/django.po,sha256=hdSp5VQdYX59z397bIQwSHymlCzgi61VRZYxPWeTz9U,1054
14
+ session_security/locale/it/LC_MESSAGES/django.po,sha256=8R2M_4MJreW1-_EDI_h_eNMzFnYrLfOmnOUqLTD3hDc,1130
15
+ session_security/locale/nl/LC_MESSAGES/django.po,sha256=UqCiUJDB5rnZNmS4mzo6ko3lG-Q2mDiSki3_fBlzxRY,1071
16
+ session_security/locale/pl/LC_MESSAGES/django.po,sha256=Wl4dQj--cRmPUQ_ysa07fy1G4GFkMBOvu_laDutX3nY,1285
17
+ session_security/locale/pt_BR/LC_MESSAGES/django.po,sha256=BU2U8nH1g6p65KSpzedLqymnHfhMwPwBDkquVPo7nKo,1021
18
+ session_security/locale/pt_PT/LC_MESSAGES/django.po,sha256=K3ss4zjKO90ALOzEY0Q3Ffe_GaSPXAOj5doSxR_ZL00,989
19
+ session_security/static/session_security/script.js,sha256=XePGKd6wEZQMnwUaSFX-3tW3MCNOb_BvM_ByOTe9siI,8614
20
+ session_security/static/session_security/style.css,sha256=11eLkqYNauOZBdXQAyLlSq0vC1dVdJNRHZBcUui54YY,558
21
+ session_security/templates/session_security/all.html,sha256=m1W6pX-4eTwIvjWU8fL40Ft1Gn_Q0uGJbG2gl6EVpuI,1777
22
+ session_security/templates/session_security/dialog.html,sha256=63GLn2f0H9vfoy3FlKzI6S3WChRfVmpdF1qif6_9IgY,451
23
+ session_security/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ session_security/templatetags/session_security_tags.py,sha256=Vhrxe0ThWpEbQZUlqxKl9XXOx8HhF96EoBmVk5hxhrc,627
25
+ session_security/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ session_security/tests/conftest.py,sha256=uT2X0J7uzmQD6TEPN86RtgkigC298BNMEl3UPu97nUE,5067
27
+ session_security/tests/test_base.py,sha256=bvqz385wyyBQNhrpeTyUTY0fWosLB9wOhPOBrt0tOBM,1775
28
+ session_security/tests/test_middleware.py,sha256=iLFlXXfoBwUBNUJPhyRvPR657y-MORj1nyjh3GXFNPc,3612
29
+ session_security/tests/test_packaging.py,sha256=MBoXky_pAWo_PFnZE1m_0p2h_kAX6nrCVxIPKmBcKpY,399
30
+ session_security/tests/test_script.py,sha256=nyPNrWJJ5F8TIrVwA-k-j8km3wrN6znW8WngViA63dk,2703
31
+ session_security/tests/test_templates.py,sha256=qXukArdCZvvthGLyHZzise9xV6Q8kFx-eUy8TCxsYXU,471
32
+ session_security/tests/test_views.py,sha256=97Ssf4nXGj0OIGc-fFf3_LdjC3k9yFMr6QD9CRsTrLc,1183
33
+ session_security/tests/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ session_security/tests/project/settings.py,sha256=BAN820rroRvYMKQPtTYvqkdjmy9ce5fznFWelrBG58c,2999
35
+ session_security/tests/project/urls.py,sha256=wFMGt1wQLCdoaAsJRltFypR473RJnkxbqReWh0FMFWE,1136
36
+ session_security/tests/project/wsgi.py,sha256=VFz8yKLbSm4-C5ejuLJ_ZuPoKZ1WP17WJVMx2R17Z8M,426
37
+ django_session_security_continued-3.0.0a2.dist-info/METADATA,sha256=_5RWprGJtAWE1r0ro0PdNVIIss63a-9uKFyXWKJO_aE,9070
38
+ django_session_security_continued-3.0.0a2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ django_session_security_continued-3.0.0a2.dist-info/top_level.txt,sha256=sUgnA1DNG4V434n9luYoNsltkfMgkCnI6GBZV6oKWJI,17
40
+ django_session_security_continued-3.0.0a2.dist-info/RECORD,,
@@ -0,0 +1,30 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ # , fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2020-01-23 08:23+0100\n"
12
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+ #: session_security/templates/session_security/all.html:32
21
+ msgid "You have unsaved changes in a form of this page."
22
+ msgstr "Un formulari d'aquesta pàgina té canvis sense guardar"
23
+
24
+ #: session_security/templates/session_security/dialog.html:6
25
+ msgid "Your session is about to expire"
26
+ msgstr "La teva sessió està a punt de caducar"
27
+
28
+ #: session_security/templates/session_security/dialog.html:7
29
+ msgid "Click or type to extend your session."
30
+ msgstr "Fes clic o premi una tecla per a continuar la sessió"
@@ -0,0 +1,30 @@
1
+ # Czech translation for the django-session-security app.
2
+ # Copyright (C) 2016 IT Management
3
+ # This file is distributed under the same license as the django-session-security package.
4
+ #
5
+ #, fuzzy
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: PACKAGE VERSION\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2016-05-18 15:58+0200\n"
11
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "Language: \n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
19
+
20
+ #: templates/session_security/all.html:33
21
+ msgid "You have unsaved changes in a form of this page."
22
+ msgstr "Ve formuláři na této stránce máte neuložené změny."
23
+
24
+ #: templates/session_security/dialog.html:6
25
+ msgid "Your session is about to expire"
26
+ msgstr "Vaše přihlášení brzy vyprší"
27
+
28
+ #: templates/session_security/dialog.html:7
29
+ msgid "Click to extend your session."
30
+ msgstr "Klikněte pro prodloužení vašeho přihlášení."
@@ -0,0 +1,29 @@
1
+ # Copyright (C) 2013 James Pic
2
+ # This file is distributed under the same license as the
3
+ # django-session-security package.
4
+ # James Pic <jamespic@gmail.com> 2013
5
+ msgid ""
6
+ msgstr ""
7
+ "Project-Id-Version: 2.0.3\n"
8
+ "Report-Msgid-Bugs-To: \n"
9
+ "POT-Creation-Date: 2024-03-18 11:41-0400\n"
10
+ "PO-Revision-Date: 2024-03-18 16:26+0100\n"
11
+ "Last-Translator: Daniel Zielinski <daniel@loctimize.com>\n"
12
+ "Language: German\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: 8bit\n"
16
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
17
+
18
+ #: templates/session_security/all.html:32
19
+ msgid "You have unsaved changes in a form of this page."
20
+ msgstr ""
21
+ "Sie haben nicht gespeicherte Änderungen in einem Formular auf dieser Seite."
22
+
23
+ #: templates/session_security/dialog.html:6
24
+ msgid "Your session is about to expire"
25
+ msgstr "Ihre Sitzung läuft in Kürze ab."
26
+
27
+ #: templates/session_security/dialog.html:7
28
+ msgid "Click or type to extend your session."
29
+ msgstr "Klicken oder tippen Sie, um nicht automatisch ausgeloggt zu werden."
@@ -0,0 +1,31 @@
1
+ # Spanish translation for the django-session-security app.
2
+ # Copyright (C) 2014
3
+ # This file is distributed under the same license as the django-session-security package.
4
+ # Jose Antonio Martin <jantonio.martin@gmail.com>, 2014.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2014-03-13 12:36+0100\n"
12
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+
21
+ #: templates/session_security/all.html:33
22
+ msgid "You have unsaved changes in a form of this page."
23
+ msgstr "Un formulario de esta página tiene cambios sin guardar"
24
+
25
+ #: templates/session_security/dialog.html:6
26
+ msgid "Your session is about to expire"
27
+ msgstr "Tu sesión está a punto de caducar"
28
+
29
+ #: templates/session_security/dialog.html:7
30
+ msgid "Click or type to extend your session."
31
+ msgstr "Haz click o pulse una tecla para continuar la sesión"
@@ -0,0 +1,29 @@
1
+ # Copyright (C) 2013 James Pic
2
+ # This file is distributed under the same license as the
3
+ # django-session-security package.
4
+ # James Pic <jamespic@gmail.com> 2013
5
+ msgid ""
6
+ msgstr ""
7
+ "Project-Id-Version: 2.0.3\n"
8
+ "Report-Msgid-Bugs-To: \n"
9
+ "POT-Creation-Date: 2018-10-23 11:41-0400\n"
10
+ "PO-Revision-Date: 2013-02-19 16:26+0100\n"
11
+ "Last-Translator: James Pic <jamespic@gmail.com>\n"
12
+ "Language: French\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: 8bit\n"
16
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
17
+
18
+ #: templates/session_security/all.html:32
19
+ msgid "You have unsaved changes in a form of this page."
20
+ msgstr ""
21
+ "Vous avez des changements non sauvegardés dans un formulaire de cette page."
22
+
23
+ #: templates/session_security/dialog.html:6
24
+ msgid "Your session is about to expire"
25
+ msgstr "Votre session est sur le point d'expirer"
26
+
27
+ #: templates/session_security/dialog.html:7
28
+ msgid "Click or type to extend your session."
29
+ msgstr "Touchez la souris ou tapez votre clavier pour étendre la durée de votre session."
@@ -0,0 +1,31 @@
1
+ # Italian translation for the django-session-security app.
2
+ # Copyright (C) 2019
3
+ # This file is distributed under the same license as the django-session-security package.
4
+ # Ali Hasan Imam <imam.aiub@gmail.com>, 2019.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2019-05-14 14:35+0200\n"
12
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+
21
+ #: session_security/templates/session_security/all.html:32
22
+ msgid "You have unsaved changes in a form of this page."
23
+ msgstr "Hai modifiche non salvate nella form di questa pagina."
24
+
25
+ #: session_security/templates/session_security/dialog.html:6
26
+ msgid "Your session is about to expire"
27
+ msgstr "La tua sessione sta per scadere"
28
+
29
+ #: session_security/templates/session_security/dialog.html:7
30
+ msgid "Click or type to extend your session."
31
+ msgstr "Fai clic per estendere la sessione."
@@ -0,0 +1,31 @@
1
+ # Dutch translation for the django-session-security app.
2
+ # Copyright (C) 2014
3
+ # This file is distributed under the same license as the django-session-security package.
4
+ # Rik Dekker <rdekker@jouwomgeving.nl>, 2016.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: \n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2014-03-13 12:36+0100\n"
11
+ "PO-Revision-Date: 2018-05-14 08:56+0200\n"
12
+ "Language: nl\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: 8bit\n"
16
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
+ "Last-Translator: Rik Dekker <rdekker@jouwomgeving.nl>\n"
18
+ "Language-Team: \n"
19
+ "X-Generator: Poedit 2.0.6\n"
20
+
21
+ #: templates/session_security/all.html:33
22
+ msgid "You have unsaved changes in a form of this page."
23
+ msgstr "Je hebt niet-opgeslagen wijzigingen op deze pagina."
24
+
25
+ #: templates/session_security/dialog.html:6
26
+ msgid "Your session is about to expire"
27
+ msgstr "Jouw sessie verloopt bijna"
28
+
29
+ #: templates/session_security/dialog.html:7
30
+ msgid "Click or type to extend your session."
31
+ msgstr "Klik of typ om je sessie te verlengen."
@@ -0,0 +1,35 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: django-session-security\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2017-06-26 12:42+0200\n"
11
+ "PO-Revision-Date: 2017-06-26 12:44+0200\n"
12
+ "Last-Translator: Michał Pasternak <michal.dtz@gmail.com>\n"
13
+ "Language: pl\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=UTF-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+ "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
18
+ "|| n%100>=20) ? 1 : 2);\n"
19
+ "X-Generator: Poedit 2.0.2\n"
20
+ "Language-Team: \n"
21
+
22
+ #: session_security/templates/session_security/all.html:32
23
+ msgid "You have unsaved changes in a form of this page."
24
+ msgstr ""
25
+ "Na tej stronie znajduje się formularz, w którym zmiany mogły jeszcze nie "
26
+ "zostać zapisane."
27
+
28
+ #: session_security/templates/session_security/dialog.html:6
29
+ msgid "Your session is about to expire"
30
+ msgstr "Twoja sesja za chwilę wygaśnie"
31
+
32
+ #: session_security/templates/session_security/dialog.html:7
33
+ msgid "Click or type to extend your session."
34
+ msgstr ""
35
+ "Kliknij lub wciśnij dowolny klawisz, aby wydłużyć czas trwania Twojej sesji."
@@ -0,0 +1,28 @@
1
+ # Copyright (C) 2013 James Pic
2
+ # This file is distributed under the same license as the
3
+ # django-session-security package.
4
+ # James Pic <jamespic@gmail.com> 2013
5
+ msgid ""
6
+ msgstr ""
7
+ "Project-Id-Version: 2.0.3\n"
8
+ "Report-Msgid-Bugs-To: \n"
9
+ "POT-Creation-Date: 2013-12-06 18:00-0300\n"
10
+ "PO-Revision-Date: 2013-12-06 18:00-0300\n"
11
+ "Last-Translator: Fabio Caritas Barrionuevo da Luz <bnafta at gmail.com>\n"
12
+ "Language: Brazilian Portuguese\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: 8bit\n"
16
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
17
+
18
+ #: templates/session_security/all.html:32
19
+ msgid "You have unsaved changes in a form of this page."
20
+ msgstr "Você tem alterações não salvas em um formulário desta página."
21
+
22
+ #: templates/session_security/dialog.html:6
23
+ msgid "Your session is about to expire"
24
+ msgstr "Sua sessão está prestes a expirar"
25
+
26
+ #: templates/session_security/dialog.html:7
27
+ msgid "Click to extend your session."
28
+ msgstr "Clique para prolongar a sua sessão."
@@ -0,0 +1,28 @@
1
+ # Copyright (C) 2015 Nuno Khan
2
+ # This file is distributed under the same license as the
3
+ # django-session-security package.
4
+ # Nuno Khan <nunok7@gmail.com> 2015
5
+ msgid ""
6
+ msgstr ""
7
+ "Project-Id-Version: 2.0.3\n"
8
+ "Report-Msgid-Bugs-To: \n"
9
+ "POT-Creation-Date: 2015-06-16 16:29+0100\n"
10
+ "PO-Revision-Date: 2015-09-18 18:00-0300\n"
11
+ "Last-Translator: Nuno Khan <nunok7 at gmail.com>\n"
12
+ "Language: Portuguese\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: 8bit\n"
16
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
17
+
18
+ #: templates/session_security/all.html:33
19
+ msgid "You have unsaved changes in a form of this page."
20
+ msgstr "Você tem alterações não guardadas em um formulário desta página."
21
+
22
+ #: templates/session_security/dialog.html:6
23
+ msgid "Your session is about to expire"
24
+ msgstr "Sua sessão está prestes a expirar"
25
+
26
+ #: templates/session_security/dialog.html:7
27
+ msgid "Click to extend your session."
28
+ msgstr "Clique para prolongar a sua sessão."
@@ -0,0 +1,282 @@
1
+ (function (globalWindow, globalDocument) {
2
+ "use strict";
3
+
4
+ if (typeof globalWindow.yourlabs === "undefined") {
5
+ globalWindow.yourlabs = {};
6
+ }
7
+
8
+ function assign(target, source) {
9
+ if (!source) {
10
+ return target;
11
+ }
12
+ Object.keys(source).forEach(function (key) {
13
+ target[key] = source[key];
14
+ });
15
+ return target;
16
+ }
17
+
18
+ function buildUrl(url, params) {
19
+ let hasQuery = url.indexOf("?") !== -1;
20
+ let query = [];
21
+ for (let key in params) {
22
+ if (Object.prototype.hasOwnProperty.call(params, key)) {
23
+ query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
24
+ }
25
+ }
26
+ return url + (hasQuery ? "&" : "?") + query.join("&");
27
+ }
28
+
29
+ function hasDirtyForms() {
30
+ return globalDocument.querySelector("form[data-dirty]") !== null;
31
+ }
32
+
33
+ function SessionSecurity(options) {
34
+ this.warning = globalDocument.getElementById("session_security_warning");
35
+ this.warningVisible = false;
36
+ this.lastActivity = new Date();
37
+ this.events = [
38
+ "mousemove",
39
+ "scroll",
40
+ "keyup",
41
+ "click",
42
+ "touchstart",
43
+ "touchend",
44
+ "touchmove",
45
+ ];
46
+ this.counterElementID = "session_security_counter";
47
+ this.expired = false;
48
+ this.counterStarted = false;
49
+ this.timeout = null;
50
+ this.counterTimeout = null;
51
+
52
+ assign(this, options || {});
53
+
54
+ let self = this;
55
+ this.activityHandler = this.activity.bind(this);
56
+ this.events.forEach(function (eventName) {
57
+ globalDocument.addEventListener(eventName, self.activityHandler, true);
58
+ });
59
+
60
+ if (this.confirmFormDiscard) {
61
+ this.beforeUnloadHandler = this.onbeforeunload.bind(this);
62
+ globalWindow.addEventListener("beforeunload", this.beforeUnloadHandler);
63
+ globalDocument.addEventListener(
64
+ "change",
65
+ function (event) {
66
+ self.formChange(event);
67
+ },
68
+ true,
69
+ );
70
+ globalDocument.addEventListener(
71
+ "submit",
72
+ function (event) {
73
+ self.formClean(event);
74
+ },
75
+ true,
76
+ );
77
+ globalDocument.addEventListener(
78
+ "reset",
79
+ function (event) {
80
+ self.formClean(event);
81
+ },
82
+ true,
83
+ );
84
+ }
85
+
86
+ this.apply();
87
+ }
88
+
89
+ SessionSecurity.prototype.expire = function () {
90
+ if (this.expired) {
91
+ return;
92
+ }
93
+ this.expired = true;
94
+ if (typeof this.returnToUrl === "string" && this.returnToUrl.length > 0) {
95
+ globalWindow.location.href = this.returnToUrl;
96
+ } else {
97
+ globalWindow.location.reload();
98
+ }
99
+ };
100
+
101
+ SessionSecurity.prototype.showWarning = function () {
102
+ if (!this.warning) {
103
+ return;
104
+ }
105
+ this.warning.style.display = "block";
106
+ this.warning.setAttribute("aria-hidden", "false");
107
+ this.warningVisible = true;
108
+ let modal = this.warning.querySelector(".session_security_modal");
109
+ if (modal && typeof modal.focus === "function") {
110
+ modal.focus();
111
+ }
112
+ };
113
+
114
+ SessionSecurity.prototype.hideWarning = function () {
115
+ if (!this.warning) {
116
+ return;
117
+ }
118
+ this.warning.style.display = "none";
119
+ this.warning.setAttribute("aria-hidden", "true");
120
+ this.warningVisible = false;
121
+ };
122
+
123
+ SessionSecurity.prototype.activity = function () {
124
+ let now = new Date();
125
+ if (now - this.lastActivity < 1000) {
126
+ return;
127
+ }
128
+
129
+ let idleFor = Math.floor((now - this.lastActivity) / 1000);
130
+ this.lastActivity = now;
131
+
132
+ if (idleFor >= this.expireAfter) {
133
+ this.expire();
134
+ return;
135
+ }
136
+
137
+ if (this.warningVisible) {
138
+ this.ping();
139
+ this.hideWarning();
140
+ }
141
+ };
142
+
143
+ SessionSecurity.prototype.ping = function () {
144
+ let idleFor = Math.floor((new Date() - this.lastActivity) / 1000);
145
+ let self = this;
146
+
147
+ fetch(buildUrl(this.pingUrl, { idleFor: idleFor }), {
148
+ method: "GET",
149
+ credentials: "same-origin",
150
+ cache: "no-store",
151
+ headers: {
152
+ "X-Requested-With": "XMLHttpRequest",
153
+ },
154
+ })
155
+ .then(function (response) {
156
+ return response.json();
157
+ })
158
+ .then(function (data) {
159
+ self.pong(data);
160
+ })
161
+ .catch(function () {
162
+ self.apply();
163
+ });
164
+ };
165
+
166
+ SessionSecurity.prototype.pong = function (data) {
167
+ if (data === "logout") {
168
+ this.expire();
169
+ return;
170
+ }
171
+
172
+ this.lastActivity = new Date();
173
+ this.lastActivity.setSeconds(this.lastActivity.getSeconds() - data);
174
+ this.apply();
175
+ };
176
+
177
+ SessionSecurity.prototype.apply = function () {
178
+ clearTimeout(this.timeout);
179
+ let idleFor = Math.floor((new Date() - this.lastActivity) / 1000);
180
+ let nextPing;
181
+
182
+ if (idleFor >= this.expireAfter) {
183
+ this.expire();
184
+ return;
185
+ } else if (idleFor >= this.warnAfter) {
186
+ if (!this.counterStarted && this.counterElementID) {
187
+ this.startCounter();
188
+ }
189
+ this.showWarning();
190
+ nextPing = this.expireAfter - idleFor;
191
+ } else {
192
+ this.hideWarning();
193
+ if (this.counterStarted && this.counterElementID) {
194
+ this.stopCounter();
195
+ }
196
+ nextPing = this.warnAfter - idleFor;
197
+ }
198
+
199
+ let milliseconds = Math.min(nextPing * 1000, 2147483647);
200
+ let self = this;
201
+ this.timeout = setTimeout(function () {
202
+ self.ping();
203
+ }, milliseconds);
204
+ };
205
+
206
+ SessionSecurity.prototype.startCounter = function () {
207
+ if (!this.counterElementID) {
208
+ return;
209
+ }
210
+ let element = globalDocument.getElementById(this.counterElementID);
211
+ if (!element) {
212
+ return;
213
+ }
214
+ let expireAfter = this.expireAfter;
215
+ let warnAfter = this.warnAfter;
216
+ let defaultTimeLeft = expireAfter - warnAfter;
217
+
218
+ if (!this.counterStarted) {
219
+ element.textContent = defaultTimeLeft.toString();
220
+ this.counterStarted = true;
221
+ }
222
+
223
+ let endTime = new Date();
224
+ endTime.setSeconds(endTime.getSeconds() + defaultTimeLeft);
225
+ this.counterTimeout = setInterval(function () {
226
+ let now = new Date().getTime();
227
+ let distance = endTime - now;
228
+ let seconds = Math.max(0, Math.floor((distance % (1000 * expireAfter)) / 1000));
229
+ if (distance > 0) {
230
+ element.textContent = seconds.toString();
231
+ }
232
+ }, 1000);
233
+ };
234
+
235
+ SessionSecurity.prototype.stopCounter = function () {
236
+ if (!this.counterElementID) {
237
+ return;
238
+ }
239
+ let element = globalDocument.getElementById(this.counterElementID);
240
+ if (!element) {
241
+ return;
242
+ }
243
+ clearInterval(this.counterTimeout);
244
+ this.counterStarted = false;
245
+ let defaultTimeLeft = this.expireAfter - this.warnAfter;
246
+ element.textContent = defaultTimeLeft.toString();
247
+ };
248
+
249
+ SessionSecurity.prototype.onbeforeunload = function (event) {
250
+ if (this.expired || !this.confirmFormDiscard) {
251
+ return undefined;
252
+ }
253
+ if (hasDirtyForms()) {
254
+ event.preventDefault();
255
+ event.returnValue = this.confirmFormDiscard;
256
+ return this.confirmFormDiscard;
257
+ }
258
+ return undefined;
259
+ };
260
+
261
+ SessionSecurity.prototype.formChange = function (event) {
262
+ if (!event.target || typeof event.target.closest !== "function") {
263
+ return;
264
+ }
265
+ let form = event.target.closest("form");
266
+ if (form) {
267
+ form.setAttribute("data-dirty", "true");
268
+ }
269
+ };
270
+
271
+ SessionSecurity.prototype.formClean = function (event) {
272
+ if (!event.target || typeof event.target.closest !== "function") {
273
+ return;
274
+ }
275
+ let form = event.target.closest("form");
276
+ if (form) {
277
+ form.removeAttribute("data-dirty");
278
+ }
279
+ };
280
+
281
+ globalWindow.yourlabs.SessionSecurity = SessionSecurity;
282
+ })(window, document);
@@ -0,0 +1,30 @@
1
+ /* credit: http://www.csslab.cl/2008/01/30/ventana-modal-solo-con-css/ */
2
+ .session_security_overlay {
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ width: 100%;
7
+ height: 100%;
8
+ background: #000;
9
+ z-index: 1001;
10
+ opacity: 0.75;
11
+ -moz-opacity: 0.75;
12
+ filter: alpha(opacity=75);
13
+ }
14
+
15
+ .session_security_modal {
16
+ position: fixed;
17
+ top: 25%;
18
+ left: 25%;
19
+ width: 50%;
20
+ padding: 16px;
21
+ background: #fff;
22
+ color: #333;
23
+ z-index: 1002;
24
+ overflow: auto;
25
+ text-align: center;
26
+ }
27
+
28
+ .session_security {
29
+ display: none;
30
+ }
@@ -0,0 +1,42 @@
1
+ {% comment %}
2
+ This demonstrates how to setup session security client side stuff on your own.
3
+ It provides sensible defaults so you could start with just::
4
+
5
+ {% include 'session_security/all.html' %}
6
+
7
+ {% endcomment %}
8
+
9
+ {% load session_security_tags %}
10
+ {% load i18n l10n %}
11
+ {% load static %}
12
+
13
+ {# If the user is not authenticated then there is no session to secure ! #}
14
+ {% if request.user.is_authenticated %}
15
+
16
+ {# The modal dialog stylesheet, it's pretty light so it should be easy to hack #}
17
+ <link rel="stylesheet" type="text/css" href="{% static 'session_security/style.css' %}">
18
+
19
+ {# Include the template that actually contains the modal dialog #}
20
+ {% include 'session_security/dialog.html' %}
21
+
22
+ {% session_security_script_path as session_security_js %}
23
+ {# Load SessionSecurity javascript 'class' #}
24
+ <script type="text/javascript" src="{% static session_security_js %}"></script>
25
+
26
+ {# Bootstrap a SessionSecurity instance as the sessionSecurity global variable #}
27
+ {% localize off %}
28
+ <script type="text/javascript"{% if request.csp_nonce %} nonce="{{ request.csp_nonce }}"{% endif %}>
29
+ var sessionSecurity = new yourlabs.SessionSecurity({
30
+ pingUrl: '{% url 'session_security_ping' %}',
31
+ warnAfter: {{ request|warn_after|unlocalize }},
32
+ expireAfter: {{ request|expire_after|unlocalize }},
33
+ {% with redirect_to_logout=request|redirect_to_logout %}
34
+ {% if redirect_to_logout %}
35
+ returnToUrl: {% url 'logout' %},
36
+ {% endif %}
37
+ {% endwith %}
38
+ confirmFormDiscard: "{% trans 'You have unsaved changes in a form of this page.' %}"
39
+ });
40
+ </script>
41
+ {% endlocalize %}
42
+ {% endif %}
@@ -0,0 +1,9 @@
1
+ {% load i18n %}
2
+
3
+ <div id="session_security_warning" class="session_security" aria-hidden="true" role="dialog">
4
+ <div class="session_security_overlay"></div>
5
+ <div class="session_security_modal" role="document" tabindex="-1">
6
+ <h3>{% trans 'Your session is about to expire' %}: <span id="session_security_counter"></span> {% trans 'seconds' %}</h3></h3>
7
+ <p>{% trans 'Click or type to extend your session.' %}</p>
8
+ </div>
9
+ </div>
@@ -16,8 +16,10 @@ from selenium.webdriver.common.by import By
16
16
  class ActivityWindow:
17
17
  min_warn_after: float
18
18
  max_warn_after: float
19
+ warn_timeout: float
19
20
  min_expire_after: float
20
21
  max_expire_after: float
22
+ expire_timeout: float
21
23
 
22
24
 
23
25
  @pytest.fixture
@@ -45,11 +47,14 @@ def authenticated_client(client, admin_user):
45
47
 
46
48
 
47
49
  TIMEOUT_PADDING_ENV = "SESSION_SECURITY_TIMEOUT_PADDING"
50
+ CI_TIMEOUT_PADDING_DEFAULT = 2.0
48
51
 
49
52
 
50
53
  def _timeout_padding_seconds() -> float:
51
54
  raw_value = os.environ.get(TIMEOUT_PADDING_ENV)
52
- if not raw_value:
55
+ if raw_value is None:
56
+ return CI_TIMEOUT_PADDING_DEFAULT if os.environ.get("CI") else 0.0
57
+ if raw_value == "":
53
58
  return 0.0
54
59
  try:
55
60
  padding = float(raw_value)
@@ -67,12 +72,16 @@ def activity_window(settings):
67
72
  padding = _timeout_padding_seconds()
68
73
  warn_margin = 0.5 # always keep at least this much headroom before expiry
69
74
  max_warn_cap = max(warn_after, expire_after - warn_margin)
70
- max_warn_after = min(expire_after * 0.9 + padding, max_warn_cap)
75
+ max_warn_after = max_warn_cap
76
+ warn_timeout = max_warn_after + padding
77
+ max_expire_after = expire_after * 1.5
71
78
  return ActivityWindow(
72
79
  min_warn_after=warn_after,
73
80
  max_warn_after=max_warn_after,
81
+ warn_timeout=warn_timeout,
74
82
  min_expire_after=expire_after,
75
- max_expire_after=expire_after * 1.5 + padding,
83
+ max_expire_after=max_expire_after,
84
+ expire_timeout=max_expire_after + padding,
76
85
  )
77
86
 
78
87
 
@@ -0,0 +1,15 @@
1
+ import pytest
2
+ from django.template.loader import get_template
3
+
4
+
5
+ @pytest.mark.parametrize(
6
+ "template_name",
7
+ [
8
+ "session_security/all.html",
9
+ "session_security/dialog.html",
10
+ ],
11
+ )
12
+ def test_templates_are_discoverable(template_name):
13
+ """Ensure Django can load templates shipped with the package."""
14
+ template = get_template(template_name)
15
+ assert template is not None
@@ -25,28 +25,28 @@ def test_warning_shows_and_session_expires(selenium_browser, activity_window):
25
25
  start = datetime.datetime.now()
26
26
 
27
27
  for _ in _iterate_windows(selenium_browser):
28
- warning = WebDriverWait(selenium_browser, activity_window.max_warn_after).until(
28
+ warning = WebDriverWait(selenium_browser, activity_window.warn_timeout).until(
29
29
  expected_conditions.visibility_of_element_located((By.ID, "session_security_warning"))
30
30
  )
31
31
  assert warning.is_displayed()
32
32
 
33
- delta = datetime.datetime.now() - start
34
- assert delta.seconds >= activity_window.min_warn_after
35
- assert delta.seconds <= activity_window.max_warn_after
33
+ delta = (datetime.datetime.now() - start).total_seconds()
34
+ assert delta >= activity_window.min_warn_after
35
+ assert delta <= activity_window.max_warn_after
36
36
 
37
37
  for _ in _iterate_windows(selenium_browser):
38
- password_field = WebDriverWait(selenium_browser, activity_window.max_expire_after).until(
38
+ password_field = WebDriverWait(selenium_browser, activity_window.expire_timeout).until(
39
39
  expected_conditions.visibility_of_element_located((By.ID, "id_password"))
40
40
  )
41
41
  assert password_field.is_displayed()
42
- delta = datetime.datetime.now() - start
43
- assert delta.seconds >= activity_window.min_expire_after
44
- assert delta.seconds <= activity_window.max_expire_after
42
+ delta = (datetime.datetime.now() - start).total_seconds()
43
+ assert delta >= activity_window.min_expire_after
44
+ assert delta <= activity_window.max_expire_after
45
45
 
46
46
 
47
47
  def test_activity_hides_warning(selenium_browser, activity_window):
48
48
  time.sleep(activity_window.min_warn_after * 0.7)
49
- WebDriverWait(selenium_browser, activity_window.max_warn_after).until(
49
+ WebDriverWait(selenium_browser, activity_window.warn_timeout).until(
50
50
  expected_conditions.visibility_of_element_located((By.ID, "session_security_warning"))
51
51
  )
52
52
 
@@ -65,7 +65,7 @@ def test_activity_prevents_warning(selenium_browser, activity_window):
65
65
  _press_space(selenium_browser)
66
66
  start = datetime.datetime.now()
67
67
 
68
- warning = WebDriverWait(selenium_browser, activity_window.max_warn_after).until(
68
+ warning = WebDriverWait(selenium_browser, activity_window.warn_timeout).until(
69
69
  expected_conditions.visibility_of_element_located((By.ID, "session_security_warning"))
70
70
  )
71
71
  assert warning.is_displayed()
@@ -1,25 +0,0 @@
1
- django_session_security_continued-3.0.0a1.dist-info/licenses/LICENSE,sha256=sTEwnChiEDBXv8ZDFVYDAhXfIA1wjpwuIhTVDhGLssw,1107
2
- session_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- session_security/middleware.py,sha256=matyK1lCSv5ZeIRWoxj-yThKNDMHRUM1Xf929pWTVmE,4008
4
- session_security/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- session_security/settings.py,sha256=pIxklXg3F1uyvsb0dl7ArQ0vquWLCie0CC5vy_fICas,2242
6
- session_security/urls.py,sha256=QK_diUsqjyQkU6UQpUW9SV_3kpf0223glrtnM7jft7M,510
7
- session_security/utils.py,sha256=d19NpP7f5kEdrVdZIae95c-Oeuw9gk0m4pATzuzlw3w,466
8
- session_security/views.py,sha256=ktla3T5Pk8qajdVTIhatWKprm10iIjM-Ek495APDBLs,879
9
- session_security/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- session_security/templatetags/session_security_tags.py,sha256=Vhrxe0ThWpEbQZUlqxKl9XXOx8HhF96EoBmVk5hxhrc,627
11
- session_security/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- session_security/tests/conftest.py,sha256=MFGSYiQ_9ViCKgr0BL0x9cB4eJR29m1XjMkoY1J6SeE,4756
13
- session_security/tests/test_base.py,sha256=bvqz385wyyBQNhrpeTyUTY0fWosLB9wOhPOBrt0tOBM,1775
14
- session_security/tests/test_middleware.py,sha256=iLFlXXfoBwUBNUJPhyRvPR657y-MORj1nyjh3GXFNPc,3612
15
- session_security/tests/test_script.py,sha256=y-gNGt6vLgsjfvqIk7GsuS5RijoSVo50kzKpKkUXcJs,2707
16
- session_security/tests/test_templates.py,sha256=qXukArdCZvvthGLyHZzise9xV6Q8kFx-eUy8TCxsYXU,471
17
- session_security/tests/test_views.py,sha256=97Ssf4nXGj0OIGc-fFf3_LdjC3k9yFMr6QD9CRsTrLc,1183
18
- session_security/tests/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- session_security/tests/project/settings.py,sha256=BAN820rroRvYMKQPtTYvqkdjmy9ce5fznFWelrBG58c,2999
20
- session_security/tests/project/urls.py,sha256=wFMGt1wQLCdoaAsJRltFypR473RJnkxbqReWh0FMFWE,1136
21
- session_security/tests/project/wsgi.py,sha256=VFz8yKLbSm4-C5ejuLJ_ZuPoKZ1WP17WJVMx2R17Z8M,426
22
- django_session_security_continued-3.0.0a1.dist-info/METADATA,sha256=jSCRkYxzDg-MpeqLKPxe23zGuccNJg4oBE1LUZsr5Kg,8935
23
- django_session_security_continued-3.0.0a1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- django_session_security_continued-3.0.0a1.dist-info/top_level.txt,sha256=sUgnA1DNG4V434n9luYoNsltkfMgkCnI6GBZV6oKWJI,17
25
- django_session_security_continued-3.0.0a1.dist-info/RECORD,,