From f7d06c2322720770774ed5c18b2f3970dc778b11 Mon Sep 17 00:00:00 2001 From: Andreas Dickow Date: Wed, 25 Aug 2021 09:08:08 +0200 Subject: [PATCH 01/47] Token delete formdata fix method --- mfa/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mfa/views.py b/mfa/views.py index 9039363..af9a129 100644 --- a/mfa/views.py +++ b/mfa/views.py @@ -57,7 +57,7 @@ def login(request): @login_required def delKey(request): - key=User_Keys.objects.get(id=request.GET["id"]) + key=User_Keys.objects.get(id=request.POST["id"]) if key.username == request.user.username: key.delete() return HttpResponse("Deleted Successfully") From 392b9efdec84d29523c644658f0c68c1882ddc30 Mon Sep 17 00:00:00 2001 From: Andreas Dickow Date: Wed, 6 Oct 2021 12:45:32 +0200 Subject: [PATCH 02/47] init internationalization and csp save templates --- mfa/static/mfa/css/mfa.css | 29 +++++++++ mfa/static/mfa/js/FIDO2/add.js | 49 +++++++++++++++ mfa/static/mfa/js/FIDO2/recheck.js | 65 ++++++++++++++++++++ mfa/static/mfa/js/U2F/add.js | 18 ++++++ mfa/static/mfa/js/U2F/recheck.js | 56 +++++++++++++++++ mfa/static/mfa/js/delete-token.js | 32 ++++++++++ mfa/static/mfa/js/mfa-check.js | 27 ++++++++ mfa/templates/FIDO2/Add.html | 68 ++++---------------- mfa/templates/FIDO2/recheck.html | 92 ++++------------------------ mfa/templates/MFA.html | 75 +++++++---------------- mfa/templates/TOTP/Add.html | 11 +--- mfa/templates/U2F/Add.html | 43 ++++--------- mfa/templates/U2F/recheck.html | 65 +++----------------- mfa/templates/mfa_check.html | 37 +---------- mfa/templates/modal.html | 7 ++- mfa/templates/select_mfa_method.html | 11 ++-- 16 files changed, 358 insertions(+), 327 deletions(-) create mode 100644 mfa/static/mfa/css/mfa.css create mode 100644 mfa/static/mfa/js/FIDO2/add.js create mode 100644 mfa/static/mfa/js/FIDO2/recheck.js create mode 100644 mfa/static/mfa/js/U2F/add.js create mode 100644 mfa/static/mfa/js/U2F/recheck.js create mode 100644 mfa/static/mfa/js/delete-token.js create mode 100644 mfa/static/mfa/js/mfa-check.js diff --git a/mfa/static/mfa/css/mfa.css b/mfa/static/mfa/css/mfa.css new file mode 100644 index 0000000..cef6f81 --- /dev/null +++ b/mfa/static/mfa/css/mfa.css @@ -0,0 +1,29 @@ +.alert-pr{ + align-items: center; +} +.alert-pr>p.success,#res>p.success,.row>success{ + color:green; +} + +.panel-body>.paragraph{ + padding-left: 15px; +} +.panel-body{ + align-items: center; +} +#popUpModal{ + top: 40px; +} +#popUpModal>.modal-dialog{ + height: 80%; + width: 80%; +} +#two-factor-steps { + border: 1px solid #ccc; + border-radius: 3px; + padding: 15px; +} +#two-factor-steps>.row{ + margin: 0px; + align-items: center; +} \ No newline at end of file diff --git a/mfa/static/mfa/js/FIDO2/add.js b/mfa/static/mfa/js/FIDO2/add.js new file mode 100644 index 0000000..1d4dec3 --- /dev/null +++ b/mfa/static/mfa/js/FIDO2/add.js @@ -0,0 +1,49 @@ +function begin_reg(){ + var formData = new FormData($('#fido2_form')) + fetch(formData.get('begin'),{}).then(function(response) { + if(response.ok) + { + return response.arrayBuffer(); + } + throw new Error('Error getting registration data!'); + }).then(CBOR.decode).then(function(options) { + options.publicKey.attestation="direct" + console.log(options) + + return navigator.credentials.create(options); + }).then(function(attestation) { + return fetch(formData.get('complete'), { + method: 'POST', + headers: {'Content-Type': 'application/cbor'}, + body: CBOR.encode({ + "attestationObject": new Uint8Array(attestation.response.attestationObject), + "clientDataJSON": new Uint8Array(attestation.response.clientDataJSON), + }) + }); + }).then(function(response) { + + var stat = response.ok ? 'successful' : 'unsuccessful'; + return response.json() + }).then(function (res) + { + if (res["status"] =='OK') + $("#res").html("
Registered Successfully, "+formData.get('success')+"
") + else + $("#res").html("
Registeration Failed as " + res["message"] + ", try again or Go to Security Home
") + + + }, function(reason) { + $("#res").html("
Registeration Failed as " +reason +", try again or Go to Security Home
") + }) + } + $(document).ready(function (){ + ua=new UAParser().getResult() + if (ua.browser.name == "Safari") + { + $("#res").html("") + } + else + { + setTimeout(begin_reg, 500) + } + }) \ No newline at end of file diff --git a/mfa/static/mfa/js/FIDO2/recheck.js b/mfa/static/mfa/js/FIDO2/recheck.js new file mode 100644 index 0000000..a40180e --- /dev/null +++ b/mfa/static/mfa/js/FIDO2/recheck.js @@ -0,0 +1,65 @@ +function authen() +{ +const begin_url = $('#begin').value; +const complete_url = $('u2f_login').attr('action'); +const mode = $('u2f_login').attr('name') === 'complete'?'auth':'recheck'; +fetch(begin_url, { +method: 'GET', +}).then(function(response) { +if(response.ok) return response.arrayBuffer(); +throw new Error('No credential available to authenticate!'); +}).then(CBOR.decode).then(function(options) { +console.log(options) +return navigator.credentials.get(options); +}).then(function(assertion) { +res=CBOR.encode({ + "credentialId": new Uint8Array(assertion.rawId), + "authenticatorData": new Uint8Array(assertion.response.authenticatorData), + "clientDataJSON": new Uint8Array(assertion.response.clientDataJSON), + "signature": new Uint8Array(assertion.response.signature) +}); + +return fetch(complete_url, { + +method: 'POST', +headers: {'Content-Type': 'application/cbor'}, +body:res, + +}).then(function (response) {if (response.ok) return res = response.json()}).then(function (res) { + if (res.status=="OK") + { + $("#msgdiv").addClass("alert alert-success").removeClass("alert-danger") + $("#msgdiv").html("Verified....please wait") + if(mode == "auth"){ + window.location.href=res.redirect; + } + else if(mode === "recheck"){ + mfa_success_function(); + } + + } + else { + $("#msgdiv").addClass("alert alert-danger").removeClass("alert-success") + $("#msgdiv").html("Verification Failed as " + res.message + ", try again or Go Back") + + if(mode === "recheck"){ + mfa_failed_function(); + } + } +}) + + }) + +} +$(document).ready(function () { +if (location.protocol != 'https:') { + $("#main_paragraph").addClass("alert alert-danger") + $("#main_paragraph").html("FIDO2 must work under secure context") +} else { + ua=new UAParser().getResult() + if (ua.browser.name == "Safari") + $("#res").html("") + else + authen() +} +}); \ No newline at end of file diff --git a/mfa/static/mfa/js/U2F/add.js b/mfa/static/mfa/js/U2F/add.js new file mode 100644 index 0000000..f0b605e --- /dev/null +++ b/mfa/static/mfa/js/U2F/add.js @@ -0,0 +1,18 @@ +$(document).ready(function addToken() { + const form = $('#u2f_form'); + var formData = new FormData(form); + data=JSON.parse(formData.get('token')); + u2f.register(data.appId,data.registerRequests,data.registeredKeys,function (response) { + $.ajax({ + "url":form.attr('action'),method:"POST", + data:{"csrfmiddlewaretoken":formData.get('csrf_token'),"response":JSON.stringify(response)}, + success:function (data) { + if (data == "OK") + { + alert(formData.get('success')) + window.location.href=formData.get('redirect') + } + } + }) + },5000) +}) \ No newline at end of file diff --git a/mfa/static/mfa/js/U2F/recheck.js b/mfa/static/mfa/js/U2F/recheck.js new file mode 100644 index 0000000..7bd9976 --- /dev/null +++ b/mfa/static/mfa/js/U2F/recheck.js @@ -0,0 +1,56 @@ +$(document).ready(function () { + const form = $('#u2f_form'); + var formData = new FormData(form); + if (location.protocol != 'https:') + { + $("#main_paragraph").addClass("alert alert-danger") + $("#main_paragraph").html(formData.get('protocol_message')) + } + else { + + + data = JSON.parse(formData.get('token')) + console.log(data) + u2f.sign(data.appId, data.challenge, data.registeredKeys, function (response) { + console.log(response) + if (response.hasOwnProperty("errorCode") && response.errorCode != 0 ) + { + if (response.errorCode == 4) + { + alert("Invalid Security Key, this security isn't linked to your account") + } + else if (response.errorCode == 5) + { + alert("Verification Timeout, please refresh the page to try again") + } + else + { + alert("Unspecified error, please try again later or try another browser.") + } + } + else if(formData.get('mode') === 'auth') + { + $("#response").val(JSON.stringify(response)) + $("#u2f_login").submit(); + } + else if(formData.get('mode') === 'recheck') { + $.ajax({ + "url":"{% url 'u2f_recheck' %}", + method: "POST", + data: {"csrfmiddlewaretoken":formData.get('csrfmiddlewaretoken'),"response":JSON.stringify(response)}, + success:function (data) { + if (data["recheck"]) { + mfa_success_function(); + } + else { + mfa_failed_function(); + } + } + + }) + + } + + }, 5000) + } + }) \ No newline at end of file diff --git a/mfa/static/mfa/js/delete-token.js b/mfa/static/mfa/js/delete-token.js new file mode 100644 index 0000000..cecfae2 --- /dev/null +++ b/mfa/static/mfa/js/delete-token.js @@ -0,0 +1,32 @@ +function confirmDel(id,confirm_url) { + $.ajax({ + url:confirm_url, + data:{"id":id}, + success:function (data) { + alert(data) + window.location.reload(); + } + }) +} +function deleteKey(id,name,confirm_url) +{ + $("#modal-title").html("Confirm Delete") + $("#modal-body").html("Are you sure you want to delete '"+name+"'? you may lose access to your system if this your only 2FA."); + $("#actionBtn").remove() + $("#modal-footer").prepend("") + $("#popUpModal").modal() +} + +function toggleKey(id,toggle_url) { + $.ajax({ + url:toggle_url, + success:function (data) { + if (data == "Error") + $("#toggle_"+id).toggle() + + }, + error:function (data) { + $("#toggle_"+id).toggle() + } + }) +} \ No newline at end of file diff --git a/mfa/static/mfa/js/mfa-check.js b/mfa/static/mfa/js/mfa-check.js new file mode 100644 index 0000000..9a5883e --- /dev/null +++ b/mfa/static/mfa/js/mfa-check.js @@ -0,0 +1,27 @@ +mfa_success_function=null; +mfa_failed_function=null; + +function recheck_mfa(success_func,fail_func,must_mfa) { + if (!must_mfa) success_func() + window.mfa_success_function=success_func; + window.mfa_failed_function=fail_func; + $.ajax({ + "url":"{% url 'mfa_recheck' %}", + success:function (data) { + if (data.hasOwnProperty("res")) { + if (data["res"]) + success_func(); + else fail_func(); + } + else + { + $("#modal-title").html("Recheck Indentity") + $("#modal-body").html(data["html"]) + $("#popUpModal").modal() + } + + + + } + }) +} \ No newline at end of file diff --git a/mfa/templates/FIDO2/Add.html b/mfa/templates/FIDO2/Add.html index 74381cf..44622d3 100644 --- a/mfa/templates/FIDO2/Add.html +++ b/mfa/templates/FIDO2/Add.html @@ -1,58 +1,10 @@ {% extends "base.html" %} {% load static %} +{% load i18n %} {% block head %} - + {% endblock %} {% block content %} @@ -61,13 +13,19 @@
- FIDO2 Security Key + {% trans 'FIDO2 Security Key' %}
- - -
-

