mirror of
				https://github.com/mail-in-a-box/mailinabox.git
				synced 2025-11-03 19:30:54 +00:00 
			
		
		
		
	Update API route naming, update setup page
* Rename /two-factor-auth/ => /2fa/ * Nest totp routes under /2fa/totp/ * Update ids and methods in panel to allow for different setup types
This commit is contained in:
		
							parent
							
								
									f205c48564
								
							
						
					
					
						commit
						8597646a12
					
				@ -412,29 +412,31 @@ def ssl_provision_certs():
 | 
			
		||||
 | 
			
		||||
# Two Factor Auth
 | 
			
		||||
 | 
			
		||||
@app.route('/two-factor-auth/status', methods=['GET'])
 | 
			
		||||
@app.route('/2fa/status', methods=['GET'])
 | 
			
		||||
@authorized_personnel_only
 | 
			
		||||
def two_factor_auth_get_status():
 | 
			
		||||
	email, privs = auth_service.authenticate(request, env)
 | 
			
		||||
	two_factor_secret, two_factor_token = get_two_factor_info(email, env)
 | 
			
		||||
	email, _ = auth_service.authenticate(request, env)
 | 
			
		||||
	two_factor_secret, _ = get_two_factor_info(email, env)
 | 
			
		||||
 | 
			
		||||
	if two_factor_secret != None:
 | 
			
		||||
		return json_response({ 'status': 'on' })
 | 
			
		||||
		return json_response({
 | 
			
		||||
			"type": 'totp'
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	secret = totp.get_secret()
 | 
			
		||||
	secret_url = totp.get_otp_uri(secret, email)
 | 
			
		||||
	secret_qr = totp.get_qr_code(secret_url)
 | 
			
		||||
 | 
			
		||||
	return json_response({
 | 
			
		||||
		"status": 'off',
 | 
			
		||||
		"secret": secret,
 | 
			
		||||
		"qr_code": secret_qr
 | 
			
		||||
		"type": None,
 | 
			
		||||
		"totp_secret": secret,
 | 
			
		||||
		"totp_qr": secret_qr
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
@app.route('/two-factor-auth/setup', methods=['POST'])
 | 
			
		||||
@app.route('/2fa/totp/enable', methods=['POST'])
 | 
			
		||||
@authorized_personnel_only
 | 
			
		||||
def two_factor_auth_post_setup():
 | 
			
		||||
	email, privs = auth_service.authenticate(request, env)
 | 
			
		||||
def totp_post_enable():
 | 
			
		||||
	email, _ = auth_service.authenticate(request, env)
 | 
			
		||||
 | 
			
		||||
	secret = request.form.get('secret')
 | 
			
		||||
	token = request.form.get('token')
 | 
			
		||||
@ -448,10 +450,10 @@ def two_factor_auth_post_setup():
 | 
			
		||||
 | 
			
		||||
	return json_response({ "error": 'token_mismatch' }, 400)
 | 
			
		||||
 | 
			
		||||
@app.route('/two-factor-auth/disable', methods=['POST'])
 | 
			
		||||
@app.route('/2fa/totp/disable', methods=['POST'])
 | 
			
		||||
@authorized_personnel_only
 | 
			
		||||
def two_factor_auth_post_disable():
 | 
			
		||||
	email, privs = auth_service.authenticate(request, env)
 | 
			
		||||
def totp_post_disable():
 | 
			
		||||
	email, _ = auth_service.authenticate(request, env)
 | 
			
		||||
	remove_two_factor_secret(email, env)
 | 
			
		||||
	return json_response({})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -136,7 +136,7 @@
 | 
			
		||||
      {% include "two-factor-auth.html" %}
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
        <div id="panel_login" class="admin_panel">
 | 
			
		||||
      <div id="panel_login" class="admin_panel">
 | 
			
		||||
      {% include "login.html" %}
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<style>
 | 
			
		||||
    .twofactor #setup-2fa,
 | 
			
		||||
    .twofactor #totp-setup,
 | 
			
		||||
    .twofactor #disable-2fa,
 | 
			
		||||
    .twofactor #output-2fa {
 | 
			
		||||
        display: none;
 | 
			
		||||
@ -10,16 +10,16 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .twofactor.disabled #disable-2fa,
 | 
			
		||||
    .twofactor.enabled #setup-2fa {
 | 
			
		||||
    .twofactor.enabled #totp-setup {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .twofactor.disabled #setup-2fa,
 | 
			
		||||
    .twofactor.disabled #totp-setup,
 | 
			
		||||
    .twofactor.enabled #disable-2fa {
 | 
			
		||||
        display: block;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .twofactor #qr-2fa img {
 | 
			
		||||
    .twofactor #totp-setup-qr img {
 | 
			
		||||
        display: block;
 | 
			
		||||
        width: 256px;
 | 
			
		||||
        max-width: 100%;
 | 
			
		||||
@ -36,23 +36,23 @@
 | 
			
		||||
<div class="twofactor">
 | 
			
		||||
    <div class="loading-indicator">Loading...</div>
 | 
			
		||||
 | 
			
		||||
    <form id="setup-2fa">
 | 
			
		||||
    <form id="totp-setup">
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <h3>Setup</h3>
 | 
			
		||||
            <p>After enabling two factor authentication, any login to the admin panel will require you to enter a time-limited 6-digit number from an authenticator app after entering your normal credentials.</p>
 | 
			
		||||
            <p>1. Scan the QR code or enter the secret into an authenticator app (e.g. Google Authenticator)</p>
 | 
			
		||||
            <div id="qr-2fa"></div>
 | 
			
		||||
            <div id="totp-setup-qr"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label for="otp">2. Enter the code displayed in the Authenticator app</label>
 | 
			
		||||
            <input type="text" id="setup-otp" class="form-control" placeholder="6-digit code" />
 | 
			
		||||
            <input type="text" id="totp-setup-token" class="form-control" placeholder="6-digit code" />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <input type="hidden" id="setup-secret" />
 | 
			
		||||
        <input type="hidden" id="totp-setup-secret" />
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <button id="setup-submit" disabled type="submit" class="btn">Enable two factor authentication</button>
 | 
			
		||||
            <button id="totp-setup-submit" disabled type="submit" class="btn">Enable two factor authentication</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
@ -73,11 +73,11 @@
 | 
			
		||||
    var el = {
 | 
			
		||||
        disableForm: document.getElementById('disable-2fa'),
 | 
			
		||||
        output: document.getElementById('output-2fa'),
 | 
			
		||||
        setupForm: document.getElementById('setup-2fa'),
 | 
			
		||||
        setupInputOtp: document.getElementById('setup-otp'),
 | 
			
		||||
        setupInputSecret: document.getElementById('setup-secret'),
 | 
			
		||||
        setupQr: document.getElementById('qr-2fa'),
 | 
			
		||||
        setupSubmit: document.querySelector('#setup-2fa button[type="submit"]'),
 | 
			
		||||
        totpSetupForm: document.getElementById('totp-setup'),
 | 
			
		||||
        totpSetupToken: document.getElementById('totp-setup-token'),
 | 
			
		||||
        totpSetupSecret: document.getElementById('totp-setup-secret'),
 | 
			
		||||
        totpQr: document.getElementById('totp-setup-qr'),
 | 
			
		||||
        totpSetupSubmit: document.querySelector('#totp-setup-submit'),
 | 
			
		||||
        wrapper: document.querySelector('.twofactor')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -86,35 +86,35 @@
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
            typeof val !== 'string' ||
 | 
			
		||||
            typeof el.setupInputSecret.value !== 'string' ||
 | 
			
		||||
            typeof el.totpSetupSecret.value !== 'string' ||
 | 
			
		||||
            val.length !== 6 ||
 | 
			
		||||
            el.setupInputSecret.value.length !== 32 ||
 | 
			
		||||
            el.totpSetupSecret.value.length !== 32 ||
 | 
			
		||||
            !(/^\+?\d+$/.test(val))
 | 
			
		||||
        ) {
 | 
			
		||||
            el.setupSubmit.setAttribute('disabled', '');
 | 
			
		||||
            el.totpSetupSubmit.setAttribute('disabled', '');
 | 
			
		||||
        } else {
 | 
			
		||||
            el.setupSubmit.removeAttribute('disabled');
 | 
			
		||||
            el.totpSetupSubmit.removeAttribute('disabled');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function render_setup(res) {
 | 
			
		||||
    function render_totp_setup(res) {
 | 
			
		||||
        function render_qr_code(encoded) {
 | 
			
		||||
            var img = document.createElement('img');
 | 
			
		||||
            img.src = encoded;
 | 
			
		||||
 | 
			
		||||
            var code = document.createElement('div');
 | 
			
		||||
            code.innerHTML = `Secret: ${res.secret}`;
 | 
			
		||||
            code.innerHTML = `Secret: ${res.totp_secret}`;
 | 
			
		||||
 | 
			
		||||
            el.setupQr.appendChild(img);
 | 
			
		||||
            el.setupQr.appendChild(code);
 | 
			
		||||
            el.totpQr.appendChild(img);
 | 
			
		||||
            el.totpQr.appendChild(code);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        el.setupInputOtp.addEventListener('input', update_setup_disabled);
 | 
			
		||||
        el.setupForm.addEventListener('submit', do_setup);
 | 
			
		||||
        el.totpSetupToken.addEventListener('input', update_setup_disabled);
 | 
			
		||||
        el.totpSetupForm.addEventListener('submit', do_enable_totp);
 | 
			
		||||
 | 
			
		||||
        el.setupInputSecret.setAttribute('value', res.secret);
 | 
			
		||||
        el.totpSetupSecret.setAttribute('value', res.totp_secret);
 | 
			
		||||
        render_qr_code(res.totp_qr);
 | 
			
		||||
 | 
			
		||||
        render_qr_code(res.qr_code);
 | 
			
		||||
        el.wrapper.classList.add('disabled');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -140,27 +140,27 @@
 | 
			
		||||
 | 
			
		||||
        hide_error();
 | 
			
		||||
 | 
			
		||||
        el.setupForm.reset();
 | 
			
		||||
        el.setupForm.removeEventListener('submit', do_setup);
 | 
			
		||||
        el.totpSetupForm.reset();
 | 
			
		||||
        el.totpSetupForm.removeEventListener('submit', do_enable_totp);
 | 
			
		||||
 | 
			
		||||
        el.setupInputSecret.setAttribute('value', '');
 | 
			
		||||
        el.setupInputOtp.removeEventListener('input', update_setup_disabled);
 | 
			
		||||
        el.totpSetupSecret.setAttribute('value', '');
 | 
			
		||||
        el.totpSetupToken.removeEventListener('input', update_setup_disabled);
 | 
			
		||||
 | 
			
		||||
        el.setupSubmit.setAttribute('disabled', '');
 | 
			
		||||
        el.setupQr.innerHTML = '';
 | 
			
		||||
        el.totpSetupSubmit.setAttribute('disabled', '');
 | 
			
		||||
        el.totpQr.innerHTML = '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function show_two_factor_auth() {
 | 
			
		||||
        reset_view();
 | 
			
		||||
 | 
			
		||||
        api(
 | 
			
		||||
            '/two-factor-auth/status',
 | 
			
		||||
            '/2fa/status',
 | 
			
		||||
            'GET',
 | 
			
		||||
            {},
 | 
			
		||||
            function(res) {
 | 
			
		||||
                el.wrapper.classList.add('loaded');
 | 
			
		||||
                var isEnabled = res.status === 'on'
 | 
			
		||||
                return isEnabled ? render_disable(res) : render_setup(res);
 | 
			
		||||
                var isTotpEnabled = res.type === 'totp'
 | 
			
		||||
                return isTotpEnabled ? render_disable(res) : render_totp_setup(res);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -170,7 +170,7 @@
 | 
			
		||||
        hide_error();
 | 
			
		||||
 | 
			
		||||
        api(
 | 
			
		||||
            '/two-factor-auth/disable',
 | 
			
		||||
            '/2fa/totp/disable',
 | 
			
		||||
            'POST',
 | 
			
		||||
            {},
 | 
			
		||||
            function() { show_two_factor_auth(); }
 | 
			
		||||
@ -179,16 +179,16 @@
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function do_setup(evt) {
 | 
			
		||||
    function do_enable_totp(evt) {
 | 
			
		||||
        evt.preventDefault();
 | 
			
		||||
        hide_error();
 | 
			
		||||
 | 
			
		||||
        api(
 | 
			
		||||
            '/two-factor-auth/setup',
 | 
			
		||||
            '/2fa/totp/enable',
 | 
			
		||||
            'POST',
 | 
			
		||||
            {
 | 
			
		||||
                token: $(el.setupInputOtp).val(),
 | 
			
		||||
                secret: $(el.setupInputSecret).val()
 | 
			
		||||
                token: $(el.totpSetupToken).val(),
 | 
			
		||||
                secret: $(el.totpSetupSecret).val()
 | 
			
		||||
            },
 | 
			
		||||
            function(res) { show_two_factor_auth(); },
 | 
			
		||||
            function(res) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user