diff --git a/mfa/Email.py b/mfa/Email.py
index 010d6d5..7bbb26d 100644
--- a/mfa/Email.py
+++ b/mfa/Email.py
@@ -7,6 +7,7 @@ from .models import *
#from django.template.context import RequestContext
from .views import login
from .Common import send
+from . import recovery
def sendEmail(request,username,secret):
"""Send Email to the user after rendering `mfa_email_token_template`"""
@@ -34,6 +35,7 @@ def start(request):
from django.core.urlresolvers import reverse
except:
from django.urls import reverse
+ recovery.genTokens(request, True) #recovery tokens
return HttpResponseRedirect(reverse(getattr(settings,'MFA_REDIRECT_AFTER_REGISTRATION','mfa_home')))
context["invalid"] = True
else:
diff --git a/mfa/FIDO2.py b/mfa/FIDO2.py
index dcdf9f2..e41c27c 100644
--- a/mfa/FIDO2.py
+++ b/mfa/FIDO2.py
@@ -16,6 +16,7 @@ from .views import login, reset_cookie
import datetime
from .Common import get_redirect_url
from django.utils import timezone
+from . import recovery
def recheck(request):
@@ -66,6 +67,7 @@ def complete_reg(request):
uk.owned_by_enterprise = getattr(settings, "MFA_OWNED_BY_ENTERPRISE", False)
uk.key_type = "FIDO2"
uk.save()
+ recovery.genTokens(request, True) #recovery tokens
return HttpResponse(simplejson.dumps({'status': 'OK'}))
except Exception as exp:
import traceback
diff --git a/mfa/TrustedDevice.py b/mfa/TrustedDevice.py
index 94b2136..aac4f6c 100644
--- a/mfa/TrustedDevice.py
+++ b/mfa/TrustedDevice.py
@@ -7,6 +7,7 @@ from django.template.context_processors import csrf
from .models import *
import user_agents
from django.utils import timezone
+from . import recovery
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
x=''.join(random.choice(chars) for _ in range(size))
@@ -75,6 +76,7 @@ def add(request):
tk.properties["user_agent"]=ua
tk.save()
context["success"]=True
+ recovery.genTokens(request, True) #recovery tokens
# tk.properties["user_agent"]=ua
# tk.save()
# context["success"]=True
diff --git a/mfa/U2F.py b/mfa/U2F.py
index 0eb04f0..18387d2 100644
--- a/mfa/U2F.py
+++ b/mfa/U2F.py
@@ -15,6 +15,7 @@ from .views import login
from .Common import get_redirect_url
import datetime
from django.utils import timezone
+from . import recovery
def recheck(request):
context = csrf(request)
@@ -98,6 +99,7 @@ def bind(request):
uk.properties = {"device":simplejson.loads(device.json),"cert":cert_hash}
uk.key_type = "U2F"
uk.save()
+ recovery.genTokens(request, True) #recovery tokens
return HttpResponse("OK")
def sign(username):
diff --git a/mfa/recovery.py b/mfa/recovery.py
new file mode 100644
index 0000000..6ddd09f
--- /dev/null
+++ b/mfa/recovery.py
@@ -0,0 +1,70 @@
+from django.shortcuts import render
+from django.views.decorators.cache import never_cache
+from django.http import HttpResponse
+from .Common import get_redirect_url
+from .models import *
+import simplejson
+from django.conf import settings
+import random
+import string
+import logging
+
+def invalidate_token(key):
+ key.enabled = 0
+ key.save()
+
+def token_left(request, username=None):
+ if not username:
+ username = request.user.username
+ return len(User_Keys.objects.filter(username=username, key_type="RECOVERY", enabled=True))
+
+def delTokens(request):
+ #Only when all MFA have been deactivated, or to generate new !
+ for key in User_Keys.objects.filter(username=request.user.username, key_type = "RECOVERY"):
+ if key.username == request.user.username:
+ key.delete()
+
+def newTokens(username):
+ for newkey in range(5):
+ token = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(6))
+ uk=User_Keys()
+ uk.username=username
+ uk.properties={"secret_key":token}
+ uk.key_type="RECOVERY"
+ uk.enabled=True
+ uk.save()
+
+def genTokens(request, softGen=False):
+ if not softGen or (softGen and token_left(request) == 0):
+ #Delete old ones
+ delTokens(request)
+ number = 5
+ #Then generate new one
+ newTokens(request.user.username)
+ return HttpResponse("Success")
+
+
+def verify_login(username,token):
+ for key in User_Keys.objects.filter(username=username, key_type = "RECOVERY"):
+ logging.critical(key.properties["secret_key"])
+ if key.properties["secret_key"] == token and key.enabled:
+ invalidate_token(key)
+ newRecoveryGen = False
+ if token_left(None, username) == 0:
+ newRecoveryGen = True
+ newTokens(username)
+ return [True, key.id, newRecoveryGen]
+ return [False]
+
+def getTokens(request):
+ tokens = []
+ enable = []
+ for key in User_Keys.objects.filter(username=request.user.username, key_type = "RECOVERY"):
+ tokens.append(key.properties["secret_key"])
+ enable.append(1 if key.enabled else 0)
+ return HttpResponse(simplejson.dumps({"keys":tokens, "enable":enable}))
+
+@never_cache
+def start(request):
+ """Start Managing recovery tokens"""
+ return render(request,"RECOVERY/Add.html",get_redirect_url())
\ No newline at end of file
diff --git a/mfa/templates/MFA.html b/mfa/templates/MFA.html
index 4940ad8..7a4d396 100644
--- a/mfa/templates/MFA.html
+++ b/mfa/templates/MFA.html
@@ -82,28 +82,40 @@
Status |
Delete |
- {% for key in keys %}
-
+ {% if keys %}
+ {% for key in keys %}
+
- | {{ key.key_type }} |
- {{ key.added_on }} |
- {{ key.expires }} |
- {% if key.device %}{{ key.device }}{% endif %} |
- {{ key.last_used }} |
- {% if key.key_type in HIDE_DISABLE %}
- {% if key.enabled %}On{% else %} Off{% endif %} |
- {% else %}
- |
- {% endif %}
- {% if key.key_type in HIDE_DISABLE %}
- ----
- {% else %}
- |
+ {{ key.key_type }} |
+ {{ key.added_on }} |
+ {{ key.expires }} |
+ {% if key.device %}{{ key.device }}{% endif %} |
+ {{ key.last_used }} |
+ {% if key.key_type in HIDE_DISABLE %}
+ {% if key.enabled %}On{% else %} Off{% endif %} |
+ {% else %}
+ |
{% endif %}
-
- {% empty %}
+ {% if key.key_type in HIDE_DISABLE %}
+ ----
+ {% else %}
+ |
+ {% endif %}
+
+ {% endfor %}
+
+
+ | RECOVERY |
+ |
+ |
+ |
+ |
+ On |
+ |
+
+ {% else %}
| You didn't have any keys yet. |
- {% endfor %}
+ {% endif %}
diff --git a/mfa/templates/RECOVERY/Add.html b/mfa/templates/RECOVERY/Add.html
new file mode 100644
index 0000000..09782a9
--- /dev/null
+++ b/mfa/templates/RECOVERY/Add.html
@@ -0,0 +1,88 @@
+
+{% extends "base.html" %}
+{% load static %}
+{% block head %}
+
+
+
+{% endblock %}
+{% block content %}
+
+
+
+
+
+
Token List
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% include "modal.html" %}
+{% endblock %}
diff --git a/mfa/templates/TOTP/recheck.html b/mfa/templates/TOTP/recheck.html
index e172b0e..84900da 100644
--- a/mfa/templates/TOTP/recheck.html
+++ b/mfa/templates/TOTP/recheck.html
@@ -40,7 +40,7 @@