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
|
# Two Factor Auth
|
||||||
|
|
||||||
@app.route('/two-factor-auth/status', methods=['GET'])
|
@app.route('/2fa/status', methods=['GET'])
|
||||||
@authorized_personnel_only
|
@authorized_personnel_only
|
||||||
def two_factor_auth_get_status():
|
def two_factor_auth_get_status():
|
||||||
email, privs = auth_service.authenticate(request, env)
|
email, _ = auth_service.authenticate(request, env)
|
||||||
two_factor_secret, two_factor_token = get_two_factor_info(email, env)
|
two_factor_secret, _ = get_two_factor_info(email, env)
|
||||||
|
|
||||||
if two_factor_secret != None:
|
if two_factor_secret != None:
|
||||||
return json_response({ 'status': 'on' })
|
return json_response({
|
||||||
|
"type": 'totp'
|
||||||
|
})
|
||||||
|
|
||||||
secret = totp.get_secret()
|
secret = totp.get_secret()
|
||||||
secret_url = totp.get_otp_uri(secret, email)
|
secret_url = totp.get_otp_uri(secret, email)
|
||||||
secret_qr = totp.get_qr_code(secret_url)
|
secret_qr = totp.get_qr_code(secret_url)
|
||||||
|
|
||||||
return json_response({
|
return json_response({
|
||||||
"status": 'off',
|
"type": None,
|
||||||
"secret": secret,
|
"totp_secret": secret,
|
||||||
"qr_code": secret_qr
|
"totp_qr": secret_qr
|
||||||
})
|
})
|
||||||
|
|
||||||
@app.route('/two-factor-auth/setup', methods=['POST'])
|
@app.route('/2fa/totp/enable', methods=['POST'])
|
||||||
@authorized_personnel_only
|
@authorized_personnel_only
|
||||||
def two_factor_auth_post_setup():
|
def totp_post_enable():
|
||||||
email, privs = auth_service.authenticate(request, env)
|
email, _ = auth_service.authenticate(request, env)
|
||||||
|
|
||||||
secret = request.form.get('secret')
|
secret = request.form.get('secret')
|
||||||
token = request.form.get('token')
|
token = request.form.get('token')
|
||||||
|
@ -448,10 +450,10 @@ def two_factor_auth_post_setup():
|
||||||
|
|
||||||
return json_response({ "error": 'token_mismatch' }, 400)
|
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
|
@authorized_personnel_only
|
||||||
def two_factor_auth_post_disable():
|
def totp_post_disable():
|
||||||
email, privs = auth_service.authenticate(request, env)
|
email, _ = auth_service.authenticate(request, env)
|
||||||
remove_two_factor_secret(email, env)
|
remove_two_factor_secret(email, env)
|
||||||
return json_response({})
|
return json_response({})
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
{% include "two-factor-auth.html" %}
|
{% include "two-factor-auth.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="panel_login" class="admin_panel">
|
<div id="panel_login" class="admin_panel">
|
||||||
{% include "login.html" %}
|
{% include "login.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<style>
|
<style>
|
||||||
.twofactor #setup-2fa,
|
.twofactor #totp-setup,
|
||||||
.twofactor #disable-2fa,
|
.twofactor #disable-2fa,
|
||||||
.twofactor #output-2fa {
|
.twofactor #output-2fa {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -10,16 +10,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.twofactor.disabled #disable-2fa,
|
.twofactor.disabled #disable-2fa,
|
||||||
.twofactor.enabled #setup-2fa {
|
.twofactor.enabled #totp-setup {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.twofactor.disabled #setup-2fa,
|
.twofactor.disabled #totp-setup,
|
||||||
.twofactor.enabled #disable-2fa {
|
.twofactor.enabled #disable-2fa {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.twofactor #qr-2fa img {
|
.twofactor #totp-setup-qr img {
|
||||||
display: block;
|
display: block;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
@ -36,23 +36,23 @@
|
||||||
<div class="twofactor">
|
<div class="twofactor">
|
||||||
<div class="loading-indicator">Loading...</div>
|
<div class="loading-indicator">Loading...</div>
|
||||||
|
|
||||||
<form id="setup-2fa">
|
<form id="totp-setup">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<h3>Setup</h3>
|
<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>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>
|
<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>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="otp">2. Enter the code displayed in the Authenticator app</label>
|
<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>
|
</div>
|
||||||
|
|
||||||
<input type="hidden" id="setup-secret" />
|
<input type="hidden" id="totp-setup-secret" />
|
||||||
|
|
||||||
<div class="form-group">
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -73,11 +73,11 @@
|
||||||
var el = {
|
var el = {
|
||||||
disableForm: document.getElementById('disable-2fa'),
|
disableForm: document.getElementById('disable-2fa'),
|
||||||
output: document.getElementById('output-2fa'),
|
output: document.getElementById('output-2fa'),
|
||||||
setupForm: document.getElementById('setup-2fa'),
|
totpSetupForm: document.getElementById('totp-setup'),
|
||||||
setupInputOtp: document.getElementById('setup-otp'),
|
totpSetupToken: document.getElementById('totp-setup-token'),
|
||||||
setupInputSecret: document.getElementById('setup-secret'),
|
totpSetupSecret: document.getElementById('totp-setup-secret'),
|
||||||
setupQr: document.getElementById('qr-2fa'),
|
totpQr: document.getElementById('totp-setup-qr'),
|
||||||
setupSubmit: document.querySelector('#setup-2fa button[type="submit"]'),
|
totpSetupSubmit: document.querySelector('#totp-setup-submit'),
|
||||||
wrapper: document.querySelector('.twofactor')
|
wrapper: document.querySelector('.twofactor')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,35 +86,35 @@
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof val !== 'string' ||
|
typeof val !== 'string' ||
|
||||||
typeof el.setupInputSecret.value !== 'string' ||
|
typeof el.totpSetupSecret.value !== 'string' ||
|
||||||
val.length !== 6 ||
|
val.length !== 6 ||
|
||||||
el.setupInputSecret.value.length !== 32 ||
|
el.totpSetupSecret.value.length !== 32 ||
|
||||||
!(/^\+?\d+$/.test(val))
|
!(/^\+?\d+$/.test(val))
|
||||||
) {
|
) {
|
||||||
el.setupSubmit.setAttribute('disabled', '');
|
el.totpSetupSubmit.setAttribute('disabled', '');
|
||||||
} else {
|
} else {
|
||||||
el.setupSubmit.removeAttribute('disabled');
|
el.totpSetupSubmit.removeAttribute('disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function render_setup(res) {
|
function render_totp_setup(res) {
|
||||||
function render_qr_code(encoded) {
|
function render_qr_code(encoded) {
|
||||||
var img = document.createElement('img');
|
var img = document.createElement('img');
|
||||||
img.src = encoded;
|
img.src = encoded;
|
||||||
|
|
||||||
var code = document.createElement('div');
|
var code = document.createElement('div');
|
||||||
code.innerHTML = `Secret: ${res.secret}`;
|
code.innerHTML = `Secret: ${res.totp_secret}`;
|
||||||
|
|
||||||
el.setupQr.appendChild(img);
|
el.totpQr.appendChild(img);
|
||||||
el.setupQr.appendChild(code);
|
el.totpQr.appendChild(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
el.setupInputOtp.addEventListener('input', update_setup_disabled);
|
el.totpSetupToken.addEventListener('input', update_setup_disabled);
|
||||||
el.setupForm.addEventListener('submit', do_setup);
|
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');
|
el.wrapper.classList.add('disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,27 +140,27 @@
|
||||||
|
|
||||||
hide_error();
|
hide_error();
|
||||||
|
|
||||||
el.setupForm.reset();
|
el.totpSetupForm.reset();
|
||||||
el.setupForm.removeEventListener('submit', do_setup);
|
el.totpSetupForm.removeEventListener('submit', do_enable_totp);
|
||||||
|
|
||||||
el.setupInputSecret.setAttribute('value', '');
|
el.totpSetupSecret.setAttribute('value', '');
|
||||||
el.setupInputOtp.removeEventListener('input', update_setup_disabled);
|
el.totpSetupToken.removeEventListener('input', update_setup_disabled);
|
||||||
|
|
||||||
el.setupSubmit.setAttribute('disabled', '');
|
el.totpSetupSubmit.setAttribute('disabled', '');
|
||||||
el.setupQr.innerHTML = '';
|
el.totpQr.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_two_factor_auth() {
|
function show_two_factor_auth() {
|
||||||
reset_view();
|
reset_view();
|
||||||
|
|
||||||
api(
|
api(
|
||||||
'/two-factor-auth/status',
|
'/2fa/status',
|
||||||
'GET',
|
'GET',
|
||||||
{},
|
{},
|
||||||
function(res) {
|
function(res) {
|
||||||
el.wrapper.classList.add('loaded');
|
el.wrapper.classList.add('loaded');
|
||||||
var isEnabled = res.status === 'on'
|
var isTotpEnabled = res.type === 'totp'
|
||||||
return isEnabled ? render_disable(res) : render_setup(res);
|
return isTotpEnabled ? render_disable(res) : render_totp_setup(res);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
hide_error();
|
hide_error();
|
||||||
|
|
||||||
api(
|
api(
|
||||||
'/two-factor-auth/disable',
|
'/2fa/totp/disable',
|
||||||
'POST',
|
'POST',
|
||||||
{},
|
{},
|
||||||
function() { show_two_factor_auth(); }
|
function() { show_two_factor_auth(); }
|
||||||
|
@ -179,16 +179,16 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function do_setup(evt) {
|
function do_enable_totp(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
hide_error();
|
hide_error();
|
||||||
|
|
||||||
api(
|
api(
|
||||||
'/two-factor-auth/setup',
|
'/2fa/totp/enable',
|
||||||
'POST',
|
'POST',
|
||||||
{
|
{
|
||||||
token: $(el.setupInputOtp).val(),
|
token: $(el.totpSetupToken).val(),
|
||||||
secret: $(el.setupInputSecret).val()
|
secret: $(el.totpSetupSecret).val()
|
||||||
},
|
},
|
||||||
function(res) { show_two_factor_auth(); },
|
function(res) { show_two_factor_auth(); },
|
||||||
function(res) {
|
function(res) {
|
||||||
|
|
Loading…
Reference in New Issue