Fixes and applied comments
This commit is contained in:
@@ -2,7 +2,7 @@ from django.shortcuts import render
|
|||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.template.context_processors import csrf
|
from django.template.context_processors import csrf
|
||||||
from django.contrib.auth.hashers import make_password, PBKDF2PasswordHasher
|
from django.contrib.auth.hashers import make_password, PBKDF2PasswordHasher
|
||||||
from django.http import HttpResponse,FileResponse,HttpResponseNotFound
|
from django.http import HttpResponse,HttpResponseNotFound
|
||||||
from .Common import get_redirect_url
|
from .Common import get_redirect_url
|
||||||
from .models import *
|
from .models import *
|
||||||
import simplejson
|
import simplejson
|
||||||
@@ -42,28 +42,25 @@ def genTokens(request):
|
|||||||
uk.username = request.user.username
|
uk.username = request.user.username
|
||||||
uk.properties={"secret_keys":hashedKeys, "salt":salt}
|
uk.properties={"secret_keys":hashedKeys, "salt":salt}
|
||||||
uk.key_type="RECOVERY"
|
uk.key_type="RECOVERY"
|
||||||
uk.enabled = False
|
uk.enabled = True
|
||||||
uk.save()
|
uk.save()
|
||||||
request.session["recovery_keys"]=clearKeys
|
|
||||||
return HttpResponse(simplejson.dumps({"keys":clearKeys}))
|
return HttpResponse(simplejson.dumps({"keys":clearKeys}))
|
||||||
|
|
||||||
def download_codes(request):
|
|
||||||
if not "recovery_keys" in request.session:
|
|
||||||
return HttpResponseNotFound("This page isn't valid anymore.")
|
|
||||||
response = HttpResponse('\n'.join(request.session["recovery_keys"]),content_type='text/text')
|
|
||||||
response['Content-Disposition'] = 'attachment; filename = Recovery Codes.txt'
|
|
||||||
return response
|
|
||||||
|
|
||||||
def verify_login(request, username,token):
|
def verify_login(request, username, token):
|
||||||
key = User_Keys.objects.filter(username=username, key_type = "RECOVERY")
|
for key in User_Keys.objects.filter(username=username, key_type = "RECOVERY"):
|
||||||
secret_keys = key.properties["secret_keys"]
|
secret_keys = key.properties["secret_keys"]
|
||||||
salt = key.properties["salt"]
|
salt = key.properties["salt"]
|
||||||
hashedToken = make_password(token, salt, "pbkdf2_sha256_custom")
|
hashedToken = make_password(token, salt, "pbkdf2_sha256_custom")
|
||||||
if hashedToken == secret_keys[0]:
|
for i in range(len(secret_keys)):
|
||||||
secret_keys.pop(0)
|
if hashedToken == secret_keys[i]:
|
||||||
key.properties["secret_keys"] = secret_keys
|
secret_keys.pop(i)
|
||||||
key.save()
|
key.properties["secret_keys"] = secret_keys
|
||||||
return [True, key.id, len(secret_keys) == 0]
|
key.save()
|
||||||
|
return [True, key.id, len(secret_keys) == 0]
|
||||||
|
if len(secret_keys) == 0:
|
||||||
|
#Show a message ?
|
||||||
|
return [False]
|
||||||
return [False]
|
return [False]
|
||||||
|
|
||||||
def getTokenLeft(request):
|
def getTokenLeft(request):
|
||||||
@@ -73,15 +70,27 @@ def getTokenLeft(request):
|
|||||||
keyLeft += len(key.properties["secret_keys"])
|
keyLeft += len(key.properties["secret_keys"])
|
||||||
return HttpResponse(simplejson.dumps({"left":keyLeft}))
|
return HttpResponse(simplejson.dumps({"left":keyLeft}))
|
||||||
|
|
||||||
|
def recheck(request):
|
||||||
|
context = csrf(request)
|
||||||
|
context["mode"]="recheck"
|
||||||
|
if request.method == "POST":
|
||||||
|
if verify_login(request,request.user.username, token=request.POST["recovery"])[0]:
|
||||||
|
import time
|
||||||
|
request.session["mfa"]["rechecked_at"] = time.time()
|
||||||
|
return HttpResponse(simplejson.dumps({"recheck": True}), content_type="application/json")
|
||||||
|
else:
|
||||||
|
return HttpResponse(simplejson.dumps({"recheck": False}), content_type="application/json")
|
||||||
|
return render(request,"RECOVERY/recheck.html", context)
|
||||||
|
|
||||||
@never_cache
|
@never_cache
|
||||||
def auth(request):
|
def auth(request):
|
||||||
from .views import login
|
from .views import login
|
||||||
context=csrf(request)
|
context=csrf(request)
|
||||||
if request.method=="POST":
|
if request.method=="POST":
|
||||||
tokenLength = len(request.POST["otp"])
|
tokenLength = len(request.POST["recovery"])
|
||||||
if tokenLength == 11 and "RECOVERY" not in settings.MFA_UNALLOWED_METHODS:
|
if tokenLength == 11 and "RECOVERY" not in settings.MFA_UNALLOWED_METHODS:
|
||||||
#Backup code check
|
#Backup code check
|
||||||
resBackup=verify_login(request, request.session["base_username"], token=request.POST["otp"])
|
resBackup=verify_login(request, request.session["base_username"], token=request.POST["recovery"])
|
||||||
if resBackup[0]:
|
if resBackup[0]:
|
||||||
mfa = {"verified": True, "method": "RECOVERY","id":resBackup[1], "lastBackup":resBackup[2]}
|
mfa = {"verified": True, "method": "RECOVERY","id":resBackup[1], "lastBackup":resBackup[2]}
|
||||||
if getattr(settings, "MFA_RECHECK", False):
|
if getattr(settings, "MFA_RECHECK", False):
|
||||||
@@ -92,15 +101,16 @@ def auth(request):
|
|||||||
if resBackup[2]:
|
if resBackup[2]:
|
||||||
#If the last bakup code has just been used, we return a response insead of redirecting to login
|
#If the last bakup code has just been used, we return a response insead of redirecting to login
|
||||||
context["lastBackup"] = True
|
context["lastBackup"] = True
|
||||||
return render(request,"TOTP/Auth.html", context)
|
return render(request,"RECOVERY/Auth.html", context)
|
||||||
return login(request)
|
return login(request)
|
||||||
|
context["invalid"]=True
|
||||||
|
|
||||||
elif request.method=="GET":
|
elif request.method=="GET":
|
||||||
mfa = request.session["mfa"]
|
mfa = request.session.get("mfa")
|
||||||
if mfa and mfa["verified"] and mfa["lastBackup"]:
|
if mfa and mfa["verified"] and mfa["lastBackup"]:
|
||||||
return login(request)
|
return login(request)
|
||||||
|
|
||||||
context["invalid"]=True
|
return render(request,"RECOVERY/Auth.html", context)
|
||||||
return render(request,"TOTP/Auth.html", context)
|
|
||||||
|
|
||||||
@never_cache
|
@never_cache
|
||||||
def start(request):
|
def start(request):
|
||||||
|
|||||||
@@ -60,10 +60,10 @@
|
|||||||
{% if not 'U2F' in UNALLOWED_AUTHEN_METHODS %}
|
{% if not 'U2F' in UNALLOWED_AUTHEN_METHODS %}
|
||||||
<li><a class="dropdown-item" href="{% url 'start_u2f' %}">Security Key</a></li>
|
<li><a class="dropdown-item" href="{% url 'start_u2f' %}">Security Key</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not 'FIDO2' in UNALLOWED_AUTHEN_METHODS %}
|
{% if not 'FIDO2' in UNALLOWED_AUTHEN_METHODS %}
|
||||||
<li><a class="dropdown-item" href="{% url 'start_fido2' %}">FIDO2 Security Key</a></li>
|
<li><a class="dropdown-item" href="{% url 'start_fido2' %}">FIDO2 Security Key</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not 'Trusted_Devices' in UNALLOWED_AUTHEN_METHODS %}
|
{% if not 'Trusted_Devices' in UNALLOWED_AUTHEN_METHODS %}
|
||||||
<li><a class="dropdown-item" href="{% url 'start_td' %}">Trusted Device</a></li>
|
<li><a class="dropdown-item" href="{% url 'start_td' %}">Trusted Device</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -21,46 +21,24 @@
|
|||||||
.tooltip {
|
.tooltip {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .tooltiptext {
|
|
||||||
visibility: hidden;
|
|
||||||
width: 140px;
|
|
||||||
background-color: #555;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 5px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
bottom: 150%;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -75px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .tooltiptext::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -5px;
|
|
||||||
border-width: 5px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: #555 transparent transparent transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip:hover .tooltiptext {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.return{
|
|
||||||
margin: 1px;
|
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.toolbtn {
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
.toolbtn:hover {
|
||||||
|
background-color: gray;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
.toolbtn:active {
|
||||||
|
background-color: green;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script src="{% static 'mfa/js/qrious.min.js' %}" type="text/javascript"></script>
|
<script src="{% static 'mfa/js/qrious.min.js' %}" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var clearCodes;
|
||||||
$(document).ready(function checkTokenLeft() {
|
$(document).ready(function checkTokenLeft() {
|
||||||
$.ajax({"url":"{% url 'get_recovery_token_left' %}", dataType:"JSON",
|
$.ajax({"url":"{% url 'get_recovery_token_left' %}", dataType:"JSON",
|
||||||
success:function (data) {
|
success:function (data) {
|
||||||
@@ -93,18 +71,35 @@
|
|||||||
<div class='row'><div class='offset-4 col-md-4' style='background-color:#f0f0f0;padding: 10px'>
|
<div class='row'><div class='offset-4 col-md-4' style='background-color:#f0f0f0;padding: 10px'>
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class="col-6 offset-6">
|
<div class="col-6 offset-6">
|
||||||
<span onclick='window.location.href="{% url 'download_recovery' %}"' class='fa fa-download' title="Download"
|
<span onclick='download_recovery()' class='fa fa-download toolbtn' title="Download"
|
||||||
style='cursor:pointer'></span>
|
style='cursor:pointer'></span>
|
||||||
<span class='fa fa-clipboard' title="Copy" onclick="copy()" style='cursor:pointer'></span>
|
<span class='fa fa-clipboard toolbtn' title="Copy" onclick="copy()" style='cursor:pointer'></span>
|
||||||
</div></div><div id='recovery_codes'><pre>`;
|
</div></div><div id='recovery_codes'><pre>`;
|
||||||
for (let i = 0; i < data.keys.length; i++) {
|
for (let i = 0; i < data.keys.length; i++) {
|
||||||
htmlkey +="- " +data.keys[i] + "\n"
|
htmlkey +="- " +data.keys[i] + "\n"
|
||||||
}
|
}
|
||||||
document.getElementById('tokens').innerHTML = htmlkey+"</pre></div></div></div>"
|
document.getElementById('tokens').innerHTML = htmlkey+"</pre></div></div></div>"
|
||||||
$("#popUpModal").modal('hide')
|
$("#popUpModal").modal('hide')
|
||||||
|
clearCodes = data.keys
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function download_recovery() {
|
||||||
|
var element = document.createElement('a');
|
||||||
|
var text = "";
|
||||||
|
for(let i = 0; i < clearCodes.length; i++)
|
||||||
|
{
|
||||||
|
text = text + clearCodes[i]
|
||||||
|
if (i < clearCodes.length - 1) { text = text + "\n"}
|
||||||
|
}
|
||||||
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||||
|
element.setAttribute('download', 'Recovery Codes.txt');
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
element.click();
|
||||||
|
console.log(element.innerHTML)
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,94 +1,14 @@
|
|||||||
<script type="application/javascript">
|
{% extends "mfa_auth_base.html" %}
|
||||||
$(document).ready(function showWarningLastBackup() {
|
{% block head %}
|
||||||
{% if lastBackup %}
|
<style>
|
||||||
$("#modal-title").html("Last backup code used !")
|
.row{
|
||||||
$("#modal-body").html("Don't forget to regenerate new backup code after login !")
|
margin-left: 15px;
|
||||||
$('#modal-footer').html(`<FORM METHOD="GET" ACTION="{% url 'recovery_auth' %}" Id="confirmLogin" onSubmit="" name="recoveryLastBackupConfirm">
|
|
||||||
<input type='submit'class='btn btn-lg btn-success btn-block' value='Continue'>`)
|
|
||||||
$("#popUpModal").modal('show')
|
|
||||||
{% endif %}
|
|
||||||
return
|
|
||||||
});
|
|
||||||
function send_totp() {
|
|
||||||
$.ajax({"url":"{% url 'totp_recheck' %}", method:"POST",dataType:"JSON",
|
|
||||||
data:{"csrfmiddlewaretoken":"{{ csrf_token }}","otp":$("#otp").val()},
|
|
||||||
success:function (data) {
|
|
||||||
if (data["recheck"])
|
|
||||||
mfa_success_function();
|
|
||||||
else {
|
|
||||||
mfa_failed_function();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
function tryToAuth() {
|
</style>
|
||||||
const otp_length = $("#otp").val().length
|
{% endblock %}
|
||||||
if (otp_length == 6) {
|
{% block content %}
|
||||||
document.getElementById("formLogin").submit();
|
<br/>
|
||||||
}
|
<br/>
|
||||||
else if (otp_length == 11) {
|
{% include "RECOVERY/recheck.html" with mode='auth' %}
|
||||||
const form = document.getElementById("formLogin");
|
|
||||||
form.setAttribute("ACTION", "{% url 'recovery_auth' %}")
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div class='container'>
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-sm-10 col-sm-offset-1 col-xs-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
{% endblock %}
|
||||||
<div class="panel panel-default card">
|
|
||||||
<div class="panel-heading card-header">
|
|
||||||
<strong>Recovery Code</strong>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body card-body">
|
|
||||||
|
|
||||||
<FORM METHOD="POST" ACTION="{% url 'recovery_auth' %}" Id="formLogin" onSubmit="" name="FrontPage_Form1">
|
|
||||||
|
|
||||||
|
|
||||||
{% csrf_token %}
|
|
||||||
{% if invalid %}
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
Sorry, The provided token is not valid.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<fieldset>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12">
|
|
||||||
<p>Enter enter your next recovery code</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12">
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group mb-3">
|
|
||||||
<span class="input-group-addon input-group-text">
|
|
||||||
<i class="glyphicon glyphicon-lock bi bi-lock"></i>
|
|
||||||
</span>
|
|
||||||
<input class="form-control" size="11" value="" placeholder="e.g npXiX-7dZgK" name="otp" type="text" id="otp" autofocus>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group d-grid gap-2">
|
|
||||||
|
|
||||||
<input type="button" onclick="{% if mode == "recheck" %} send_totp() {% else %} tryToAuth() {% endif %}" class="btn btn-lg btn-success btn-block" value="Sign in">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</FORM>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12 mb-3" style="padding-left: 25px">
|
|
||||||
{% if request.session.mfa_methods|length > 1 %}
|
|
||||||
<a href="{% url 'mfa_methods_list' %}">Select Another Method</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include "modal.html" %}
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
return
|
return
|
||||||
});
|
});
|
||||||
function send_totp() {
|
function send_recovery() {
|
||||||
$.ajax({"url":"{% url 'totp_recheck' %}", method:"POST",dataType:"JSON",
|
$.ajax({"url":"{% url 'recovery_recheck' %}", method:"POST",dataType:"JSON",
|
||||||
data:{"csrfmiddlewaretoken":"{{ csrf_token }}","otp":$("#otp").val()},
|
data:{"csrfmiddlewaretoken":"{{ csrf_token }}","recovery":$("#recovery").val()},
|
||||||
success:function (data) {
|
success:function (data) {
|
||||||
if (data["recheck"])
|
if (data["recheck"])
|
||||||
mfa_success_function();
|
mfa_success_function();
|
||||||
@@ -21,17 +21,6 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function tryToAuth() {
|
|
||||||
const otp_length = $("#otp").val().length
|
|
||||||
if (otp_length == 6) {
|
|
||||||
document.getElementById("formLogin").submit();
|
|
||||||
}
|
|
||||||
else if (otp_length == 11) {
|
|
||||||
const form = document.getElementById("formLogin");
|
|
||||||
form.setAttribute("ACTION", "{% url 'recovery_auth' %}")
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -39,17 +28,17 @@
|
|||||||
<div class="col-sm-10 col-sm-offset-1 col-xs-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
<div class="col-sm-10 col-sm-offset-1 col-xs-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
||||||
<div class="panel panel-default card">
|
<div class="panel panel-default card">
|
||||||
<div class="panel-heading card-header">
|
<div class="panel-heading card-header">
|
||||||
<strong> One Time Password</strong>
|
<strong> Recovery code</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body card-body">
|
<div class="panel-body card-body">
|
||||||
|
|
||||||
<FORM METHOD="POST" ACTION="{% url 'totp_auth' %}" Id="formLogin" onSubmit="" name="FrontPage_Form1">
|
<FORM METHOD="POST" ACTION="{% url 'recovery_auth' %}" Id="formLogin" onSubmit="" name="FrontPage_Form1">
|
||||||
|
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if invalid %}
|
{% if invalid %}
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
Sorry, The provided token is not valid.
|
Sorry, The provided code is not valid.
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if quota %}
|
{% if quota %}
|
||||||
@@ -60,7 +49,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-12">
|
<div class="col-sm-12 col-md-12">
|
||||||
<p>Enter the 6-digits on your authenticator. Or input a recovery code</p>
|
<p>Enter the 11-digits on your authenticator. Or input a recovery code</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -71,14 +60,14 @@
|
|||||||
<span class="input-group-addon input-group-text">
|
<span class="input-group-addon input-group-text">
|
||||||
<i class="glyphicon glyphicon-lock bi bi-lock"></i>
|
<i class="glyphicon glyphicon-lock bi bi-lock"></i>
|
||||||
</span>
|
</span>
|
||||||
<input class="form-control" size="6" MaxLength="11" value="" placeholder="e.g 55552" name="otp" type="text" id="otp" autofocus>
|
<input class="form-control" size="11" MaxLength="11" value="" placeholder="e.g abcde-fghij" name="recovery" type="text" id="recovery" autofocus>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group d-grid gap-2">
|
<div class="form-group d-grid gap-2">
|
||||||
|
|
||||||
<input type="button" onclick="{% if mode == "recheck" %} send_totp() {% else %} tryToAuth() {% endif %}" class="btn btn-lg btn-success btn-block" value="Sign in">
|
<input type="{% if mode == "auth" %}submit{% elif mode == 'recheck' %}button{% endif %}" {% if mode == "recheck" %}onclick="send_recovery()" {% endif %} class="btn btn-lg btn-success btn-block" value="Sign in">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@@ -1,14 +1,4 @@
|
|||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
$(document).ready(function showWarningLastBackup() {
|
|
||||||
{% if lastBackup %}
|
|
||||||
$("#modal-title").html("Last backup code used !")
|
|
||||||
$("#modal-body").html("Don't forget to regenerate new backup code after login !")
|
|
||||||
$('#modal-footer').html(`<FORM METHOD="GET" ACTION="{% url 'recovery_auth' %}" Id="confirmLogin" onSubmit="" name="recoveryLastBackupConfirm">
|
|
||||||
<input type='submit'class='btn btn-lg btn-success btn-block' value='Continue'>`)
|
|
||||||
$("#popUpModal").modal('show')
|
|
||||||
{% endif %}
|
|
||||||
return
|
|
||||||
});
|
|
||||||
function send_totp() {
|
function send_totp() {
|
||||||
$.ajax({"url":"{% url 'totp_recheck' %}", method:"POST",dataType:"JSON",
|
$.ajax({"url":"{% url 'totp_recheck' %}", method:"POST",dataType:"JSON",
|
||||||
data:{"csrfmiddlewaretoken":"{{ csrf_token }}","otp":$("#otp").val()},
|
data:{"csrfmiddlewaretoken":"{{ csrf_token }}","otp":$("#otp").val()},
|
||||||
@@ -21,17 +11,6 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function tryToAuth() {
|
|
||||||
const otp_length = $("#otp").val().length
|
|
||||||
if (otp_length == 6) {
|
|
||||||
document.getElementById("formLogin").submit();
|
|
||||||
}
|
|
||||||
else if (otp_length == 11) {
|
|
||||||
const form = document.getElementById("formLogin");
|
|
||||||
form.setAttribute("ACTION", "{% url 'recovery_auth' %}")
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -60,7 +39,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-12">
|
<div class="col-sm-12 col-md-12">
|
||||||
<p>Enter the 6-digits on your authenticator. Or input a recovery code</p>
|
<p>Enter the 6-digits on your authenticator</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -71,15 +50,14 @@
|
|||||||
<span class="input-group-addon input-group-text">
|
<span class="input-group-addon input-group-text">
|
||||||
<i class="glyphicon glyphicon-lock bi bi-lock"></i>
|
<i class="glyphicon glyphicon-lock bi bi-lock"></i>
|
||||||
</span>
|
</span>
|
||||||
<input class="form-control" size="6" MaxLength="11" value="" placeholder="e.g 55552" name="otp" type="text" id="otp" autofocus>
|
<input class="form-control" size="6" MaxLength="6" value="" placeholder="e.g 55552" name="otp" type="text" id="otp" autofocus>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group d-grid gap-2">
|
<div class="form-group d-grid gap-2">
|
||||||
|
|
||||||
<input type="button" onclick="{% if mode == "recheck" %} send_totp() {% else %} tryToAuth() {% endif %}" class="btn btn-lg btn-success btn-block" value="Sign in">
|
<input type="{% if mode == "auth" %}submit{% elif mode == 'recheck' %}button{% endif %}" {% if mode == "recheck" %}onclick="send_totp()" {% endif %} class="btn btn-lg btn-success btn-block" value="Sign in"> </div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</FORM>
|
</FORM>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from .Common import get_redirect_url
|
|||||||
from .models import *
|
from .models import *
|
||||||
from django.template.context_processors import csrf
|
from django.template.context_processors import csrf
|
||||||
import simplejson
|
import simplejson
|
||||||
from django.template.context import RequestContext
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import pyotp
|
import pyotp
|
||||||
from .views import login
|
from .views import login
|
||||||
@@ -27,7 +26,7 @@ def recheck(request):
|
|||||||
context = csrf(request)
|
context = csrf(request)
|
||||||
context["mode"]="recheck"
|
context["mode"]="recheck"
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if verify_login(request,request.user.username, token=request.POST["otp"]):
|
if verify_login(request,request.user.username, token=request.POST["otp"])[0]:
|
||||||
import time
|
import time
|
||||||
request.session["mfa"]["rechecked_at"] = time.time()
|
request.session["mfa"]["rechecked_at"] = time.time()
|
||||||
return HttpResponse(simplejson.dumps({"recheck": True}), content_type="application/json")
|
return HttpResponse(simplejson.dumps({"recheck": True}), content_type="application/json")
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ urlpatterns = [
|
|||||||
url(r'recovery/getTokenLeft', recovery.getTokenLeft, name="get_recovery_token_left"),
|
url(r'recovery/getTokenLeft', recovery.getTokenLeft, name="get_recovery_token_left"),
|
||||||
url(r'recovery/genTokens', recovery.genTokens, name="regen_recovery_tokens"),
|
url(r'recovery/genTokens', recovery.genTokens, name="regen_recovery_tokens"),
|
||||||
url(r'recovery/auth', recovery.auth, name="recovery_auth"),
|
url(r'recovery/auth', recovery.auth, name="recovery_auth"),
|
||||||
url(r'recovery/download_codes', recovery.download_codes, name="download_recovery"),
|
url(r'recovery/recheck', recovery.recheck, name="recovery_recheck"),
|
||||||
|
|
||||||
url(r'email/start/', Email.start , name="start_email"),
|
url(r'email/start/', Email.start , name="start_email"),
|
||||||
url(r'email/auth/', Email.auth , name="email_auth"),
|
url(r'email/auth/', Email.auth , name="email_auth"),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def verify(request,username):
|
|||||||
request.session["base_username"] = username
|
request.session["base_username"] = username
|
||||||
#request.session["base_password"] = password
|
#request.session["base_password"] = password
|
||||||
keys=User_Keys.objects.filter(username=username,enabled=1)
|
keys=User_Keys.objects.filter(username=username,enabled=1)
|
||||||
methods=list(set([k.key_type for k in keys if k.key_type != "RECOVERY"]))
|
methods=list(set([k.key_type for k in keys]))
|
||||||
|
|
||||||
if "Trusted Device" in methods and not request.session.get("checked_trusted_device",False):
|
if "Trusted Device" in methods and not request.session.get("checked_trusted_device",False):
|
||||||
if TrustedDevice.verify(request):
|
if TrustedDevice.verify(request):
|
||||||
@@ -40,10 +40,6 @@ def verify(request,username):
|
|||||||
methods.remove("Trusted Device")
|
methods.remove("Trusted Device")
|
||||||
request.session["mfa_methods"] = methods
|
request.session["mfa_methods"] = methods
|
||||||
|
|
||||||
if "TOTP" not in methods and "RECOVERY" not in settings.MFA_UNALLOWED_METHODS:
|
|
||||||
#Add the "totp" option if user doesn't have totp auth (case with fido auth and backup code for instace)
|
|
||||||
methods.append("TOTP")
|
|
||||||
|
|
||||||
if len(methods)==1:
|
if len(methods)==1:
|
||||||
return HttpResponseRedirect(reverse(methods[0].lower()+"_auth"))
|
return HttpResponseRedirect(reverse(methods[0].lower()+"_auth"))
|
||||||
return show_methods(request)
|
return show_methods(request)
|
||||||
|
|||||||
Reference in New Issue
Block a user