@@ -1025,130 +1025,6 @@ | |||||
"set_only_once": 0, | "set_only_once": 0, | ||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"depends_on": "eval:doc.enable_two_factor_auth==1 && doc.two_factor_method == \"OTP App\" && doc.send_barcode_as_email==1", | |||||
"fieldname": "qr_code_email_subject", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "QR Code Email Subject", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"depends_on": "eval:doc.enable_two_factor_auth==1 && doc.two_factor_method == \"OTP App\" && doc.send_barcode_as_email==1", | |||||
"fieldname": "qr_code_email_body", | |||||
"fieldtype": "Small Text", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "QR Code Email Body", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"depends_on": "eval:doc.enable_two_factor_auth==1 && doc.two_factor_method == \"Email\"", | |||||
"fieldname": "two_factor_email_subject", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Two factor Email Subject", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"depends_on": "eval:doc.enable_two_factor_auth==1 && doc.two_factor_method == \"Email\"", | |||||
"fieldname": "two_factor_email_body", | |||||
"fieldtype": "Small Text", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Two factor Email Body", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | { | ||||
"allow_bulk_edit": 0, | "allow_bulk_edit": 0, | ||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
@@ -1281,8 +1157,8 @@ | |||||
"issingle": 1, | "issingle": 1, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-07-28 07:21:12.520227", | |||||
"modified_by": "Administrator", | |||||
"modified": "2017-07-29 13:33:49.201189", | |||||
"modified_by": "chude.osiegbu@manqala.com", | |||||
"module": "Core", | "module": "Core", | ||||
"name": "System Settings", | "name": "System Settings", | ||||
"name_case": "", | "name_case": "", | ||||
@@ -269,18 +269,12 @@ var continue_otp_app = function(setup, qrcode){ | |||||
request_otp(); | request_otp(); | ||||
var qrcode_div = $('<div>').attr({'id':'qrcode_div','style':'text-align:center;padding-bottom:15px;'}); | var qrcode_div = $('<div>').attr({'id':'qrcode_div','style':'text-align:center;padding-bottom:15px;'}); | ||||
if (!setup){ | |||||
direction = $('<div>').attr('id','qr_info').text('Scan QR Code and enter the resulting code displayed. \ | |||||
You can use apps such as Google Authenticator, Lastpass Authenticator, Authy, Duo Mobile and others.'), | |||||
qrimg = $('<img>').attr({ | |||||
'src':'data:image/svg+xml;base64,' + qrcode, | |||||
'style':'width:250px;height:250px;'}); | |||||
if (setup){ | |||||
direction = $('<div>').attr('id','qr_info').text('Enter Code displayed in OTP App.'); | |||||
qrcode_div.append(direction); | qrcode_div.append(direction); | ||||
qrcode_div.append(qrimg); | |||||
$('#otp_div').prepend(qrcode_div); | $('#otp_div').prepend(qrcode_div); | ||||
} else { | } else { | ||||
direction = $('<div>').attr('id','qr_info').text('Enter Code displayed in OTP App'); | |||||
direction = $('<div>').attr('id','qr_info').text('OTP setup using OTP App was not completed. Please contact Administrator.'); | |||||
qrcode_div.append(direction); | qrcode_div.append(direction); | ||||
$('#otp_div').prepend(qrcode_div); | $('#otp_div').prepend(qrcode_div); | ||||
} | } | ||||
@@ -291,36 +285,10 @@ var continue_sms = function(setup, prompt){ | |||||
var sms_div = $('<div>').attr({'id':'sms_div','style':'padding-bottom:15px;text-align:center;'}); | var sms_div = $('<div>').attr({'id':'sms_div','style':'padding-bottom:15px;text-align:center;'}); | ||||
if (setup){ | if (setup){ | ||||
direction = $('<div>').attr('id','sms_info').text('Enter phone number to send verification code'); | |||||
sms_div.append(direction); | |||||
sms_div.append($('<div>').attr({'id':'sms_code_div'}).html( | |||||
'<div class="form-group text-center">\ | |||||
<input type="text" id="phone_no" class="form-control" placeholder="2347001234567" required="" autofocus="">\ | |||||
<button class="btn btn-sm btn-primary" id="submit_phone_no" >Send SMS</button>\ | |||||
</div><hr>')); | |||||
sms_div.append(prompt) | |||||
$('#otp_div').prepend(sms_div); | $('#otp_div').prepend(sms_div); | ||||
$('#submit_phone_no').on('click',function(){ | |||||
frappe.call({ | |||||
method: "frappe.core.doctype.user.user.send_token_via_sms", | |||||
args: {'phone_no': $('#phone_no').val(), 'tmp_id':data.tmp_id }, | |||||
freeze: true, | |||||
callback: function(r) { | |||||
if (r.message){ | |||||
$('#sms_div').empty().append( | |||||
'<p class="lead">SMS sent.<br><small><small>Enter verification code received</small></small></p><hr>' | |||||
); | |||||
} else { | |||||
$('#sms_div').empty().append( | |||||
'<p class="lead">SMS not sent</p><hr>' | |||||
); | |||||
} | |||||
} | |||||
}); | |||||
}) | |||||
} else { | } else { | ||||
direction = $('<div>').attr('id','qr_info').text(prompt || 'SMS not sent'); | |||||
direction = $('<div>').attr('id','qr_info').text(prompt || 'SMS was not sent. Please contact Administrator.'); | |||||
sms_div.append(direction); | sms_div.append(direction); | ||||
$('#otp_div').prepend(sms_div) | $('#otp_div').prepend(sms_div) | ||||
} | } | ||||
@@ -331,22 +299,10 @@ var continue_email = function(setup, prompt){ | |||||
var email_div = $('<div>').attr({'id':'email_div','style':'padding-bottom:15px;text-align:center;'}); | var email_div = $('<div>').attr({'id':'email_div','style':'padding-bottom:15px;text-align:center;'}); | ||||
if (setup){ | if (setup){ | ||||
email_div.append('<p>Verification code email will be sent to registered email address. Enter code received below</p>') | |||||
email_div.append(prompt) | |||||
$('#otp_div').prepend(email_div); | $('#otp_div').prepend(email_div); | ||||
frappe.call({ | |||||
method: "frappe.core.doctype.user.user.send_token_via_email", | |||||
args: {'tmp_id':data.tmp_id }, | |||||
callback: function(r) { | |||||
if (r.message){ | |||||
} else { | |||||
$('#email_div').empty().append( | |||||
'<p>Email not sent</p><hr>' | |||||
); | |||||
} | |||||
} | |||||
}); | |||||
} else { | } else { | ||||
var direction = $('<div>').attr('id','qr_info').text(prompt || 'Verification code email not sent'); | |||||
var direction = $('<div>').attr('id','qr_info').text(prompt || 'Verification code email not sent. Please contact Administrator.'); | |||||
email_div.append(direction); | email_div.append(direction); | ||||
$('#otp_div').prepend(email_div); | $('#otp_div').prepend(email_div); | ||||
} | } |
@@ -130,12 +130,13 @@ def get_verification_obj(user,token,otp_secret): | |||||
if verification_method == 'SMS': | if verification_method == 'SMS': | ||||
verification_obj = process_2fa_for_sms(user,token,otp_secret) | verification_obj = process_2fa_for_sms(user,token,otp_secret) | ||||
elif verification_method == 'OTP App': | elif verification_method == 'OTP App': | ||||
if should_send_barcode_as_email(): | |||||
verification_obj = process_2fa_for_email(user,token,otp_secret,otp_issuer,method='otp_app') | |||||
#check if this if the first time that the user is trying to login. If so, send an email | |||||
if not frappe.db.get_default(user + '_otplogin'): | |||||
verification_obj = process_2fa_for_email(user,token,otp_secret,otp_issuer,method='OTP App') | |||||
else: | else: | ||||
verification_obj = process_2fa_for_otp_app(user,otp_secret,otp_issuer) | verification_obj = process_2fa_for_otp_app(user,otp_secret,otp_issuer) | ||||
elif verification_method == 'Email': | elif verification_method == 'Email': | ||||
process_2fa_for_email(user,token,otp_secret,otp_issuer) | |||||
verification_obj = process_2fa_for_email(user,token,otp_secret,otp_issuer) | |||||
return verification_obj | return verification_obj | ||||
@@ -146,7 +147,8 @@ def process_2fa_for_sms(user,token,otp_secret): | |||||
status = send_token_via_sms(otp_secret,token=token, phone_no=phone) | status = send_token_via_sms(otp_secret,token=token, phone_no=phone) | ||||
verification_obj = {'token_delivery': status, | verification_obj = {'token_delivery': status, | ||||
'prompt': status and 'Enter verification code sent to {}'.format(phone[:4] + '******' + phone[-3:]), | 'prompt': status and 'Enter verification code sent to {}'.format(phone[:4] + '******' + phone[-3:]), | ||||
'method': 'SMS'} | |||||
'method': 'SMS', | |||||
'setup': status} | |||||
return verification_obj | return verification_obj | ||||
def process_2fa_for_otp_app(user,otp_secret,otp_issuer): | def process_2fa_for_otp_app(user,otp_secret,otp_issuer): | ||||
@@ -163,55 +165,50 @@ def process_2fa_for_otp_app(user,otp_secret,otp_issuer): | |||||
'setup': otp_setup_completed } | 'setup': otp_setup_completed } | ||||
return verification_obj | return verification_obj | ||||
def process_2fa_for_email(user,token,otp_secret,otp_issuer,method='email'): | |||||
def process_2fa_for_email(user,token,otp_secret,otp_issuer,method='Email'): | |||||
'''Process Email method for 2fa.''' | '''Process Email method for 2fa.''' | ||||
subject = None | |||||
message = None | message = None | ||||
status = True | status = True | ||||
if method == 'otp_app' and not frappe.db.get_default(user + '_otplogin'): | |||||
prompt = '' | |||||
if method == 'OTP App' and not frappe.db.get_default(user + '_otplogin'): | |||||
'''Sending one-time email for OTP App''' | |||||
totp_uri = pyotp.TOTP(otp_secret).provisioning_uri(user, issuer_name=otp_issuer) | totp_uri = pyotp.TOTP(otp_secret).provisioning_uri(user, issuer_name=otp_issuer) | ||||
qrcode_link = get_link_for_qrcode(user,totp_uri) | qrcode_link = get_link_for_qrcode(user,totp_uri) | ||||
message = get_email_body_for_qr_code({'qrcode_link':qrcode_link}) | message = get_email_body_for_qr_code({'qrcode_link':qrcode_link}) | ||||
subject = get_email_subject_for_qr_code({'qrcode_link':qrcode_link}) | subject = get_email_subject_for_qr_code({'qrcode_link':qrcode_link}) | ||||
if method == 'email' or message: | |||||
status = send_token_via_email(user,token,otp_secret,otp_issuer,subject=subject,message=message) | |||||
prompt = 'Please check your registered email address for instructions on how to proceed. Do not close this window as you will have to return to it!!' | |||||
else: | |||||
'''Sending email verification''' | |||||
prompt = 'Verification code has been sent to your registered email address.' | |||||
status = send_token_via_email(user,token,otp_secret,otp_issuer,subject=subject,message=message) | |||||
verification_obj = {'token_delivery': status, | verification_obj = {'token_delivery': status, | ||||
'prompt': status and 'Verification code has been sent to your registered email address', | |||||
'method': 'Email'} | |||||
'prompt': status and prompt, | |||||
'method': 'Email', | |||||
'setup': status} | |||||
return verification_obj | return verification_obj | ||||
def get_email_subject_for_2fa(kwargs_dict): | def get_email_subject_for_2fa(kwargs_dict): | ||||
'''Get email subject for 2fa.''' | '''Get email subject for 2fa.''' | ||||
subject_template = 'Verifcation Code from Frappe Framework' | |||||
template = frappe.get_value('System Settings','System Settings','two_factor_email_subject') | |||||
if not template == '': | |||||
subject_template = template | |||||
subject_template = 'Verifcation Code from {}'.format(frappe.db.get_value('System Settings', 'System Settings', 'otp_issuer_name')) | |||||
subject = render_string_template(subject_template,kwargs_dict) | subject = render_string_template(subject_template,kwargs_dict) | ||||
return subject | return subject | ||||
def get_email_body_for_2fa(kwargs_dict): | def get_email_body_for_2fa(kwargs_dict): | ||||
'''Get email body for 2fa.''' | '''Get email body for 2fa.''' | ||||
body_template = 'Use this token to login <br> {{otp}}' | body_template = 'Use this token to login <br> {{otp}}' | ||||
template = frappe.get_value('System Settings','System Settings','two_factor_email_body') | |||||
if not template == '': | |||||
subject_template = template | |||||
body = render_string_template(body_template,kwargs_dict) | body = render_string_template(body_template,kwargs_dict) | ||||
return body | return body | ||||
def get_email_subject_for_qr_code(kwargs_dict): | def get_email_subject_for_qr_code(kwargs_dict): | ||||
'''Get QRCode email subject.''' | '''Get QRCode email subject.''' | ||||
subject_template = 'Verification Code from Frappe Framework' | |||||
template = frappe.get_value('System Settings','System Settings','qr_code_email_subject') | |||||
if not template == '': | |||||
subject_template = template | |||||
subject_template = 'OTP Registration Code from {}'.format(frappe.db.get_value('System Settings', 'System Settings', 'otp_issuer_name')) | |||||
subject = render_string_template(subject_template,kwargs_dict) | subject = render_string_template(subject_template,kwargs_dict) | ||||
return subject | return subject | ||||
def get_email_body_for_qr_code(kwargs_dict): | def get_email_body_for_qr_code(kwargs_dict): | ||||
'''Get QRCode email body.''' | '''Get QRCode email body.''' | ||||
body_template = 'Scan the QRCode on this link to get token <br> {{qrcode_link}}' | |||||
template = frappe.get_value('System Settings','System Settings','qr_code_email_body') | |||||
if not template == '': | |||||
body_template = template | |||||
body_template = 'Please click on the following link and follow the instructions on the page.<br> {{qrcode_link}}' | |||||
body = render_string_template(body_template,kwargs_dict) | body = render_string_template(body_template,kwargs_dict) | ||||
return body | return body | ||||
@@ -1,12 +1,31 @@ | |||||
{% extends "templates/web.html" %} | |||||
{% block title %}Register OTP Secret{% endblock %} | |||||
{% block page_content %} | |||||
<div> | <div> | ||||
<div style="text-align:center"> | <div style="text-align:center"> | ||||
<div style="width:400px;margin:auto;text-align:center;"> | |||||
<strong style="padding:10px;">Hi {{qr_code_user.first_name}}, Please scan QR Code and enter the resulting code displayed. | |||||
You can use apps such as Google Authenticator, Lastpass Authenticator, Authy, Duo Mobile and others. | |||||
</strong> | |||||
</div> | |||||
<div style="margin-top:10px;"> | |||||
<img src="data:image/svg+xml;base64,{{qrcode_svg}}"> | |||||
</div> | |||||
<table> | |||||
<tr> | |||||
<td width="50%"> | |||||
<div style="margin:auto;text-align:left;"> | |||||
<p> | |||||
Hi {{qr_code_user.first_name}}, please perform the following actions: | |||||
<li> Open your authentication app on your mobile phone, | |||||
<li> Scan the QR Code and enter the resulting code displayed | |||||
<li> Return to the Verification screen and enter the code displayed by your authentication app | |||||
</p> | |||||
<p>Examples of Authentication Apps you can use are Google Authenticator, Lastpass Authenticator, Authy and Duo Mobile. | |||||
</p> | |||||
</div> | |||||
</td> | |||||
<td> | |||||
<div style="padding:10px;"> | |||||
<img src="data:image/svg+xml;base64,{{qrcode_svg}}"> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
</div> | </div> | ||||
</div> | |||||
</div> | |||||
{% endblock %} |
@@ -14,10 +14,6 @@ no_cache = 1 | |||||
def get_context(context): | def get_context(context): | ||||
context.qr_code_user,context.qrcode_svg = get_user_svg_from_cache() | context.qr_code_user,context.qrcode_svg = get_user_svg_from_cache() | ||||
def get_query_key(): | def get_query_key(): | ||||
'''Return query string arg.''' | '''Return query string arg.''' | ||||
query_string = frappe.local.request.query_string | query_string = frappe.local.request.query_string | ||||