From 4b84a1a5728b3faabbba1d126fc7766cab6421cb Mon Sep 17 00:00:00 2001 From: B H Boma Date: Tue, 18 Jul 2017 10:39:44 +0100 Subject: [PATCH] [fix] Qrcode not visible for twofactor auth --- frappe/auth.py | 47 +++++++++++++----------- frappe/public/build.json | 3 -- frappe/templates/includes/login/login.js | 21 ++++------- frappe/www/login.py | 18 +-------- 4 files changed, 34 insertions(+), 55 deletions(-) diff --git a/frappe/auth.py b/frappe/auth.py index 39578fead8..7cb903e30e 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -17,7 +17,6 @@ from frappe.translate import get_lang_code from frappe.utils.password import check_password from frappe.core.doctype.authentication_log.authentication_log import add_authentication_log -from erpnext.setup.doctype.sms_settings.sms_settings import send_request from urllib import quote @@ -130,28 +129,16 @@ class LoginManager: self.authenticate() # after authenticate, self.user is set (from check_password() call) user_obj = frappe.get_doc('User', self.user) - two_factor_auth_user = len(frappe.db.sql("""select name from `tabRole` where two_factor_auth=1 - and name in ({0}) limit 1""".format(', '.join(['%s'] * len(user_obj.roles))), - [d.role for d in user_obj.roles])) + two_factor_auth_user = 0 + if user_obj.roles: + 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_auth_user = len(frappe.db.sql(query)) + if two_factor_auth_user == 1: otp_secret = frappe.db.get_default(self.user + '_otpsecret') - - #restrict_method = frappe.db.get_value('System Settings', None, 'fix_2fa_method') - #verification_meth = frappe.db.get_value('User', self.user, 'two_factor_method') - #fixed_method = [frappe._dict()] - - #if int(restrict_method): - # try: - # fixed_method = frappe.db.sql('''SELECT DEFAULT(two_factor_method) AS 'default_method' FROM - # (SELECT 1) AS dummy LEFT JOIN tabUser on True LIMIT 1;''', as_dict=1) - # except OperationalError: - # pass - - #if not verification_meth: - # verification_method = fixed_method[0].default_method or 'OTP App' - #else: - # verification_method = fixed_method[0].default_method or verification_meth verification_method = frappe.db.get_value('System Settings', None, 'two_factor_method') if otp_secret: @@ -175,7 +162,8 @@ class LoginManager: verification_obj = {'token_delivery': True, 'prompt': False, 'totp_uri': totp_uri, - 'method': 'OTP App'} + 'method': 'OTP App', + 'qrcode':get_qr_svg_code(totp_uri)} elif verification_method == 'Email': status = self.send_token_via_email(token=token,otpsecret=otp_secret) verification_obj = {'token_delivery': status, @@ -197,6 +185,7 @@ class LoginManager: 'token_delivery': True, 'prompt': False, 'totp_uri': totp_uri, + 'qrcode':get_qr_svg_code(totp_uri) #'restrict_method': int(restrict_method) and (fixed_method[0].default_method or 'OTP App') } @@ -420,6 +409,10 @@ class LoginManager: clear_cookies() 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 ss = frappe.get_doc('SMS Settings', 'SMS Settings') if not ss.sms_gateway_url: return False @@ -499,3 +492,15 @@ def get_website_user_home_page(user): return '/' + home_page.strip('/') else: return '/me' + +def get_qr_svg_code(totp_uri): + '''Get SVG code to display Qrcode for OTP.''' + from pyqrcode import create as qrcreate + from StringIO import StringIO + from base64 import b64encode + url = qrcreate(totp_uri) + stream = StringIO() + url.svg(stream, scale=5) + svg = stream.getvalue().replace('\n','') + svg = b64encode(bytes(svg)) + return svg diff --git a/frappe/public/build.json b/frappe/public/build.json index 082fbf5a71..75e4e76469 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -22,9 +22,6 @@ "website/js/website.js", "public/js/frappe/misc/rating_icons.html" ], - "js/qrious.min.js": [ - "public/js/frappe/qrious.min.js" - ], "js/dialog.min.js": [ "public/js/frappe/dom.js", "public/js/frappe/ui/modal.html", diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js index 997e058c6e..d460a4e62a 100644 --- a/frappe/templates/includes/login/login.js +++ b/frappe/templates/includes/login/login.js @@ -174,24 +174,17 @@ login.login_handlers = (function() { verify_token(); if (!setup_completed){ - var qrcode = $('
').attr('id','qrcode_div'); + 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 qrcanvas = $(''); - qrcanvas.attr('id','qrcanvass'); + var qrimg = $(''); + qrimg.attr('src','data:image/svg+xml;base64,' + data.verification.qrcode); qrcode.append(direction); - qrcode.append(qrcanvas); - $('#otp_div').prepend(qrcode) - qr = new QRious({ - element: document.getElementById('qrcanvass'), - value: data.verification.totp_uri, - background: 'white', // background color - foreground: 'black', // foreground color - level: 'L', // Error correction level of the QR code - mime: 'image/png', // MIME type used to render - size: 200 - }); + 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'); diff --git a/frappe/www/login.py b/frappe/www/login.py index e81c7bcb78..5002a44b35 100644 --- a/frappe/www/login.py +++ b/frappe/www/login.py @@ -12,23 +12,9 @@ from frappe.integrations.doctype.ldap_settings.ldap_settings import get_ldap_set no_cache = True -import pyqrcode -from StringIO import StringIO -from werkzeug.wrappers import Response - -def get_qr_code(): - - url = pyqrcode.create('http://www.google.com') - stream = StringIO() - url.svg(stream, scale=5) - responses = Response(stream.getvalue().encode('utf-8')) - responses.status_code = 200 - responses.headers['content-type'] = 'image/svg+xml; charset=utf-8' - return responses - def get_context(context): if frappe.session.user != "Guest" and frappe.session.data.user_type=="System User": - frappe.local.flags.redirect_location = "/testpayment" + frappe.local.flags.redirect_location = "/desk" raise frappe.Redirect # get settings from site config @@ -44,7 +30,6 @@ def get_context(context): ldap_settings = get_ldap_settings() context["ldap_settings"] = ldap_settings - context['qqrcode'] = frappe.render_template(get_qr_code()) return context @@ -83,4 +68,3 @@ def login_via_token(login_token): frappe.local.login_manager = LoginManager() redirect_post_login(desk_user = frappe.db.get_value("User", frappe.session.user, "user_type")=="System User") -