diff --git a/powerdnsadmin/assets.py b/powerdnsadmin/assets.py index dfe79ff..e7c6354 100644 --- a/powerdnsadmin/assets.py +++ b/powerdnsadmin/assets.py @@ -23,6 +23,7 @@ css_login = Bundle('node_modules/bootstrap/dist/css/bootstrap.css', js_login = Bundle('node_modules/jquery/dist/jquery.js', 'node_modules/bootstrap/dist/js/bootstrap.js', 'node_modules/icheck/icheck.js', + 'custom/js/custom.js', filters=(ConcatFilter, 'jsmin'), output='generated/login.js') diff --git a/powerdnsadmin/models/user.py b/powerdnsadmin/models/user.py index f5e3556..ca0561b 100644 --- a/powerdnsadmin/models/user.py +++ b/powerdnsadmin/models/user.py @@ -8,6 +8,9 @@ import ldap.filter from flask import current_app from flask_login import AnonymousUserMixin from sqlalchemy import orm +import qrcode as qrc +import qrcode.image.svg as qrc_svg +from io import BytesIO from .base import db from .role import Role @@ -633,6 +636,13 @@ class User(db.Model): for q in query: accounts.append(q[1]) return accounts + + def get_qrcode_value(self): + img = qrc.make(self.get_totp_uri(), + image_factory=qrc_svg.SvgPathImage) + stream = BytesIO() + img.save(stream) + return stream.getvalue() def read_entitlements(self, key): @@ -794,7 +804,4 @@ def getUserInfo(DomainsOrAccounts): current=[] for DomainOrAccount in DomainsOrAccounts: current.append(DomainOrAccount.name) - return current - - - + return current \ No newline at end of file diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index 650d141..693418a 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -591,8 +591,7 @@ def authenticate_user(user, authenticator, remember=False): # Prepare user to enter /welcome screen, otherwise they won't have permission to do so def prepare_welcome_user(user_id): logout_user() - session['user_id'] = user_id - session['welcome'] = True + session['welcome_user_id'] = user_id @index_bp.route('/logout') def logout(): @@ -684,10 +683,8 @@ def register(): if Setting().get('verify_user_email'): send_account_verification(email) if Setting().get('otp_force') and Setting().get('otp_field_enabled'): - login_user(user) - current_user.update_profile(enable_otp=True) - user_id = current_user.id - prepare_welcome_user(user_id) + user.update_profile(enable_otp=True) + prepare_welcome_user(user.id) return redirect(url_for('index.welcome')) else: return redirect(url_for('index.login')) @@ -703,14 +700,11 @@ def register(): # Show welcome page on first login if otp_force is enabled @index_bp.route('/welcome', methods=['GET', 'POST']) def welcome(): - if 'welcome' not in session: + if 'welcome_user_id' not in session: return redirect(url_for('index.index')) - user_id = session['user_id'] - user = User(id = user_id) - login_user(user) - encoded_img_data = base64.b64encode(qrcode()[0]) - prepare_welcome_user(user_id) + user = User(id = session['welcome_user_id']) + encoded_img_data = base64.b64encode(user.get_qrcode_value()) if request.method == 'GET': return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user) @@ -722,7 +716,7 @@ def welcome(): return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user, error="Invalid token") else: return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user, error="Token required") - session.pop('welcome') + session.pop('welcome_user_id') return redirect(url_for('index.index')) @index_bp.route('/confirm/', methods=['GET']) diff --git a/powerdnsadmin/routes/user.py b/powerdnsadmin/routes/user.py index 6ca927b..f411c29 100644 --- a/powerdnsadmin/routes/user.py +++ b/powerdnsadmin/routes/user.py @@ -1,7 +1,4 @@ import datetime -import qrcode as qrc -import qrcode.image.svg as qrc_svg -from io import BytesIO from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, current_app from flask_login import current_user, login_required, login_manager @@ -94,13 +91,9 @@ def qrcode(): if not current_user: return redirect(url_for('index')) - img = qrc.make(current_user.get_totp_uri(), - image_factory=qrc_svg.SvgPathImage) - stream = BytesIO() - img.save(stream) - return stream.getvalue(), 200, { + return current_user.get_qrcode_value(), 200, { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' - } + } \ No newline at end of file diff --git a/powerdnsadmin/static/custom/js/custom.js b/powerdnsadmin/static/custom/js/custom.js index 9bd9669..395e1ac 100644 --- a/powerdnsadmin/static/custom/js/custom.js +++ b/powerdnsadmin/static/custom/js/custom.js @@ -285,4 +285,14 @@ function timer(elToUpdate, maxTime) { }, 1000); return interval; -} \ No newline at end of file +} + +// copy otp secret code to clipboard +function copy_otp_secret_to_clipboard() { + var copyBox = document.getElementById("otp_secret"); + copyBox.select(); + copyBox.setSelectionRange(0, 99999); /* For mobile devices */ + navigator.clipboard.writeText(copyBox.value); + $("#copy_tooltip").css("visibility", "visible"); + setTimeout(function(){ $("#copy_tooltip").css("visibility", "collapse"); }, 2000); + } \ No newline at end of file diff --git a/powerdnsadmin/templates/register_otp.html b/powerdnsadmin/templates/register_otp.html index 2777b4f..68e7ab8 100755 --- a/powerdnsadmin/templates/register_otp.html +++ b/powerdnsadmin/templates/register_otp.html @@ -41,7 +41,7 @@ Your secret key is:
- +
Copied.

@@ -87,15 +87,4 @@ {% assets "js_validation" -%} {%- endassets %} - \ No newline at end of file diff --git a/powerdnsadmin/templates/user_profile.html b/powerdnsadmin/templates/user_profile.html index 1d2a0e5..8570f7e 100644 --- a/powerdnsadmin/templates/user_profile.html +++ b/powerdnsadmin/templates/user_profile.html @@ -97,7 +97,7 @@ Your secret key is:
- +
Copied.
@@ -160,15 +160,5 @@ }; applyChanges(postdata, $SCRIPT_ROOT + '/user/profile', false, true); }); - - // copy otp secret code to clipboard - function copy_to_clickboard() { - var copyBox = document.getElementById("otp_secret"); - copyBox.select(); - copyBox.setSelectionRange(0, 99999); /* For mobile devices */ - navigator.clipboard.writeText(copyBox.value); - $("#copy_tooltip").css("visibility", "visible"); - setTimeout(function(){ $("#copy_tooltip").css("visibility", "collapse"); }, 2000); - } {% endblock %}