Coder Social home page Coder Social logo

mkalioby / django-mfa2 Goto Github PK

View Code? Open in Web Editor NEW
282.0 282.0 41.0 5.34 MB

A Django app that handles MFA, it supports TOTP, U2F, FIDO2 U2F (Webauthn), Email Token and Trusted Devices

License: MIT License

Python 39.94% HTML 45.00% JavaScript 15.07%
conda django django-packages django-web fido2 mfa python security totp webauthn

django-mfa2's Introduction

Hi there ๐Ÿ‘‹

A little about me

  • ๐Ÿ”ญ Iโ€™m currently working as the lead for software development team at Center for Genomic Medicine, King Faisal Specialist Hospital & Research Center
  • ๐Ÿ“œ I'm a CPHIMS, CKAD and MCP. I've Masters in Software Engineering and Bioinformatics.
  • I was a member of Content Comittee of djangoCon Europe 2022 in Porto.
  • I'm main contributor for django-mfa2 (which has more than 200 ๐ŸŒŸ and downloaded more than 175k times) and django-passkeys which provides easy-to-integrate passkey interface for django authentication which is stared 100 times in 6 months
  • Python Software Foundation Contributing Member.
  • Speaker at DjangoCon US 2023.
  • Django Software Foundation Member.
  • DjangoCon US 2024 Community Reviewer.
  • ๐Ÿ’ฌ Ask me about Python, Django and Linux in general
  • ๐Ÿ“ซ How to reach me: [email protected]

Connect with me:

mahmoodnasr mahmood-nasr

Languages and Tools:

aws bootstrap chartjs css3 django docker flask heroku html5 javascript kubernetes mysql postman python rabbitMQ selenium sqlite

ย mkalioby

GitHub Streak

django-mfa2's People

Contributors

andreasdickow avatar camposmoreira avatar mahmoodnasr avatar mkalioby avatar pacrim avatar swainn avatar unramk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-mfa2's Issues

Add section on how to setup local dev enviroment

Hi there.

Thanks for making this package.

I love yubikeys so much I am building a business around them.
I am currently working on building a closed network that only allows FIDO2 logins to get rid of passwords altogether. Django didn't like it when I tried to build a user model without passwords. So instead, I have randomly created ones that will never get used. I can do this because I provide yubikeys to all my customers/users free of charge, set up the whole account, and for out-of-network users will have Anonymous accounts that get sent an email to create a login session.

I am still struggling with adding the package but what this is really about is that it would be nice if there were a section in the readme on how to set up the local dev environment to use https

You mention

Note: U2F and FIDO2 can only be served under secure context (https)

in the readme.

That is good to know but without mentioning how to do it or adding a link to how to set it up locally, working on this is rather difficult. It is not feasible for me to test in production. So I have been reading up on it but was not successful so far in setting it up.

Do you happen to know where I can find this kind of information?

mfa_auth_base.html not being used

I created the file mfa_auth_based.html in my root template directory, but it's not getting used.
I looked at mfa.views.index and, sure enough, it's using the template MFA.html, which extends base.html.

Where does mfa_auth_base.html come into play?

Should the documentation and example instead say to use MFA.html?

Thoughts on removing Javascript requirements?

Understandably, some of the MFA methods rely on Javascript, however for those users not interested in relying on Javascript, we should still be able to support methods like TOTP, email, etc without requiring Javascript.

Would you be open to having fallbacks?

django-mfa2 using TOTP fails in Django 3.2

When I try to sign in with a user with a TOTP already registered after entering the TOTP code using Django 3.2, I get the following exception:

TypeError at /mfa/totp/auth

string indices must be integers

Django Version: 3.2
Exception Type: TypeError
Request Method: POST
Exception Location: /app/lib/python3.9/site-packages/mfa/totp.py, line 18, in verify_login

And using django shell

In [1]: from mfa.models import User_Keys

In [2]: username='Username'

In [3]: key = User_Keys.objects.filter(username=username,key_type = "TOTP").first()

In [4]: key.properties
Out[4]: '{"secret_key": "CLMMOLJHBKJNLAXIBTSQUSCPFUEO42GW"}'

In [5]: key.properties["secret_key"]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [5], line 1
----> 1 key.properties["secret_key"]

TypeError: string indices must be integers

Using Django 3.1 the same code everything works fine:

In [1]: from mfa.models import User_Keys

In [2]: username='Username'

In [3]: key = User_Keys.objects.filter(username=username,key_type = "TOTP").first()

In [4]: key.properties["secret_key"]
Out[4]: 'CLMMOLJHBKJNLAXIBTSQUSCPFUEO42GW'

In [5]: key.properties
Out[5]: {'secret_key': 'CLMMOLJHBKJNLAXIBTSQUSCPFUEO42GW'}

ValueError: Invalid format string

Hello, I noticed a small problem:
strftime format should beuppercase "S" instead of lowercase "s" since this gives me Pyhton error "ValueError: Invalid format string"
I think line 45 of file totp.py should be modified like this:

Ist:
seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%s"))
Soll:
seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%S"))

Failure on U2F verify

