diff --git a/frappe/auth.py b/frappe/auth.py
index 4ab689f759..003637da5c 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -124,7 +124,7 @@ class LoginManager:
query = """select name from `tabRole` where two_factor_auth=1
and name in ("All",{0}) limit 1""".format(', '.join('\"{}\"'.format(i.role) for \
i in user_obj.roles))
- two_factor_user_role = len(frappe.db.sql(query))
+ two_factor_user_role = len(frappe.db.sql(query))
self.otp_secret = frappe.db.get_default(self.user + '_otpsecret')
if not self.otp_secret:
@@ -152,12 +152,10 @@ class LoginManager:
else:
otp_setup_completed = False
- verification_obj = {'token_delivery': True,
- 'prompt': False,
- 'totp_uri': totp_uri,
+ verification_obj = {'totp_uri': totp_uri,
'method': 'OTP App',
'qrcode': get_qr_svg_code(totp_uri),
- 'otp_setup_completed': otp_setup_completed}
+ 'setup': otp_setup_completed }
elif self.verification_method == 'Email':
status = self.send_token_via_email(token=token,otpsecret=self.otp_secret)
verification_obj = {'token_delivery': status,
@@ -174,9 +172,13 @@ class LoginManager:
usr = frappe.form_dict.get('usr')
pwd = frappe.form_dict.get('pwd')
+ # set increased expiry time for SMS and Email
if self.verification_method in ['SMS', 'Email']:
- frappe.cache().set(tmp_id + '_token',token)
- frappe.cache().expire(tmp_id + '_token',300)
+ expiry_time = 300
+ frappe.cache().set(tmp_id + '_token', token)
+ frappe.cache().expire(tmp_id + '_token', expiry_time)
+ else:
+ expiry_time = 180
frappe.cache().set(tmp_id + '_usr', usr)
frappe.cache().set(tmp_id + '_pwd', pwd)
@@ -184,7 +186,7 @@ class LoginManager:
frappe.cache().set(tmp_id + '_user', self.user)
for field in [tmp_id + nm for nm in ['_usr', '_pwd', '_otp_secret', '_user']]:
- frappe.cache().expire(field,180)
+ frappe.cache().expire(field, expiry_time)
frappe.local.response['verification'] = verification_obj
frappe.local.response['tmp_id'] = tmp_id
@@ -232,7 +234,7 @@ class LoginManager:
try:
otp_secret = frappe.cache().get(tmp_id + '_otp_secret')
if not otp_secret:
- frappe.throw('Login session expired, please refresh page to try again')
+ frappe.throw('Login session expired. Refresh page to try again')
except AttributeError:
return False
@@ -395,21 +397,24 @@ class LoginManager:
def clear_cookies(self):
clear_cookies()
- def send_token_via_sms(self,otpsecret,token=None,phone_no=None):
+ def send_token_via_sms(self, otpsecret, token=None, phone_no=None):
try:
from erpnext.setup.doctype.sms_settings.sms_settings import send_request
except:
return False
+
+ if not phone_no:
+ return False
+
ss = frappe.get_doc('SMS Settings', 'SMS Settings')
if not ss.sms_gateway_url:
return False
+
hotp = pyotp.HOTP(otpsecret)
args = {ss.message_parameter: 'verification code is {}'.format(hotp.at(int(token)))}
for d in ss.get("parameters"):
args[d.parameter] = d.value
- if not phone_no:
- return False
args[ss.receiver_parameter] = phone_no
status = send_request(ss.sms_gateway_url, args)
@@ -419,13 +424,14 @@ class LoginManager:
else:
return False
- def send_token_via_email(self,token,otpsecret):
- user_email = frappe.db.get_value('User',self.user, 'email')
+ def send_token_via_email(self, token, otpsecret):
+ user_email = frappe.db.get_value('User', self.user, 'email')
if not user_email:
return False
hotp = pyotp.HOTP(otpsecret)
frappe.sendmail(recipients=user_email, sender=None, subject='Verification Code',
- message='
Your verification code is {}
'.format(hotp.at(int(token))),delayed=False, retry=3)
+ message='Your verification code is {}
'.format(hotp.at(int(token))),
+ delayed=False, retry=3)
return True
class CookieManager:
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index d2343672fb..7f05f5def8 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -928,17 +928,18 @@ def update_gravatar(name):
@frappe.whitelist(allow_guest=True)
def send_token_via_sms(tmp_id,phone_no=None,user=None):
- from erpnext.setup.doctype.sms_settings.sms_settings import send_request
+ try:
+ from erpnext.setup.doctype.sms_settings.sms_settings import send_request
+ except:
+ return False
if not frappe.cache().ttl(tmp_id + '_token'):
return False
-
- token = frappe.cache().get(tmp_id + '_token')
-
ss = frappe.get_doc('SMS Settings', 'SMS Settings')
if not ss.sms_gateway_url:
return False
+ token = frappe.cache().get(tmp_id + '_token')
args = {ss.message_parameter: 'verification code is {}'.format(token)}
for d in ss.get("parameters"):
@@ -956,7 +957,6 @@ def send_token_via_sms(tmp_id,phone_no=None,user=None):
return False
args[ss.receiver_parameter] = usr_phone
-
status = send_request(ss.sms_gateway_url, args)
if 200 <= status < 300:
@@ -971,22 +971,19 @@ def send_token_via_email(tmp_id,token=None):
user = frappe.cache().get(tmp_id + '_user')
count = token or frappe.cache().get(tmp_id + '_token')
+
if ((not user) or (user == 'None') or (not count)):
return False
-
- otpsecret = frappe.cache().get(tmp_id + '_otp_secret')
- hotp = pyotp.HOTP(otpsecret)
user_email = frappe.db.get_value('User',user, 'email')
if not user_email:
return False
- frappe.sendmail(recipients=user_email, sender=None, subject='Verification Code',
- message='Your verification code is {0}
'.format(hotp.at(int(count))),delayed=False, retry=3)
- return True
-#@frappe.whitelist(allow_guest=True)
-#def set_verification_method(tmp_id,method=None):
-# user = frappe.cache().get(tmp_id + '_user')
-# if ((not user) or (user == 'None') or (not method)):
-# return False
-# frappe.db.set_value('User', user, 'two_factor_method', method)
-# frappe.db.commit()
\ No newline at end of file
+ otpsecret = frappe.cache().get(tmp_id + '_otp_secret')
+ hotp = pyotp.HOTP(otpsecret)
+
+ frappe.sendmail(
+ recipients=user_email, sender=None, subject='Verification Code',
+ message='Your verification code is {0}
'.format(hotp.at(int(count))),
+ delayed=False, retry=3)
+
+ return True
diff --git a/frappe/hooks.py b/frappe/hooks.py
index f9eadafca0..49ec772175 100755
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -40,8 +40,7 @@ app_include_css = [
]
web_include_js = [
- "website_script.js",
- "assets/js/qrious.min.js"
+ "website_script.js"
]
bootstrap = "assets/frappe/css/bootstrap.css"
diff --git a/frappe/public/js/frappe/qrious.min.js b/frappe/public/js/frappe/qrious.min.js
deleted file mode 100644
index 5943f8c0f9..0000000000
--- a/frappe/public/js/frappe/qrious.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*! QRious v4.0.2 | (C) 2017 Alasdair Mercer | GPL v3 License
-Based on jsqrencode | (C) 2010 tz@execpc.com | GPL v3 License
-*/
-!function(t,e){console.log(t);console.log(e);"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.QRious=e()}(this,function(){"use strict";function t(t,e){var n;return"function"==typeof Object.create?n=Object.create(t):(s.prototype=t,n=new s,s.prototype=null),e&&i(!0,n,e),n}function e(e,n,s,r){var o=this;return"string"!=typeof e&&(r=s,s=n,n=e,e=null),"function"!=typeof n&&(r=s,s=n,n=function(){return o.apply(this,arguments)}),i(!1,n,o,r),n.prototype=t(o.prototype,s),n.prototype.constructor=n,n.class_=e||o.class_,n.super_=o,n}function i(t,e,i){for(var n,s,a=0,h=(i=o.call(arguments,2)).length;a>1&1,n=0;n0;e--)n[e]=n[e]?n[e-1]^_.EXPONENT[v._modN(_.LOG[n[e]]+t)]:n[e-1];n[0]=_.EXPONENT[v._modN(_.LOG[n[0]]+t)]}for(t=0;t<=i;t++)n[t]=_.LOG[n[t]]},_checkBadness:function(){var t,e,i,n,s,r=0,o=this._badness,a=this.buffer,h=this.width;for(s=0;sh*h;)u-=h*h,c++;for(r+=c*v.N4,n=0;n=o-2&&(t=o-2,s>9&&t--);var a=t;if(s>9){for(r[a+2]=0,r[a+3]=0;a--;)e=r[a],r[a+3]|=255&e<<4,r[a+2]=e>>4;r[2]|=255&t<<4,r[1]=t>>4,r[0]=64|t>>12}else{for(r[a+1]=0,r[a+2]=0;a--;)e=r[a],r[a+2]|=255&e<<4,r[a+1]=e>>4;r[1]|=255&t<<4,r[0]=64|t>>4}for(a=t+3-(s<10);a=5&&(i+=v.N1+n[e]-5);for(e=3;et||3*n[e-3]>=4*n[e]||3*n[e+3]>=4*n[e])&&(i+=v.N3);return i},_finish:function(){this._stringBuffer=this.buffer.slice();var t,e,i=0,n=3e4;for(e=0;e<8&&(this._applyMask(e),(t=this._checkBadness())>=1)1&n&&(s[r-1-e+8*r]=1,e<6?s[8+r*e]=1:s[8+r*(e+1)]=1);for(e=0;e<7;e++,n>>=1)1&n&&(s[8+r*(r-7+e)]=1,e?s[6-e+8*r]=1:s[7+8*r]=1)},_interleaveBlocks:function(){var t,e,i=this._dataBlock,n=this._ecc,s=this._eccBlock,r=0,o=this._calculateMaxLength(),a=this._neccBlock1,h=this._neccBlock2,f=this._stringBuffer;for(t=0;t1)for(t=u.BLOCK[n],i=s-7;;){for(e=s-7;e>t-3&&(this._addAlignment(e,i),!(e6)for(t=d.BLOCK[r-7],e=17,i=0;i<6;i++)for(n=0;n<3;n++,e--)1&(e>11?r>>e-12:t>>e)?(s[5-i+o*(2-n+o-11)]=1,s[2-n+o-11+o*(5-i)]=1):(this._setMask(5-i,2-n+o-11),this._setMask(2-n+o-11,5-i))},_isMasked:function(t,e){var i=v._getMaskBit(t,e);return 1===this._mask[i]},_pack:function(){var t,e,i,n=1,s=1,r=this.width,o=r-1,a=r-1,h=(this._dataBlock+this._eccBlock)*(this._neccBlock1+this._neccBlock2)+this._neccBlock2;for(e=0;ee&&(i=t,t=e,e=i),i=e,i+=e*e,i>>=1,i+=t},_modN:function(t){for(;t>=255;)t=((t-=255)>>8)+(255&t);return t},N1:3,N2:3,N3:40,N4:10}),p=v,m=f.extend({draw:function(){this.element.src=this.qrious.toDataURL()},reset:function(){this.element.src=""},resize:function(){var t=this.element;t.width=t.height=this.qrious.size}}),g=h.extend(function(t,e,i,n){this.name=t,this.modifiable=Boolean(e),this.defaultValue=i,this._valueTransformer=n},{transform:function(t){var e=this._valueTransformer;return"function"==typeof e?e(t,this):t}}),k=h.extend(null,{abs:function(t){return null!=t?Math.abs(t):null},hasOwn:function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},noop:function(){},toUpperCase:function(t){return null!=t?t.toUpperCase():null}}),w=h.extend(function(t){this.options={},t.forEach(function(t){this.options[t.name]=t},this)},{exists:function(t){return null!=this.options[t]},get:function(t,e){return w._get(this.options[t],e)},getAll:function(t){var e,i=this.options,n={};for(e in i)k.hasOwn(i,e)&&(n[e]=w._get(i[e],t));return n},init:function(t,e,i){"function"!=typeof i&&(i=k.noop);var n,s;for(n in this.options)k.hasOwn(this.options,n)&&(s=this.options[n],w._set(s,s.defaultValue,e),w._createAccessor(s,e,i));this._setAll(t,e,!0)},set:function(t,e,i){return this._set(t,e,i)},setAll:function(t,e){return this._setAll(t,e)},_set:function(t,e,i,n){var s=this.options[t];if(!s)throw new Error("Invalid option: "+t);if(!s.modifiable&&!n)throw new Error("Option cannot be modified: "+t);return w._set(s,e,i)},_setAll:function(t,e,i){if(!t)return!1;var n,s=!1;for(n in t)k.hasOwn(t,n)&&this._set(n,t[n],e,i)&&(s=!0);return s}},{_createAccessor:function(t,e,i){var n={get:function(){return w._get(t,e)}};t.modifiable&&(n.set=function(n){w._set(t,n,e)&&i(n,t)}),Object.defineProperty(e,t.name,n)},_get:function(t,e){return e["_"+t.name]},_set:function(t,e,i){var n="_"+t.name,s=i[n],r=t.transform(null!=e?e:t.defaultValue);return i[n]=r,r!==s}}),M=w,b=h.extend(function(){this._services={}},{getService:function(t){var e=this._services[t];if(!e)throw new Error("Service is not being managed with name: "+t);return e},setService:function(t,e){if(this._services[t])throw new Error("Service is already managed with name: "+t);e&&(this._services[t]=e)}}),B=new M([new g("background",!0,"white"),new g("backgroundAlpha",!0,1,k.abs),new g("element"),new g("foreground",!0,"black"),new g("foregroundAlpha",!0,1,k.abs),new g("level",!0,"L",k.toUpperCase),new g("mime",!0,"image/png"),new g("padding",!0,null,k.abs),new g("size",!0,100,k.abs),new g("value",!0,"")]),y=new b,O=h.extend(function(t){B.init(t,this,this.update.bind(this));var e=B.get("element",this),i=y.getService("element"),n=e&&i.isCanvas(e)?e:i.createCanvas(),s=e&&i.isImage(e)?e:i.createImage();this._canvasRenderer=new c(this,n,!0),this._imageRenderer=new m(this,s,s===e),this.update()},{get:function(){return B.getAll(this)},set:function(t){B.setAll(t,this)&&this.update()},toDataURL:function(t){return this.canvas.toDataURL(t||this.mime)},update:function(){var t=new p({level:this.level,value:this.value});this._canvasRenderer.render(t),this._imageRenderer.render(t)}},{use:function(t){y.setService(t.getName(),t)}});Object.defineProperties(O.prototype,{canvas:{get:function(){return this._canvasRenderer.getElement()}},image:{get:function(){return this._imageRenderer.getElement()}}});var A=O,L=h.extend({getName:function(){}}).extend({createCanvas:function(){},createImage:function(){},getName:function(){return"element"},isCanvas:function(t){},isImage:function(t){}}).extend({createCanvas:function(){return document.createElement("canvas")},createImage:function(){return document.createElement("img")},isCanvas:function(t){return t instanceof HTMLCanvasElement},isImage:function(t){return t instanceof HTMLImageElement}});return A.use(new L),A});
-
-//# sourceMappingURL=qrious.min.js.map
\ No newline at end of file
diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js
index e9d22892af..8d3c7f63f3 100644
--- a/frappe/templates/includes/login/login.js
+++ b/frappe/templates/includes/login/login.js
@@ -160,204 +160,16 @@ login.login_handlers = (function() {
if(data.verification) {
login.set_indicator("{{ _("Success") }}", 'green');
- var continue_otp = function(setup_completed,method_prompt){
-
- $('.login-content').empty().append($('').attr({'id':'otp_div'}).html(
- '
'));
-
- verify_token();
-
- if (!setup_completed){
- var qrcode = $('
')
- qrcode.attr('id','qrcode_div');
- qrcode.css('text-align','center');
-
- var direction = $('
').attr('id','qr_info').text(method_prompt || 'Scan QR Code and enter the resulting code displayed');
-
- var qrimg = $('
');
- qrimg.attr('src','data:image/svg+xml;base64,' + data.verification.qrcode);
- qrcode.append(direction);
- qrcode.append(qrimg);
- $('#otp_div').prepend(qrcode);
- } else {
- var qrcode = $('
').attr('id','qrcode_div');
- var direction = $('
').attr('id','qr_info').text(method_prompt || 'Enter Code displayed in OTP App');
- direction.attr('style','padding-bottom:10px;');
- qrcode.append(direction);
- $('#otp_div').prepend(qrcode)
- }
- }
-
- var continue_sms = function(setup_completed,method_prompt){
-
- $('.login-content').empty().append($('
').attr({'id':'otp_div'}).html(
- '
'));
-
- verify_token();
-
- if (!setup_completed){
- var sms_div = $('
').attr({'id':'sms_div','style':'margin-bottom: 20px;'});
- var direction = $('
').attr({'id':'sms_info','style':'margin-bottom: 15px;'}).text('Enter phone number to send verification code');
- sms_div.append(direction);
- sms_div.append($('
').attr({'id':'sms_code_div'}).html(
- '
\
- \
- Send SMS \
-
'));
-
- $('#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(
- '
SMS sent.Enter verification code received
'
- );
- } else {
- $('#sms_div').empty().append(
- '
SMS not sent
'
- );
- }
- }
- });
- })
- } else {
- var smscode = $('
').attr('id','smscode_div');
- var direction = $('
').attr('id','qr_info').text(method_prompt || 'Enter verification code sent to registered phone number');
- direction.attr('style','padding-bottom:10px;');
- smscode.append(direction);
- $('#otp_div').prepend(smscode)
- }
- }
-
- var continue_email = function(setup_completed,method_prompt){
-
- $('.login-content').empty().append($('
').attr({'id':'otp_div'}).html(
- '
'));
-
- verify_token();
-
- if (!setup_completed){
- var email_div = $('
').attr({'id':'email_div','style':'margin-bottom: 20px;'});
- email_div.append('
Verification code email will be sent to registered email address. Enter code received below
')
-
- $('#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(
- '
Email not sent
'
- );
- }
- }
- });
- } else {
- if (method_prompt){
- var emailcode = $('
').attr('id','emailcode_div');
- var direction = $('
').attr('id','qr_info').text(method_prompt || 'Verification code email will be sent to registered email address. Enter code received below');
- direction.attr('style','padding-bottom:10px;');
- emailcode.append(direction);
- $('#otp_div').prepend(emailcode);
- } else {
- var emailcode = $('
').attr('id','emailcode_div');
- var direction = $('
').attr('id','qr_info').text('Verification code email not sent');
- direction.attr('style','padding-bottom:10px;');
- emailcode.append(direction);
- $('#otp_div').prepend(emailcode)
- }
-
- }
- }
-
- if (data.verification.method_first_time){
- // $('.login-content').empty().append('
\
- //
\
- //
Select verification Method \
- // method may be changed later in settings
\
- //
\
- //
\
- // \
- // \
- // OTP App\
- // \
- //
\
- //
\
- // \
- // \
- // SMS\
- // \
- //
\
- //
\
- // \
- // \
- // Email\
- // \
- //
\
- //
Continue \
- //
')
-
- // if (data.verification.restrict_method){
- // $('input[name=method]').each(function(){
- // if ($(this).val() != data.verification.restrict_method){
- // $(this).attr('disabled',true)
- // }
- // })
- // }
- // $('#submit_method').on('click',function(event){
- if (data.verification.method == 'OTP App'){
- continue_otp(setup_completed=false);
- } else if (data.verification.method == 'SMS'){
- continue_sms(setup_completed=false);
- } else if (data.verification.method == 'Email'){
- continue_email(setup_completed=false);
- }
+ document.cookie = "tmp_id="+data.tmp_id;
- // frappe.call({
- // method: "frappe.core.doctype.user.user.set_verification_method",
- // args: {'tmp_id':data.tmp_id, 'method': $('input[name=method]:checked').val()},
- // callback: function(r) { }
- // });
- // });
- } else {
- if (data.verification.method == 'OTP App'){
- console.log(data.verification.totp_uri)
- continue_otp(setup_completed = data.verification.otp_setup_completed);
- } else if (data.verification.method == 'SMS'){
- continue_sms(setup_completed=true, method_prompt=data.verification.prompt);
- console.log('SMS');
- } else if (data.verification.method == 'Email'){
- continue_sms(setup_completed=true, method_prompt=data.verification.prompt);
- }
+ if (data.verification.method == 'OTP App'){
+ continue_otp_app(data.verification.setup, data.verification.qrcode);
+ } else if (data.verification.method == 'SMS'){
+ continue_sms(data.verification.setup, data.verification.prompt);
+ } else if (data.verification.method == 'Email'){
+ continue_sms(data.verification.setup, data.verification.prompt);
}
- document.cookie = "tmp_id="+data.tmp_id;
- //verify_token();
return false;
} else if(data.message == 'Logged In'){
@@ -410,10 +222,7 @@ login.login_handlers = (function() {
frappe.ready(function() {
-
login.bind_events();
- console.log("Why");
-
if (!window.location.hash) {
window.location.hash = "#login";
@@ -440,3 +249,103 @@ var verify_token = function(event) {
return false;
});
}
+
+var request_otp = function(r){
+ $('.login-content').empty().append($('
').attr({'id':'twofactor_div'}).html(
+ '
'));
+ // add event handler for submit button
+ verify_token();
+}
+
+var continue_otp_app = function(setup, qrcode){
+ request_otp();
+ var qrcode_div = $('
').attr({'id':'qrcode_div','style':'text-align:center;padding-bottom:15px;'});
+
+ if (!setup){
+ direction = $('
').attr('id','qr_info').text('Scan QR Code and enter the resulting code displayed' ),
+ qrimg = $('
').attr({
+ 'src':'data:image/svg+xml;base64,' + qrcode,
+ 'style':'width:250px;height:250px;'});
+
+ qrcode_div.append(direction);
+ qrcode_div.append(qrimg);
+ $('#otp_div').prepend(qrcode_div);
+ } else {
+ direction = $('
').attr('id','qr_info').text('Enter Code displayed in OTP App');
+ qrcode_div.append(direction);
+ $('#otp_div').prepend(qrcode_div);
+ }
+}
+
+var continue_sms = function(setup, prompt){
+ request_otp();
+ var sms_div = $('
').attr({'id':'sms_div','style':'padding-bottom:15px;text-align:center;'});
+
+ if (!setup){
+ direction = $('
').attr('id','sms_info').text('Enter phone number to send verification code');
+ sms_div.append(direction);
+ sms_div.append($('
').attr({'id':'sms_code_div'}).html(
+ '
\
+ \
+ Send SMS \
+
'));
+
+ $('#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(
+ '
SMS sent.Enter verification code received
'
+ );
+ } else {
+ $('#sms_div').empty().append(
+ '
SMS not sent
'
+ );
+ }
+ }
+ });
+ })
+ } else {
+ direction = $('
').attr('id','qr_info').text(prompt || 'SMS not sent');
+ sms_div.append(direction);
+ $('#otp_div').prepend(sms_div)
+ }
+}
+
+var continue_email = function(setup, prompt){
+ request_otp();
+ var email_div = $('
').attr({'id':'email_div','style':'padding-bottom:15px;text-align:center;'});
+
+ if (!setup){
+ email_div.append('
Verification code email will be sent to registered email address. Enter code received below
')
+ $('#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(
+ '
Email not sent
'
+ );
+ }
+ }
+ });
+ } else {
+ var direction = $('
').attr('id','qr_info').text(prompt || 'Verification code email not sent');
+ email_div.append(direction);
+ $('#otp_div').prepend(email_div);
+ }
+}
\ No newline at end of file