Your browser should ask you to confirm you identity.

+ + +
+

{% trans 'Your browser should ask you to confirm you identity.' %}

diff --git a/mfa/templates/FIDO2/recheck.html b/mfa/templates/FIDO2/recheck.html index 3dc0609..d67379f 100644 --- a/mfa/templates/FIDO2/recheck.html +++ b/mfa/templates/FIDO2/recheck.html @@ -1,117 +1,51 @@ {% load static %} +{% load i18n %} +
- Security Key + {% trans 'Security Key
-
+
{% if mode == "auth" %} - Welcome back {% comment %}{% endcomment %} {{ request.session.base_username }}
- Not me + {% trans 'Welcome back' %} {% comment %}{% endcomment %} {{ request.session.base_username }}
+ {% trans 'Not me' %}
{% endif %}
-

please press the button on your security key to prove it is you.

+

{% trans 'please press the button on your security key to prove it is you.' %}

{% if mode == "auth" %} -
+ {% elif mode == "recheck" %} - + {% endif %} {% csrf_token %} +
-
+
{% if request.session.mfa_methods|length > 1 %} - Select Another Method + {% trans 'Select Another Method' %} {% endif %}
-
- - \ No newline at end of file +
\ No newline at end of file diff --git a/mfa/templates/MFA.html b/mfa/templates/MFA.html index 9f250c9..efadf66 100644 --- a/mfa/templates/MFA.html +++ b/mfa/templates/MFA.html @@ -1,44 +1,15 @@ {% extends "base.html" %} {% load static %} +{% load i18n %} {% block head %} - - + + + {% endblock %} {% block content %} + +

@@ -46,23 +17,23 @@
@@ -72,13 +43,13 @@ - - - - - - - + + + + + + + {% for key in keys %} @@ -89,18 +60,18 @@ {% if key.key_type in HIDE_DISABLE %} - + {% else %} - + {% endif %} + {% endif %} {% empty %} - + {% endfor %}
TypeDate AddedExpires OnDeviceLast UsedStatusDelete{% trans 'Type' %}{% trans 'Date Added' %}{% trans 'Expires On' %}{% trans 'Device' %}{% trans 'Last Used' %}{% trans 'Status' %}{% trans 'Delete' %}
{% if key.device %}{{ key.device }}{% endif %} {{ key.last_used }}{% if key.enabled %}On{% else %} Off{% endif %}{% if key.enabled %}{% trans 'On' %}{% else %} {% trans 'Off' %}{% endif %}{% if key.key_type in HIDE_DISABLE %} ---- {% else %} -
You didn't have any keys yet.
{% trans 'You didn't have any keys yet.' %}
diff --git a/mfa/templates/TOTP/Add.html b/mfa/templates/TOTP/Add.html index d303f96..5aa92cb 100644 --- a/mfa/templates/TOTP/Add.html +++ b/mfa/templates/TOTP/Add.html @@ -2,16 +2,7 @@ {% extends "base.html" %} {% load static %} {% block head %} - + - + {% endblock %} {% block content %}

-
-

Adding Security Key

+
+

{% trans 'Adding Security Key' %}

+
-

Your secure Key should be flashing now, please press on button.

+

{% trans 'Your secure Key should be flashing now, please press on button.' %}

diff --git a/mfa/templates/U2F/recheck.html b/mfa/templates/U2F/recheck.html index 9d9bfa6..1b10fe5 100644 --- a/mfa/templates/U2F/recheck.html +++ b/mfa/templates/U2F/recheck.html @@ -1,4 +1,5 @@ {% load static %} +{% load i18n %}
@@ -10,7 +11,7 @@
-

Your key should be flashing now, please press the button.

+

{% trans "Your key should be flashing now, please press the button." %}

{% if mode == "auth" %}
{% elif mode == "recheck" %} @@ -18,6 +19,10 @@ {% endif %} {% csrf_token %} + + + +
@@ -27,7 +32,7 @@
{% if request.session.mfa_methods|length > 1 %} - Select Another Method + {% trans "Select Another Method" %} {% endif %}
@@ -38,61 +43,7 @@ \ No newline at end of file diff --git a/mfa/templates/mfa_check.html b/mfa/templates/mfa_check.html index a7077b7..c375f84 100644 --- a/mfa/templates/mfa_check.html +++ b/mfa/templates/mfa_check.html @@ -1,36 +1,3 @@ - +{% load static %} + {% include "modal.html" %} \ No newline at end of file diff --git a/mfa/templates/modal.html b/mfa/templates/modal.html index 59a3cee..7cb3081 100644 --- a/mfa/templates/modal.html +++ b/mfa/templates/modal.html @@ -1,5 +1,6 @@ -