ERROR 2020-06-13 19:08:23,133 228 log Internal Server Error: /mfa/u2f/verify
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedFunction: function json_extract(text, unknown) does not exist
LINE 1: ..."owned_by_enterprise" FROM "mfa_user_keys" WHERE (JSON_EXTRA...
                                                             ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/mfa/U2F.py", line 107, in verify
    x= validate(request,request.session["base_username"])
  File "/usr/local/lib/python3.6/site-packages/mfa/U2F.py", line 55, in validate
    key=User_Keys.objects.get(username=username,properties__shas="$.device.publicKey=%s"%device["publicKey"])
  File "/usr/local/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 411, in get
    num = len(clone)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 258, in __len__
    self._fetch_all()
  File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 1261, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 57, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1152, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: function json_extract(text, unknown) does not exist
LINE 1: ..."owned_by_enterprise" FROM "mfa_user_keys" WHERE (JSON_EXTRA...
                                                             ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

I tried tracking this down, but I am not sure whats the best step. Its this line But I am not sure what about that queryset is failing here exactly. Would it be possible to write this queryset without using this import? Looking up the module it appears to be a MySQL module,

https://pypi.org/project/jsonLookup/

Can this be done database agnostic? (assuming that is the problem)

FIDO2.complete_reg returns wrong status_code == 200 in exception handling

Please stick to HTTP convention and change status codes when you catch exceptions. When I was using your code in my wrappers to apply JWT auth into it, I found in negative test with wrong payload I cannot pass the line below 'cause it was always status_code == 200
assert response = client.post(url, wrong_payload, format='json') assert response.status_code == HTTP_400_BAD_REQUEST

As an example, code from mfa/FIDO2.py line 89.

return JsonResponse({'status': 'ERR', "message": "Error on server, please try again later"})
is using default status_code = 200 from base class HttpResponseBase .

expected code:
return JsonResponse({'status': 'ERR', "message": "Error on server, please try again later"}, status=status.HTTP_400_BAD_REQUEST)
The same goes for mfa/FIDO2.py line 55.

Is JWT tokens authorization handling possible?

Hey,

I'd like to use webauthn(Fido2) in my app as mfa (second step). App consists of django BE and will consist of FE app (vue probably). That's why we decided to use JWT tokens authorization. Is it possible with this lib? I see everywhere in Readme and code the session based authentication method.
I'm using rest_framework_simplejwt.authentication.JWTAuthentication as DEFAULT_AUTHENTICATION_CLASSES. I tried starting Fido2 device registartion by mfa/fido2/begin_reg endpoint by it looks it's not authenticating user by Bearer token and user is seen in the endpoint as AnonymousUser. In other endpoints the user is properly authenticated by JWT access token
image

Migration Error After Upgrading to django-mfa2 2.0.0

Encountered the error after upgrading to 2.0.0 and running database migrations on a fresh database:

Applying mfa.0009_user_keys_owned_by_enterprise...Traceback (most recent call last):
  File "/home/nswain/miniconda/envs/tethys-dev/lib/python3.7/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
psycopg2.errors.DatatypeMismatch: column "owned_by_enterprise" is of type boolean but expression is of type integer
LINE 1: update mfa_user_keys set owned_by_enterprise = 0 where key_t...
                                                       ^
HINT:  You will need to rewrite or cast the expression.

Looks like an issue with migration 0009_user_keys_owned_by_enterprise.py.

no permission checks on views

I noticed that I can access /mfa/ as the anonymous user, and the code gets very confused very quickly. Should have some sort of check that rejects requests by anonymous users.

Issue with FIDO2 dependency

I've run into this issue with the django-mfa2 package today (see error below). Looks like the FIDO2 package released some breaking changes. I'd advise to either update django-mfa2 with these changes or pin the FIDO2 dependency.

Traceback (most recent call last):
  File "/Users/runner/work/tethys/tethys/tethys_portal/manage.py", line 20, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/base.py", line 89, in wrapped
    res = handle_func(*args, **kwargs)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/commands/migrate.py", line 75, in handle
    self.check(databases=[database])
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/management/base.py", line 419, in check
    all_issues = checks.run_checks(
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/checks/registry.py", line 76, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/checks/urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/core/checks/urls.py", line 23, in check_resolver
    return check_method()
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/urls/resolvers.py", line 416, in check
    for pattern in self.url_patterns:
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/urls/resolvers.py", line 602, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/django/urls/resolvers.py", line 595, in urlconf_module
    return import_module(self.urlconf_name)
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/Users/runner/work/tethys/tethys/tethys_portal/urls.py", line 20, in <module>
    from tethys_portal.views import accounts as tethys_portal_accounts, \
  File "/Users/runner/work/tethys/tethys/tethys_portal/views/accounts.py", line 15, in <module>
    from mfa.helpers import has_mfa
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/mfa/helpers.py", line 3, in <module>
    from . import TrustedDevice, U2F, FIDO2, totp
  File "/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/mfa/FIDO2.py", line 1, in <module>
    from fido2.client import ClientData
ImportError: cannot import name 'ClientData' from 'fido2.client' (/Users/runner/miniconda/envs/tethys/lib/python3.10/site-packages/fido2/client.py)

Use pylint to ensure code quality - 5 errors were detected

Pylint is a linter for python, there are several plugins for different frameworks and use cases such as the pylint-django plugin.
Using pylint with pylint-django plugin I got the following result:

install it with:

(venv) $ pip3 install pylint pylint-django
(venv) $ pylint --load-plugins=pylint_django --django-settings-module=mfa --errors-only mfa

************* Module mfa.FIDO2
mfa/FIDO2.py:80:12: E0401: Unable to import 'raven.contrib.django.raven_compat.models' (import-error)
mfa/FIDO2.py:143:16: E0401: Unable to import 'raven.contrib.django.raven_compat.models' (import-error)
mfa/FIDO2.py:180:74: E1101: Instance of 'Exception' has no 'message' member (no-member)
************* Module mfa.middleware
mfa/middleware.py:3:0: E0401: Unable to import 'django.core.urlresolvers' (import-error)
mfa/middleware.py:3:0: E0611: No name 'urlresolvers' in module 'django.core' (no-name-in-module)

And the full output...

(venv) $ pylint --load-plugins=pylint_django --django-settings-module=mfa  mfa
************* Module mfa
mfa/__init__.py:1:0: C0114: Missing module docstring (missing-module-docstring)
************* Module mfa.totp
mfa/totp.py:32:0: C0301: Line too long (101/100) (line-too-long)
mfa/totp.py:34:0: C0301: Line too long (102/100) (line-too-long)
mfa/totp.py:50:0: C0301: Line too long (109/100) (line-too-long)
mfa/totp.py:62:0: C0301: Line too long (162/100) (line-too-long)
mfa/totp.py:75:0: C0301: Line too long (120/100) (line-too-long)
mfa/totp.py:76:0: C0301: Line too long (141/100) (line-too-long)
mfa/totp.py:78:0: C0301: Line too long (114/100) (line-too-long)
mfa/totp.py:88:0: C0301: Line too long (110/100) (line-too-long)
mfa/totp.py:89:0: C0301: Line too long (102/100) (line-too-long)
mfa/totp.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/totp.py:5:0: W0401: Wildcard import models (wildcard-import)
mfa/totp.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/totp.py:25:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/totp.py:29:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/totp.py:30:12: C0415: Import outside toplevel (time) (import-outside-toplevel)
mfa/totp.py:32:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/totp.py:34:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/totp.py:38:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/totp.py:41:8: C0103: Variable name "tokenLength" doesn't conform to snake_case naming style (invalid-name)
mfa/totp.py:58:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/totp.py:58:0: C0103: Function name "getToken" doesn't conform to snake_case naming style (invalid-name)
mfa/totp.py:64:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/totp.py:75:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/totp.py:6:0: C0411: third party import "from django.template.context_processors import csrf" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/totp.py:7:0: C0411: third party import "import simplejson" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/totp.py:8:0: C0411: third party import "from django.conf import settings" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/totp.py:9:0: C0411: third party import "import pyotp" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/totp.py:11:0: C0411: standard import "import datetime" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/totp.py:12:0: C0411: third party import "from django.utils import timezone" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/totp.py:13:0: C0411: standard import "import random" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/totp.py:8:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/totp.py:12:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/totp.py:5:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.FIDO2
mfa/FIDO2.py:53:0: C0301: Line too long (109/100) (line-too-long)
mfa/FIDO2.py:71:0: C0301: Line too long (164/100) (line-too-long)
mfa/FIDO2.py:72:0: C0301: Line too long (133/100) (line-too-long)
mfa/FIDO2.py:91:0: C0301: Line too long (108/100) (line-too-long)
mfa/FIDO2.py:92:0: C0301: Line too long (105/100) (line-too-long)
mfa/FIDO2.py:139:0: C0301: Line too long (143/100) (line-too-long)
mfa/FIDO2.py:160:0: C0301: Line too long (118/100) (line-too-long)
mfa/FIDO2.py:165:0: C0301: Line too long (118/100) (line-too-long)
mfa/FIDO2.py:166:0: C0301: Line too long (107/100) (line-too-long)
mfa/FIDO2.py:175:0: C0301: Line too long (108/100) (line-too-long)
mfa/FIDO2.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/FIDO2.py:1:0: C0103: Module name "FIDO2" doesn't conform to snake_case naming style (invalid-name)
mfa/FIDO2.py:12:0: W0401: Wildcard import models (wildcard-import)
mfa/FIDO2.py:29:0: C0103: Function name "getServer" doesn't conform to snake_case naming style (invalid-name)
mfa/FIDO2.py:39:8: W1406: The u prefix for strings is no longer necessary in Python >=3.0 (redundant-u-string-prefix)
mfa/FIDO2.py:40:8: W1406: The u prefix for strings is no longer necessary in Python >=3.0 (redundant-u-string-prefix)
mfa/FIDO2.py:41:8: W1406: The u prefix for strings is no longer necessary in Python >=3.0 (redundant-u-string-prefix)
mfa/FIDO2.py:76:11: W0718: Catching too general exception Exception (broad-exception-caught)
mfa/FIDO2.py:71:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/FIDO2.py:77:8: C0415: Import outside toplevel (traceback) (import-outside-toplevel)
mfa/FIDO2.py:82:8: W0702: No exception type(s) specified (bare-except)
mfa/FIDO2.py:80:12: E0401: Unable to import 'raven.contrib.django.raven_compat.models' (import-error)
mfa/FIDO2.py:80:12: C0415: Import outside toplevel (raven.contrib.django.raven_compat.models.client) (import-outside-toplevel)
mfa/FIDO2.py:76:4: W0612: Unused variable 'exp' (unused-variable)
mfa/FIDO2.py:96:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/FIDO2.py:96:0: C0103: Function name "getUserCredentials" doesn't conform to snake_case naming style (invalid-name)
mfa/FIDO2.py:103:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/FIDO2.py:108:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/FIDO2.py:117:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/FIDO2.py:117:0: R0914: Too many local variables (20/15) (too-many-locals)
mfa/FIDO2.py:179:11: W0718: Catching too general exception Exception (broad-exception-caught)
mfa/FIDO2.py:141:15: W0718: Catching too general exception Exception (broad-exception-caught)
mfa/FIDO2.py:138:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:145:12: W0702: No exception type(s) specified (bare-except)
mfa/FIDO2.py:143:16: E0401: Unable to import 'raven.contrib.django.raven_compat.models' (import-error)
mfa/FIDO2.py:143:16: C0415: Import outside toplevel (raven.contrib.django.raven_compat.models.client) (import-outside-toplevel)
mfa/FIDO2.py:147:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:151:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/FIDO2.py:152:12: C0415: Import outside toplevel (time) (import-outside-toplevel)
mfa/FIDO2.py:154:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:157:12: C0415: Import outside toplevel (random) (import-outside-toplevel)
mfa/FIDO2.py:170:20: W0702: No exception type(s) specified (bare-except)
mfa/FIDO2.py:174:50: C0321: More than one statement on a single line (multiple-statements)
mfa/FIDO2.py:175:31: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:177:27: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:180:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/FIDO2.py:180:74: E1101: Instance of 'Exception' has no 'message' member (no-member)
mfa/FIDO2.py:117:0: R0911: Too many return statements (7/6) (too-many-return-statements)
mfa/FIDO2.py:117:0: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
mfa/FIDO2.py:13:0: C0411: third party import "from fido2.utils import websafe_decode, websafe_encode" should be placed before "from .models import *" (wrong-import-order)
mfa/FIDO2.py:14:0: C0411: third party import "from fido2.webauthn import AttestedCredentialData" should be placed before "from .models import *" (wrong-import-order)
mfa/FIDO2.py:16:0: C0411: standard import "import datetime" should be placed before "from fido2.client import Fido2Client" (wrong-import-order)
mfa/FIDO2.py:18:0: C0411: third party import "from django.utils import timezone" should be placed before "from .models import *" (wrong-import-order)
mfa/FIDO2.py:19:0: C0411: third party import "from django.http import JsonResponse" should be placed before "from .models import *" (wrong-import-order)
mfa/FIDO2.py:9:0: C0412: Imports from package fido2 are not grouped (ungrouped-imports)
mfa/FIDO2.py:10:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/FIDO2.py:13:0: C0412: Imports from package fido2 are not grouped (ungrouped-imports)
mfa/FIDO2.py:18:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/FIDO2.py:1:0: W0611: Unused Fido2Client imported from fido2.client (unused-import)
mfa/FIDO2.py:12:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.recovery
mfa/recovery.py:22:0: C0301: Line too long (102/100) (line-too-long)
mfa/recovery.py:28:0: C0301: Line too long (116/100) (line-too-long)
mfa/recovery.py:39:0: W0311: Bad indentation. Found 12 spaces, expected 8 (bad-indentation)
mfa/recovery.py:40:0: W0311: Bad indentation. Found 12 spaces, expected 8 (bad-indentation)
mfa/recovery.py:41:0: W0311: Bad indentation. Found 12 spaces, expected 8 (bad-indentation)
mfa/recovery.py:42:0: W0311: Bad indentation. Found 12 spaces, expected 8 (bad-indentation)
mfa/recovery.py:81:0: C0301: Line too long (101/100) (line-too-long)
mfa/recovery.py:83:0: C0301: Line too long (102/100) (line-too-long)
mfa/recovery.py:94:0: C0301: Line too long (109/100) (line-too-long)
mfa/recovery.py:96:0: C0301: Line too long (107/100) (line-too-long)
mfa/recovery.py:100:0: C0301: Line too long (111/100) (line-too-long)
mfa/recovery.py:103:0: C0301: Line too long (115/100) (line-too-long)
mfa/recovery.py:105:72: C0303: Trailing whitespace (trailing-whitespace)
mfa/recovery.py:122:0: C0304: Final newline missing (missing-final-newline)
mfa/recovery.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/recovery.py:7:0: W0401: Wildcard import models (wildcard-import)
mfa/recovery.py:16:0: C0115: Missing class docstring (missing-class-docstring)
mfa/recovery.py:20:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:20:0: C0103: Function name "delTokens" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:27:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:27:0: C0103: Function name "randomGen" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:31:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:31:0: C0103: Function name "genTokens" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:36:4: C0103: Variable name "hashedKeys" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:37:4: C0103: Variable name "clearKeys" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:40:12: C0103: Variable name "hashedToken" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:38:8: W0612: Unused variable 'i' (unused-variable)
mfa/recovery.py:53:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:57:8: C0103: Variable name "hashedToken" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:58:14: R1704: Redefining argument with the local name 'token' (redefined-argument-from-local)
mfa/recovery.py:67:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:67:0: C0103: Function name "getTokenLeft" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:69:4: C0103: Variable name "keyLeft" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:71:8: C0103: Variable name "keyLeft" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:74:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:78:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/recovery.py:79:12: C0415: Import outside toplevel (time) (import-outside-toplevel)
mfa/recovery.py:81:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/recovery.py:83:19: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/recovery.py:87:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/recovery.py:88:4: C0415: Import outside toplevel (views.login) (import-outside-toplevel)
mfa/recovery.py:91:8: C0103: Variable name "tokenLength" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:94:12: C0103: Variable name "resBackup" doesn't conform to snake_case naming style (invalid-name)
mfa/recovery.py:8:0: C0411: third party import "import simplejson" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/recovery.py:9:0: C0411: standard import "import random" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/recovery.py:10:0: C0411: standard import "import string" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/recovery.py:11:0: C0411: standard import "import datetime" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/recovery.py:12:0: C0411: third party import "from django.utils import timezone" should be placed before "from .Common import get_redirect_url" (wrong-import-order)
mfa/recovery.py:12:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/recovery.py:11:0: W0611: Unused import datetime (unused-import)
mfa/recovery.py:7:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.models
mfa/models.py:8:0: C0301: Line too long (116/100) (line-too-long)
mfa/models.py:29:0: C0301: Line too long (133/100) (line-too-long)
mfa/models.py:30:0: C0301: Line too long (131/100) (line-too-long)
mfa/models.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/models.py:8:8: W0707: Consider explicitly re-raising using 'except ModuleNotFoundError as exc' and 'raise ModuleNotFoundError("Can't find a JSONField implementation, please install jsonfield if django < 4.0") from exc' (raise-missing-from)
mfa/models.py:17:0: C0115: Missing class docstring (missing-class-docstring)
mfa/models.py:17:0: C0103: Class name "User_Keys" doesn't conform to PascalCase naming style (invalid-name)
mfa/models.py:17:0: W5102: Found __unicode__ method on model (User_Keys). Python3 uses __str__. (model-has-unicode)
mfa/models.py:30:8: R1725: Consider using Python 3 style super() without arguments (super-with-arguments)
mfa/models.py:33:15: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/models.py:11:0: C0412: Imports from package django are not grouped (ungrouped-imports)
************* Module mfa.ApproveLogin
mfa/ApproveLogin.py:1:0: C0103: Module name "ApproveLogin" doesn't conform to snake_case naming style (invalid-name)
************* Module mfa.apps
mfa/apps.py:4:0: C0304: Final newline missing (missing-final-newline)
mfa/apps.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/apps.py:2:0: C0115: Missing class docstring (missing-class-docstring)
mfa/apps.py:2:0: C0103: Class name "myAppNameConfig" doesn't conform to PascalCase naming style (invalid-name)
************* Module mfa.TrustedDevice
mfa/TrustedDevice.py:67:0: C0301: Line too long (120/100) (line-too-long)
mfa/TrustedDevice.py:90:0: C0301: Line too long (102/100) (line-too-long)
mfa/TrustedDevice.py:102:0: C0301: Line too long (122/100) (line-too-long)
mfa/TrustedDevice.py:129:0: C0301: Line too long (134/100) (line-too-long)
mfa/TrustedDevice.py:133:0: C0301: Line too long (102/100) (line-too-long)
mfa/TrustedDevice.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/TrustedDevice.py:1:0: C0103: Module name "TrustedDevice" doesn't conform to snake_case naming style (invalid-name)
mfa/TrustedDevice.py:7:0: W0401: Wildcard import models (wildcard-import)
mfa/TrustedDevice.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:14:4: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/TrustedDevice.py:14:58: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/TrustedDevice.py:14:85: C0321: More than one statement on a single line (multiple-statements)
mfa/TrustedDevice.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:17:0: C0103: Function name "getUserAgent" doesn't conform to snake_case naming style (invalid-name)
mfa/TrustedDevice.py:18:4: W0622: Redefining built-in 'id' (redefined-builtin)
mfa/TrustedDevice.py:27:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:34:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:34:0: C0103: Function name "checkTrusted" doesn't conform to snake_case naming style (invalid-name)
mfa/TrustedDevice.py:36:4: W0622: Redefining built-in 'id' (redefined-builtin)
mfa/TrustedDevice.py:41:8: W0702: No exception type(s) specified (bare-except)
mfa/TrustedDevice.py:40:53: C0321: More than one statement on a single line (multiple-statements)
mfa/TrustedDevice.py:45:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:45:0: C0103: Function name "getCookie" doesn't conform to snake_case naming style (invalid-name)
mfa/TrustedDevice.py:51:8: C0415: Import outside toplevel (datetime.datetime, datetime.timedelta) (import-outside-toplevel)
mfa/TrustedDevice.py:45:0: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
mfa/TrustedDevice.py:58:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:60:4: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/TrustedDevice.py:67:102: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/TrustedDevice.py:68:8: W0612: Unused variable 'cookie' (unused-variable)
mfa/TrustedDevice.py:89:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:103:4: W0702: No exception type(s) specified (bare-except)
mfa/TrustedDevice.py:101:11: C0121: Comparison 'td == None' should be 'td is None' (singleton-comparison)
mfa/TrustedDevice.py:101:21: C0321: More than one statement on a single line (multiple-statements)
mfa/TrustedDevice.py:108:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:110:4: C0415: Import outside toplevel (Common.send) (import-outside-toplevel)
mfa/TrustedDevice.py:123:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/TrustedDevice.py:125:8: W0621: Redefining name 'jwt' from outer scope (line 7) (redefined-outer-name)
mfa/TrustedDevice.py:125:8: C0415: Import outside toplevel (jose.jwt) (import-outside-toplevel)
mfa/TrustedDevice.py:135:12: W0702: No exception type(s) specified (bare-except)
mfa/TrustedDevice.py:129:108: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/TrustedDevice.py:136:16: C0415: Import outside toplevel (traceback) (import-outside-toplevel)
mfa/TrustedDevice.py:8:0: C0411: third party import "import user_agents" should be placed before "from .models import *" (wrong-import-order)
mfa/TrustedDevice.py:9:0: C0411: third party import "from django.utils import timezone" should be placed before "from .models import *" (wrong-import-order)
mfa/TrustedDevice.py:10:0: C0411: third party import "from django.urls import reverse" should be placed before "from .models import *" (wrong-import-order)
mfa/TrustedDevice.py:9:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/TrustedDevice.py:5:0: W0611: Unused RequestContext imported from django.template.context (unused-import)
mfa/TrustedDevice.py:7:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.admin
mfa/admin.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/admin.py:1:0: W0611: Unused admin imported from django.contrib (unused-import)
************* Module mfa.Common
mfa/Common.py:18:0: C0301: Line too long (103/100) (line-too-long)
mfa/Common.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/Common.py:1:0: C0103: Module name "Common" doesn't conform to snake_case naming style (invalid-name)
mfa/Common.py:5:0: W0702: No exception type(s) specified (bare-except)
mfa/Common.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/Common.py:12:4: C0103: Variable name "From" doesn't conform to snake_case naming style (invalid-name)
mfa/Common.py:12:11: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/Common.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
************* Module mfa.Email
mfa/Email.py:37:0: C0301: Line too long (104/100) (line-too-long)
mfa/Email.py:40:0: C0301: Line too long (120/100) (line-too-long)
mfa/Email.py:42:0: C0301: Line too long (116/100) (line-too-long)
mfa/Email.py:59:0: C0301: Line too long (109/100) (line-too-long)
mfa/Email.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/Email.py:1:0: C0103: Module name "Email" doesn't conform to snake_case naming style (invalid-name)
mfa/Email.py:4:0: C0410: Multiple imports on one line (datetime, random) (multiple-imports)
mfa/Email.py:6:0: W0401: Wildcard import models (wildcard-import)
mfa/Email.py:11:0: C0103: Function name "sendEmail" doesn't conform to snake_case naming style (invalid-name)
mfa/Email.py:13:4: C0415: Import outside toplevel (django.contrib.auth.get_user_model) (import-outside-toplevel)
mfa/Email.py:14:4: C0103: Variable name "User" doesn't conform to snake_case naming style (invalid-name)
mfa/Email.py:32:12: C0415: Import outside toplevel (django.http.HttpResponseRedirect) (import-outside-toplevel)
mfa/Email.py:35:12: W0702: No exception type(s) specified (bare-except)
mfa/Email.py:34:16: C0415: Import outside toplevel (django.core.urlresolvers.reverse) (import-outside-toplevel)
mfa/Email.py:36:16: C0415: Import outside toplevel (django.urls.reverse) (import-outside-toplevel)
mfa/Email.py:63:12: C0415: Import outside toplevel (django.utils.timezone) (import-outside-toplevel)
mfa/Email.py:4:0: C0411: standard import "import datetime, random" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/Email.py:4:0: C0411: standard import "import datetime, random" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/Email.py:5:0: C0411: standard import "from random import randint" should be placed before "from django.shortcuts import render" (wrong-import-order)
mfa/Email.py:6:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.U2F
mfa/U2F.py:56:0: C0301: Line too long (114/100) (line-too-long)
mfa/U2F.py:63:0: C0301: Line too long (101/100) (line-too-long)
mfa/U2F.py:76:0: C0301: Line too long (114/100) (line-too-long)
mfa/U2F.py:85:0: C0301: Line too long (114/100) (line-too-long)
mfa/U2F.py:86:0: C0301: Line too long (110/100) (line-too-long)
mfa/U2F.py:107:0: C0301: Line too long (116/100) (line-too-long)
mfa/U2F.py:108:0: C0301: Line too long (137/100) (line-too-long)
mfa/U2F.py:110:0: C0301: Line too long (127/100) (line-too-long)
mfa/U2F.py:115:0: C0301: Line too long (108/100) (line-too-long)
mfa/U2F.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/U2F.py:1:0: C0103: Module name "U2F" doesn't conform to snake_case naming style (invalid-name)
mfa/U2F.py:13:0: W0401: Wildcard import models (wildcard-import)
mfa/U2F.py:19:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:28:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:30:7: C0121: Comparison 'x == True' should be 'x is True' if checking for the singleton value True, or 'x' if testing for truthiness (singleton-comparison)
mfa/U2F.py:31:8: C0415: Import outside toplevel (time) (import-outside-toplevel)
mfa/U2F.py:33:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/U2F.py:36:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:38:35: C0321: More than one statement on a single line (multiple-statements)
mfa/U2F.py:44:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:45:4: W0621: Redefining name 'datetime' from outer scope (line 16) (redefined-outer-name)
mfa/U2F.py:45:4: W0404: Reimport 'datetime' (imported line 16) (reimported)
mfa/U2F.py:45:4: C0415: Import outside toplevel (datetime, random) (import-outside-toplevel)
mfa/U2F.py:45:4: C0410: Multiple imports on one line (datetime, random) (multiple-imports)
mfa/U2F.py:50:7: C0121: Comparison 'res != True' should be 'res is not True' if checking for the singleton value True, or 'not res' if testing for falsiness (singleton-comparison)
mfa/U2F.py:66:4: W0702: No exception type(s) specified (bare-except)
mfa/U2F.py:56:74: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
mfa/U2F.py:54:12: W0612: Unused variable 'c' (unused-variable)
mfa/U2F.py:54:15: W0612: Unused variable 't' (unused-variable)
mfa/U2F.py:71:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:79:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:90:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:91:4: C0415: Import outside toplevel (hashlib) (import-outside-toplevel)
mfa/U2F.py:114:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:119:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/U2F.py:121:4: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/U2F.py:121:7: C0121: Comparison 'x == True' should be 'x is True' if checking for the singleton value True, or 'x' if testing for truthiness (singleton-comparison)
mfa/U2F.py:16:0: C0411: standard import "import datetime" should be placed before "from u2flib_server.u2f import begin_registration, begin_authentication, complete_registration, complete_authentication" (wrong-import-order)
mfa/U2F.py:17:0: C0411: third party import "from django.utils import timezone" should be placed before "from .models import *" (wrong-import-order)
mfa/U2F.py:10:0: C0412: Imports from package django are not grouped (ungrouped-imports)
mfa/U2F.py:16:0: W0611: Unused import datetime (unused-import)
mfa/U2F.py:13:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.urls
mfa/urls.py:7:0: W0311: Bad indentation. Found 5 spaces, expected 4 (bad-indentation)
mfa/urls.py:56:0: C0304: Final newline missing (missing-final-newline)
mfa/urls.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/urls.py:6:0: W0702: No exception type(s) specified (bare-except)
************* Module mfa.helpers
mfa/helpers.py:23:0: C0301: Line too long (116/100) (line-too-long)
mfa/helpers.py:25:0: C0301: Line too long (118/100) (line-too-long)
mfa/helpers.py:27:0: C0301: Line too long (120/100) (line-too-long)
mfa/helpers.py:29:0: C0301: Line too long (119/100) (line-too-long)
mfa/helpers.py:32:0: C0305: Trailing newlines (trailing-newlines)
mfa/helpers.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/helpers.py:2:0: W0401: Wildcard import models (wildcard-import)
mfa/helpers.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/helpers.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/helpers.py:12:0: W0102: Dangerous default value [] as argument (dangerous-default-value)
mfa/helpers.py:18:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/helpers.py:21:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/helpers.py:22:4: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
mfa/helpers.py:23:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/helpers.py:25:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/helpers.py:27:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/helpers.py:29:15: R5102: Instead of HttpResponse(content_type='application/json') use JsonResponse() (http-response-with-content-type-json)
mfa/helpers.py:18:0: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
mfa/helpers.py:4:0: C0411: third party import "import simplejson" should be placed before "from .models import *" (wrong-import-order)
mfa/helpers.py:5:0: C0411: third party import "from django.shortcuts import HttpResponse" should be placed before "from .models import *" (wrong-import-order)
mfa/helpers.py:6:0: C0411: first party import "from mfa.views import verify, goto" should be placed before "from .models import *" (wrong-import-order)
mfa/helpers.py:1:0: W0611: Unused import pyotp (unused-import)
mfa/helpers.py:6:0: W0611: Unused goto imported from mfa.views (unused-import)
mfa/helpers.py:2:0: W0614: Unused import(s) models, JSONField, jwt and settings from wildcard import of models (unused-wildcard-import)
************* Module mfa.middleware
mfa/middleware.py:12:0: C0301: Line too long (117/100) (line-too-long)
mfa/middleware.py:13:0: C0304: Final newline missing (missing-final-newline)
mfa/middleware.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/middleware.py:3:0: E0401: Unable to import 'django.core.urlresolvers' (import-error)
mfa/middleware.py:3:0: E0611: No name 'urlresolvers' in module 'django.core' (no-name-in-module)
mfa/middleware.py:5:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/middleware.py:7:23: C0321: More than one statement on a single line (multiple-statements)
mfa/middleware.py:12:60: C0209: Formatting a regular string which could be an f-string (consider-using-f-string)
************* Module mfa.views
mfa/views.py:20:0: C0301: Line too long (134/100) (line-too-long)
mfa/views.py:21:0: C0301: Line too long (128/100) (line-too-long)
mfa/views.py:56:0: C0301: Line too long (113/100) (line-too-long)
mfa/views.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/views.py:5:0: W0401: Wildcard import models (wildcard-import)
mfa/views.py:8:0: W0702: No exception type(s) specified (bare-except)
mfa/views.py:18:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:35:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:39:17: R1718: Consider using a set comprehension (consider-using-set-comprehension)
mfa/views.py:55:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:58:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:63:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:65:4: W0621: Redefining name 'settings' from outer scope (line 5) (redefined-outer-name)
mfa/views.py:64:4: C0415: Import outside toplevel (django.contrib.auth) (import-outside-toplevel)
mfa/views.py:65:4: W0404: Reimport 'settings' (imported line 12) (reimported)
mfa/views.py:65:4: C0415: Import outside toplevel (django.conf.settings) (import-outside-toplevel)
mfa/views.py:64:4: W0611: Unused auth imported from django.contrib (unused-import)
mfa/views.py:71:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:71:0: C0103: Function name "delKey" doesn't conform to snake_case naming style (invalid-name)
mfa/views.py:73:4: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/views.py:80:4: W0621: Redefining name 'importlib' from outer scope (line 1) (redefined-outer-name)
mfa/views.py:80:4: W0404: Reimport 'importlib' (imported line 1) (reimported)
mfa/views.py:80:4: C0415: Import outside toplevel (importlib) (import-outside-toplevel)
mfa/views.py:82:8: W0719: Raising too general exception: Exception (broad-exception-raised)
mfa/views.py:89:8: W0719: Raising too general exception: Exception (broad-exception-raised)
mfa/views.py:93:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:93:0: C0103: Function name "toggleKey" doesn't conform to snake_case naming style (invalid-name)
mfa/views.py:94:4: W0622: Redefining built-in 'id' (redefined-builtin)
mfa/views.py:98:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
mfa/views.py:107:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/views.py:10:0: C0411: third party import "from django.template.context_processors import csrf" should be placed before "from .models import *" (wrong-import-order)
mfa/views.py:11:0: C0411: third party import "from django.template.context import RequestContext" should be placed before "from .models import *" (wrong-import-order)
mfa/views.py:12:0: C0411: third party import "from django.conf import settings" should be placed before "from .models import *" (wrong-import-order)
mfa/views.py:14:0: C0411: third party import "from django.contrib.auth.decorators import login_required" should be placed before "from .models import *" (wrong-import-order)
mfa/views.py:15:0: C0411: third party import "from user_agents import parse" should be placed before "from .models import *" (wrong-import-order)
mfa/views.py:1:0: W0611: Unused import importlib (unused-import)
mfa/views.py:10:0: W0611: Unused csrf imported from django.template.context_processors (unused-import)
mfa/views.py:11:0: W0611: Unused RequestContext imported from django.template.context (unused-import)
mfa/views.py:5:0: W0614: Unused import(s) models, JSONField and jwt from wildcard import of models (unused-wildcard-import)
************* Module mfa.migrations.0010_auto_20201110_0557
mfa/migrations/0010_auto_20201110_0557.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0010_auto_20201110_0557.py:1:0: C0103: Module name "0010_auto_20201110_0557" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0010_auto_20201110_0557.py:6:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0006_trusted_devices
mfa/migrations/0006_trusted_devices.py:17:0: C0301: Line too long (114/100) (line-too-long)
mfa/migrations/0006_trusted_devices.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0006_trusted_devices.py:1:0: C0103: Module name "0006_trusted_devices" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0006_trusted_devices.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0005_auto_20181115_2014
mfa/migrations/0005_auto_20181115_2014.py:11:0: C0301: Line too long (108/100) (line-too-long)
mfa/migrations/0005_auto_20181115_2014.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0005_auto_20181115_2014.py:1:0: C0103: Module name "0005_auto_20181115_2014" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0005_auto_20181115_2014.py:11:8: W0707: Consider explicitly re-raising using 'except ImportError as exc' and 'raise ImportError("Can't find a JSONField implementation, please install jsonfield if django < 4.0") from exc' (raise-missing-from)
mfa/migrations/0005_auto_20181115_2014.py:15:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/migrations/0005_auto_20181115_2014.py:16:4: C0415: Import outside toplevel (django.conf.settings) (import-outside-toplevel)
mfa/migrations/0005_auto_20181115_2014.py:15:16: W0613: Unused argument 'apps' (unused-argument)
mfa/migrations/0005_auto_20181115_2014.py:15:22: W0613: Unused argument 'schema_editor' (unused-argument)
mfa/migrations/0005_auto_20181115_2014.py:21:0: C0115: Missing class docstring (missing-class-docstring)
mfa/migrations/0005_auto_20181115_2014.py:4:0: W0611: Unused models imported from django.db (unused-import)
************* Module mfa.migrations.0002_user_keys_key_type
mfa/migrations/0002_user_keys_key_type.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0002_user_keys_key_type.py:1:0: C0103: Module name "0002_user_keys_key_type" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0002_user_keys_key_type.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0011_auto_20210530_0622
mfa/migrations/0011_auto_20210530_0622.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0011_auto_20210530_0622.py:1:0: C0103: Module name "0011_auto_20210530_0622" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0011_auto_20210530_0622.py:6:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0007_auto_20181230_1549
mfa/migrations/0007_auto_20181230_1549.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0007_auto_20181230_1549.py:1:0: C0103: Module name "0007_auto_20181230_1549" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0007_auto_20181230_1549.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0008_user_keys_last_used
mfa/migrations/0008_user_keys_last_used.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0008_user_keys_last_used.py:1:0: C0103: Module name "0008_user_keys_last_used" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0008_user_keys_last_used.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0004_user_keys_enabled
mfa/migrations/0004_user_keys_enabled.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0004_user_keys_enabled.py:1:0: C0103: Module name "0004_user_keys_enabled" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0004_user_keys_enabled.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0009_user_keys_owned_by_enterprise
mfa/migrations/0009_user_keys_owned_by_enterprise.py:10:0: C0301: Line too long (124/100) (line-too-long)
mfa/migrations/0009_user_keys_owned_by_enterprise.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0009_user_keys_owned_by_enterprise.py:1:0: C0103: Module name "0009_user_keys_owned_by_enterprise" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0009_user_keys_owned_by_enterprise.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
mfa/migrations/0009_user_keys_owned_by_enterprise.py:8:37: W0613: Unused argument 'schema_editor' (unused-argument)
mfa/migrations/0009_user_keys_owned_by_enterprise.py:13:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0003_auto_20181114_2159
mfa/migrations/0003_auto_20181114_2159.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0003_auto_20181114_2159.py:1:0: C0103: Module name "0003_auto_20181114_2159" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0003_auto_20181114_2159.py:7:0: C0115: Missing class docstring (missing-class-docstring)
************* Module mfa.migrations.0001_initial
mfa/migrations/0001_initial.py:16:0: C0301: Line too long (114/100) (line-too-long)
mfa/migrations/0001_initial.py:1:0: C0114: Missing module docstring (missing-module-docstring)
mfa/migrations/0001_initial.py:1:0: C0103: Module name "0001_initial" doesn't conform to snake_case naming style (invalid-name)
mfa/migrations/0001_initial.py:7:0: C0115: Missing class docstring (missing-class-docstring)
mfa/migrations/0001_initial.py:1:0: R0801: Similar lines in 2 files
==mfa.U2F:[59:64]
==mfa.totp:[46:51]
        if getattr(settings, "MFA_RECHECK", False):
            mfa["next_check"] = datetime.datetime.timestamp((datetime.datetime.now()
                                     + datetime.timedelta(
                        seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))))
        request.session["mfa"] = mfa (duplicate-code)

------------------------------------------------------------------
Your code has been rated at 4.89/10 (previous run: 4.89/10, +0.00)

NameError in mfa/models.py

Tests for my project started failing with version 2.0.5 of django-mfa2. Here's the traceback:

Traceback (most recent call last):
  File "/Users/travis/build/Aquaveo/tethys/tethys_portal/manage.py", line 20, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute
    django.setup()
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/django/apps/registry.py", line 114, in populate
    app_config.import_models()
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/django/apps/config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/travis/miniconda/envs/tethys/lib/python3.7/site-packages/mfa/models.py", line 7, in <module>
    JSONField.register_lookup(hasLookup)
NameError: name 'hasLookup' is not defined

Full Test output here: https://travis-ci.org/github/Aquaveo/tethys/jobs/748432868#L1647

I'm using a PostgreSQL database and django 2.2.14

Email OTP should have a period of validity

Hi,

I searched for this functionnality in the readme and by exploring the code and it seems that there is no concept of period of validity involved in the logic of mfa.Email.auth

Maybe this could be implemented using the request session only for email keys, or a more generic approach could be added directly using User_Keys.expires and a middleware.

In both case, this timeout should be configurable per OTP method and have sensible defaults.

Happy to discuss it further if you think it's worth it !

Missing Migration

I've recently updated to version 2.0.1 and I noticed that there was a migration that was not generated in my project. When I run manage.py makemigrations this is what it generates:

Migrations for 'mfa':
  ...\site-packages\mfa\migrations\0010_auto_20201106_1523.py
    - Alter field key_type on user_keys

Is django-mfa2 missing a migration?

Some bugs in FIDO2

Line 72 template FIDO/recheck.html

      }).then(function (response) {if (response.ok) return res = response.json()}).then(function (res) {
          if (res.status=="OK")
          {

'res is undefined'

My fix is to remove the extra 'then' and just not dump it as json,

      }).then(function (response) {
          if (response.statusText=="OK")

Later in the same template 'res is used again for the redirect,

          {%  if mode == "auth" %}
          window.location.href=res.redirect;
          {% elif mode == "recheck" %}

I never actually saw one in the object when I console logged it, and was able to hard code it for my use case, but this should also be checked.

I am happy to fix the above but it should be reviewed for context/intent and see if I am missing something.

Line 139 of FIDO2.py is a bool not a callable

138                     request.session["mfa"] = mfa
139                     if not request.user.is_authenticated():
140                         res=login(request)

should be

138                     request.session["mfa"] = mfa
139                     if not request.user.is_authenticated:
140                         res=login(request)

Please review and if these fixes are OK I can do a PR for them. I feel like I am forgetting one more...

New feature: Change success link and url

@Sirneij: I created new settings parameters to change the link when the keys are successfully registered, the names of parameters are

  • MFA_REDIRECT_AFTER_REGISTRATION which takes a view name.
  • MFA_SUCCESS_REGISTRATION_MSG which defines the message

please test using version 2.2.0b2 which can be downloaded by

pip install django-mfa2==2.2.0b2

Waiting to hear from you.

fixes from #5 not in pip

Howdy,

The fixes from #5 are not in pip. I can verify this by reading the tarball. Would it be possible to fix that? I can patch this for staging but would love to see it live for prod so all the automation is happy.

psycopg2.ProgrammingError: column "owned_by_enterprise" is of type boolean but expression is of type integer

migrations.RunSQL("update mfa_user_keys set owned_by_enterprise = %s where key_type='FIDO2'"%(1 if getattr(settings,"MFA_OWNED_BY_ENTERPRISE",False) else 0 ))

0 is not a valid boolean value on Postgresql:

Operations to perform:
  Apply all migrations: admin, auth, authtoken, bouncy_emails, contenttypes, db, django_cron, dynamicforms, er_admin, erws, erws_announcements, erws_datareporting, erws_notifications, erws_registration_bulkimport, erws_survey, generate_label, led_lamps, mfa, migs, news_article, registration, sessions
Running migrations:
  Applying mfa.0001_initial... OK
  Applying mfa.0002_user_keys_key_type... OK
  Applying mfa.0003_auto_20181114_2159... OK
  Applying mfa.0004_user_keys_enabled... OK
  Applying mfa.0005_auto_20181115_2014... OK
  Applying mfa.0006_trusted_devices... OK
  Applying mfa.0007_auto_20181230_1549... OK
  Applying mfa.0008_user_keys_last_used... OK
  Applying mfa.0009_user_keys_owned_by_enterprise...Traceback (most recent call last):
  File "/home/brian/.virtualenvs/energy_rating/lib/python3.6/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
psycopg2.ProgrammingError: column "owned_by_enterprise" is of type boolean but expression is of type integer
LINE 1: update mfa_user_keys set owned_by_enterprise = 0 where key_t...
                                                       ^
HINT:  You will need to rewrite or cast the expression.

Issues with toggleKey/ HIDE_DISABLE

Howdy again (not trying to be a pain I promise)

Found the following bug with toggleKey/HIDE_DISABLE

The logic in the MFA.html template for enabling the toggleKey java script function is 'if not HIDE_DISABLE',

    {% if not HIDE_DISABLE %}
    function toggleKey(id) {

If one uses the defaults in the example this will cause HIDE_DISABLE to be a tuple with FIDO2 within it, so it fails the 'if not' and does not allow toggleKey to render.

Since other types can be mixed this will disable them for all types.

Passwordless approach

Hi just came across this package after been fiddling with django-fido project, regarding the passwordless section in the README, it mentions about creating a cookie for the previously logged in username, I presume it's because we use that to know which user to perform the fido auth against?

Has anyone considered using combination of using resident_key for discoverable credential from the key and storing the user handle against the credential in the django database?

Reference
CZ-NIC/django-fido#137
CZ-NIC/django-fido#139
CZ-NIC/django-fido#142

Is it possible to log in without Bluetooth?

The lack of Bluetooth on devices can cause an authorization problem if webAuthn is the only authorization method. Is it possible to configure so that authorization does not require Bluetooth?

Can not register Biometric Authentication in Firefox

Hi!

I can't register a new Biometric Authentication in Firefox. Google Chrome and Safari are OK... Just Firefox. I have this error:

image

This problem exists for registration only, the login process is working.

MacOS 14.2.1
Firefox 121.0.1

Touch ID is in beta testing

Dear All,

I'm glad to announce the availability of Touch ID as a FIDO2 authenticator on both Mac OS X and iOS using Safari on both platforms.

The beta is on TouchID branch.

The trick that a button shall be clicked when the user registers and logins and can't be at a page ready event.

Password-less authentication with django-mfa2

I need a password-less system, registration should only require some special alphanumeric characters as username and surname as display name. Clicking register should bring up the platform's fingerprint scanner and touching it should send the hashed challenge as well as the username and display name to the database for storage. Then, users whose credentials have been saved can login with only their username and fingerprint. No password in the entire process. I have implemented this with DUO lab's webauthn but it supports fewer attestation formats and I need to support all attestation formats including tpm, android-safetynet, and apple.

Can I have a concrete example of django-mfa2 with this flow and requirement? No password in the entire process.

@mkalioby

This project contains deprecated code (Django 2.0 deprecated render_to_response)

Hi there,

Thanks for implementing this! However, in trying to get this working, we do face quite a few issues. First of all, the project contains deprecated code, namely calling the function render_to_response. See the Django docs, it has been deprecated in Django 2.0 and you state to support Django 2.1.
https://docs.djangoproject.com/en/2.2/topics/http/shortcuts/#render-to-response
Replacing the calls with render(request, template, optional context) works.

We are trying to get this working in Django 2.2, which might cause more problems, but this is the first big issue we faced.

Thanks in advance!

Regards,
Ellen

P.S. Is it possible to require either django-jsonfield or jsonfield? We are using django-jsonfield instead of jsonfield and using django-jsonfield for this app works fine. It would be nice to make django-jsonfield a possibility.

TrustedDevice fails because of JSONField

Captura de pantalla 2022-10-31 a las 19 59 07

Hello!

I am using jsonfield 3.1.0, Django 3.2.6 and Python 3.8. When trying to add a TrustedDevice (following the example code, already integrated into my application, I am getting this error.

Add a setting to control the number of generated recovery tokens (at the moment set to 5)

The function genTokens in recovery.py generates 5 tokens by default:

@never_cache
def genTokens(request):
    #Delete old ones
    delTokens(request)
    #Then generate new one
    salt = randomGen(15)
    hashedKeys = []
    clearKeys = []
    for i in range(5):
            token = randomGen(5) + "-" + randomGen(5)
            hashedToken = make_password(token, salt, 'pbkdf2_sha256_custom')
            hashedKeys.append(hashedToken)
            clearKeys.append(token)
    uk=User_Keys()

    uk.username = request.user.username
    uk.properties={"secret_keys":hashedKeys, "salt":salt}
    uk.key_type="RECOVERY"
    uk.enabled = True
    uk.save()
    return HttpResponse(simplejson.dumps({"keys":clearKeys}))

There is no way to change the number of generated tokens.
I am thinking of adding a settings variable to control the number of generated recovery tokens, called MFA_NUMBER_OF_RECOVERY_CODES... something like this:

@never_cache
def genTokens(request):
    #Delete old ones
    delTokens(request)
    #Then generate new one
    salt = randomGen(15)
    hashedKeys = []
    clearKeys = []
    n = MFA_NUMBER_OF_RECOVERY_CODES
    if n < 5 or n > 10:
        n = 5
    for i in range(n):
            token = randomGen(5) + "-" + randomGen(5)
            hashedToken = make_password(token, salt, 'pbkdf2_sha256_custom')
            hashedKeys.append(hashedToken)
            clearKeys.append(token)
    uk=User_Keys()

    uk.username = request.user.username
    uk.properties={"secret_keys":hashedKeys, "salt":salt}
    uk.key_type="RECOVERY"
    uk.enabled = True
    uk.save()
    return HttpResponse(simplejson.dumps({"keys":clearKeys}))

in recovery.py The number of hashing iterations defined by RECOVERY_ITERATION, should not default to 1 if RECOVERY_ITERATION is not defined in settings.py

in the class Hash in recovery.py you can see the following:

class Hash(PBKDF2PasswordHasher):
    algorithm = 'pbkdf2_sha256_custom'
    iterations = getattr(settings,"RECOVERY_ITERATION",1)

in the case RECOVERY_ITERATION was not defined in settings.py, the value for iterations will default to 1.

Although that the risk posed by an inadequate number of hashing iterations for the recovery tokens is maybe not the biggest concern in case of any leak to the User_keys table, and potentially other tables in the database. it is still a bad practice and I would advise against it, as it normalises the reuse of such code.

The current recommended value (by django) is 720000 iterations, while the default the package is suggesting is 350000.

Trusted device cannot be added

Hello,
when adding a trusted device, I get the following error:

ERROR:django.request:Internal Server Error: /mfa/td/add
uwsgi_1         | Traceback (most recent call last):
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
uwsgi_1         |     response = get_response(request)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
uwsgi_1         |     response = self.process_exception_by_middleware(e, request)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
uwsgi_1         |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/mfa/TrustedDevice.py", line 65, in add
uwsgi_1         |     trusted_keys=User_Keys.objects.filter(username=request.POST["username"],properties__has="$.key="+key)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
uwsgi_1         |     return getattr(self.get_queryset(), name)(*args, **kwargs)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 892, in filter
uwsgi_1         |     return self._filter_or_exclude(False, *args, **kwargs)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 910, in _filter_or_exclude
uwsgi_1         |     clone.query.add_q(Q(*args, **kwargs))
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1290, in add_q
uwsgi_1         |     clause, _ = self._add_q(q_object, self.used_aliases)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1318, in _add_q
uwsgi_1         |     split_subq=split_subq, simple_col=simple_col,
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1251, in build_filter
uwsgi_1         |     condition = self.build_lookup(lookups, col, value)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1110, in build_lookup
uwsgi_1         |     lhs = self.try_transform(lhs, lookup_name)
uwsgi_1         |   File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1151, in try_transform
uwsgi_1         |     "permitted%s" % (name, output_field.__name__, suggestion)
uwsgi_1         | django.core.exceptions.FieldError: Unsupported lookup 'has' for JSONField or join on the field not permitted, perhaps you meant shas?

Has anyone else this error?
I am running in Docker and integrated django-mfa2 into DefectDojo

Using user foreign key to settings.AUTH_USER_MODEL instead of "username" in User_Keys

Currently the User_Keys model in models.py, uses username=models.CharField(max_length = 50).

This could be problematic in case the django app allows for changing the username for example. Also deleting a user will not result in deleting entries for that user in the User_Keys model in the database.

The mainstream approach is to use:

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

The request in django view functions already have request.user variable that can be used directly when CRUD an entry in the User_Keys table.

Nonetheless, changing the data model will require a lot of refactoring.

"ValueError: Invalid format string" at Email.py

Hi there,

Thank you for making a great package.
I am doing MFA using Email.
"ValueError: Invalid format string" occurred when inputting OTP.

Occurrence is where "strftime ("% s ")" is described in Email auth.


Internal Server Error: /mfa/email/auth/
Traceback (most recent call last):
File "C:\work\15.DEV\Anaconda3\envs\env-base\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\work\15.DEV\Anaconda3\envs\env-base\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\work\15.DEV\Anaconda3\envs\env-base\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\work\15.DEV\Anaconda3\envs\env-base\lib\site-packages\mfa\Email.py", line 47, in auth
seconds = random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%s"))
ValueError: Invalid format string

%s > %S๏ผŸ

Help with integration with Allauth

Hi guys,

I'm not sure where would be the best place for communication, so here I am,
Anyway I'm currently trying to integrate django-mf2 with my current application.

In my current setup, I am currently using django-allauth for all my authentication need.
Im honestly stuck with one part, which is go passwordless,

image

I get the logic to implement the get logic in my allauth login page, that is done. My question is when do I set the cookies?

for some context here is my Loginview code for allauth and MFA2

from django.conf import settings
from django.shortcuts import render
from allauth.account.views import LoginView
from mfa.helpers import has_mfa
from allauth.exceptions import ImmediateHttpResponse
# Create your views here.


class MF2LoginView(LoginView):

    def get(self, request, *args, **kwargs):
        if getattr(settings, "MFA_QUICKLOGIN", False) and request.COOKIES.get('base_username'):
            username = request.COOKIES.get('base_username')
            res = has_mfa(username=username, request=request,)
            if res:
                return res
        return self.super().get(self, request, *args, **kwargs)

    def form_valid(self, form):
        success_url = self.get_success_url()
        res = has_mfa(self.request, username=form.user)
        if res:
            return res
        try:
            return form.login(self.request, redirect_url=success_url)
        except ImmediateHttpResponse as e:
            return e.response


MF2Login_View = MF2LoginView.as_view()

now that I think about it, what you need to do is to set the cookie once the user had been directed to my main page I guess?

Issue with 'collectstatic' in Django 4.2+ and django-mfa2 2.8.0

I encountered an issue when running python manage.py collectstatic in a Django project with the following configuration:

  • Django: 4.2.7
  • django-mfa2: 2.8.0
  • Staticfiles storage: "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"

Error Message:

ValueError: The file 'mfa/js/qrious.min.js.map' could not be found with <django.contrib.staticfiles.storage.ManifestStaticFilesStorage object at 0x7fa5f2e5e770>.

Context:
Upon investigation, it seems that the issue is related to changes introduced in Django 4.2, where ManifestStaticFilesStorage now replaces paths to JavaScript source map references with their hashed counterparts. The relevant changelog can be found here.

Observation:
The files mfa/static/mfa/js/bootstrap-toggle.min.js and mfa/static/mfa/js/qrious.min.js are referencing source map files as follows:

//# sourceMappingURL=bootstrap-toggle.min.js.map
//# sourceMappingURL=qrious.min.js.map

Proposal for Solution:
To resolve this issue, I propose adding the missing .map files. The required files can be found at the following locations:

By including these map files in the project, the collectstatic process should complete successfully.

Please let me know if you need any further information or clarification.

Add tests

I suggest adding tests with PyTest.

If you like the idea, and you approves I will volunteer to create the boilerplate and the first few tests.

AttributeError: 'UnicodeDecodeError' object has no attribute 'message'

In FIDO2.py there's wrong code raising exception in exception handling block
image

Current:
image

Expected:

return HttpResponse(
            simplejson.dumps({"status": "ERR", "message": str(exp)}),
            content_type="application/json",
            status=400
        )

Steps to reproduce:
call fido2_complete_auth endpoint with some random bytes encoded into payload before cbor.encode call

FIDO2

When I try to setup the FIDO2 security method I get the following error on Chrome

Registeration Failed as Error on server, please try again later, try again or Go to Security Home

I don't see any errors on the server. I am using Chrome 84.0.4147.105 and Mac OS 10.15.5.

Please could you let me know what I may be doing wrong. Thank you.

Regards,
Jugma

Commented out import in views.py

When I go to delete an object I see a 500 which complains that HttpResponse is missing. The imports show it was there and is now removed, why is that?

#from django.http import HttpResponse,HttpResponseRedirect
...
from django.http import HttpResponseRedirect

Changing which is commented out manually fixes this. Can it be fixed and pushed to pip?

QR Code not showing when trying to enable authenticator

When I goto /mfa and select the Authenticator App it returns the following

Screen Shot 2020-09-08 at 9 51 12 PM

When I click on 'phone/PC' or 'enter this text' I see a Javascript error in the networking which states this:
Uncaught ReferenceError: showKey is not defined at HTMLAnchorElement.onclick ((index):158) onclick | @ | (index):158

Any idea how to get the QR code to render? Also is there a way to disable the other MFA methods and only support the authenticator app?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.