Skip to content
Snippets Groups Projects
Commit 3f3c7b50 authored by Olivier Dony's avatar Olivier Dony
Browse files

[IMP] base, totp: simplify form layout and improve responsiveness


Some of the TOTP-related forms contained an attempt at making a centered
modal pop-up, using a bootstrap `card` that would also serve to
emphasize that the interaction was sensitive and security-related.
Some of the "footer buttons" were moved inside the form to make it
more obvious that they were part of the interaction flow.

However some of this caused breakages of responsiveness and did not yield
a really satisfactory result anyway.

This commit switches back to using regular non-centered forms. It looks
quite ugly because the content is better suited for a narrow modal, but
it means less surprises in terms of layout and less responsiveness
issues.

closes odoo/odoo#58541

closes odoo/odoo#58544

Signed-off-by: default avatarOlivier Dony (odo) <odo@openerp.com>
parent 963f0ed0
Branches
Tags
No related merge requests found
......@@ -42,7 +42,7 @@ tour.register('totp_tour_setup', {
trigger: 'button[name=totp_enable_wizard]',
}, {
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......@@ -126,7 +126,7 @@ tour.register('totp_login_enabled', {
trigger: 'button[name=totp_disable]',
}, {
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......@@ -225,7 +225,7 @@ tour.register('totp_admin_disables', {
trigger: 'a.dropdown-item:contains(Disable TOTP on users)'
}, { // enhanced security yo
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......
......@@ -20,12 +20,19 @@
<p class="alert alert-danger" t-if="error" role="alert">
<t t-esc="error"/>
</p>
<div t-attf-class="clearfix oe_login_buttons text-center mb-1 {{'pt-2' if form_small else 'pt-3'}}">
<div t-attf-class="clearfix oe_login_buttons text-center mb-1">
<button type="submit" class="btn btn-primary btn-block">
Verify
</button>
</div>
<div class="small mb-2 mt-2 text-muted">
<i class="fa fa-2x fa-mobile pull-left"/>
Open the two-factor authentication app on your
device to obtain a code and verify your identity
</div>
</form>
</div>
<div class="text-center pb-2 border-top">
<form method="POST" action="/web/session/logout" class="form-inline">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<button type="submit" class="btn btn-link btn-sm mb-2">
......
......@@ -55,7 +55,7 @@
<form>
<sheet>
<div class="row container">
<div class="col-lg-6 offset-lg-3 mb-3">
<div class="mb-3">
<h3 class="font-weight-bold">Scan this barcode with your app</h3>
<div>
Scan the image below with the authenticator app on your phone.<br/>
......@@ -72,7 +72,7 @@
</li>
</ul>
<!-- code outside list to have more horiz space on mobile -->
<div class="collapse" id="collapseTotpSecret">
<div class="collapse col-12 col-md-6" id="collapseTotpSecret">
<div class="card card-body">
<h3>Your two-factor secret:</h3>
<code class="text-center"><field name="secret"/></code>
......@@ -80,24 +80,27 @@
</div>
</div>
<field class="offset-1 offset-lg-2" name="qrcode" readonly="True" widget="image"/>
<field class="offset-1" name="qrcode" readonly="True" widget="image"/>
<h3 class="font-weight-bold">Enter the 6-digit code from your app</h3>
<div class="text-justify">
<div class="text-justify col-10 col-lg-6 px-0">
After scanning the barcode, the app will display a 6-digit code that you
should enter below. Don't worry if the code changes in the app,
it stays valid a bit longer.
</div>
<div class="mt-2">
<label for="code">Verification Code</label>
<field required="True" name="code"/>
<label for="code" class="col-4 col-md-12 px-0">Verification Code</label>
<field required="True" name="code" class="col-10 col-md-6 px-0"/>
</div>
<button type="object" name="enable" class="btn btn-primary"
string="Enable two-factor authentication"/>
</div>
</div>
</sheet>
<footer><!-- no buttons --></footer>
<footer>
<button type="object" name="enable" class="btn btn-primary"
string="Enable two-factor authentication"/>
<button string="Cancel" special="cancel"/>
</footer>
</form>
</field>
</record>
......
......@@ -13,7 +13,7 @@ function fromField(f, record) {
switch (f.getAttribute('name')) {
case 'qrcode':
const qrcode = document.createElement('img');
qrcode.setAttribute('class', 'img img-fluid offset-1 offset-lg-2');
qrcode.setAttribute('class', 'img img-fluid offset-1');
qrcode.setAttribute('src', 'data:image/png;base64,' + record['qrcode']);
return qrcode;
case 'url':
......@@ -24,7 +24,7 @@ function fromField(f, record) {
case 'code':
const code = document.createElement('input');
code.setAttribute('name', 'code');
code.setAttribute('class', 'form-control');
code.setAttribute('class', 'form-control col-10 col-md-6');
code.setAttribute('placeholder', '6-digit code');
code.required = true;
code.maxLength = 6;
......@@ -108,10 +108,6 @@ class Button {
// because Dialog doesnt' call() click on the descriptor object
this.click = this._click.bind(this);
}
if (!button_node.closest('footer')) {
// remove non-footer buttons, otherwise they will appear twice
button_node.parentNode.removeChild(button_node);
}
}
async _click() {
if (!this.input.reportValidity()) {
......@@ -191,7 +187,7 @@ publicWidget.registry.TOTPButton = publicWidget.Widget.extend({
codeInput.addEventListener('input', () => codeInput.setCustomValidity(''));
const buttons = [];
for(const button of body.querySelectorAll('button')) {
for(const button of doc.querySelectorAll('footer button')) {
buttons.push(new Button(this, model, record.id, codeInput, button));
}
......
......@@ -12,7 +12,7 @@ tour.register('totportal_tour_setup', {
trigger: 'button#auth_totp_portal_enable',
}, {
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......@@ -84,7 +84,7 @@ tour.register('totportal_login_enabled', {
trigger: 'button#auth_totp_portal_disable',
}, {
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......
......@@ -215,6 +215,9 @@ function handleCheckIdentity(rpc, wrapped) {
}
}, {
text: _t('Cancel'), close: true
}, {
text: _t('Forgot password?'), classes: 'btn btn-link',
click() { window.location.href = "/web/reset_password/"; }
}]
}).on('close', null, () => {
// unlink wizard object?
......
<templates xml:space="preserve">
<t t-name="portal.identitycheck">
<form>
<div class="row container">
<div class="col-10 offset-1">
<div class="card bg-dark my-b mx-5">
<div class="card-header">
<i class="fa fa-bell mx-2"/>
<span class="text-uppercase">Security Control</span>
</div>
<div class="card-body">
<a href="/web/reset_password/" class="float-right">Forgot password?</a>
<h4 class="card-title">Please confirm your password to continue</h4>
<p class="card-text">
This is necessary for security-related changes. The authorization will last for a few minutes.
</p>
<div>
<label for="password">Password</label>
<input class="form-control" autocomplete="current-password"
name="password" type="password" required="required"/>
</div>
</div>
</div>
</div>
<form string="Security Control">
<h3><strong>Please confirm your password to continue</strong></h3>
<p>This is necessary for security-related changes. The authorization will last for a few minutes.</p>
<div>
<label for="password" class="col-4 col-md-12 px-0">Password</label>
<input class="form-control col-10 col-md-6" autocomplete="current-password"
name="password" type="password" required="required"/>
</div>
</form>
</t>
......
......@@ -40,32 +40,19 @@
<field name="model">res.users.identitycheck</field>
<field name="arch" type="xml">
<form string="Security Control">
<sheet>
<div class="row container">
<div class="col-8 offset-2">
<div class="card bg-dark my-b mx-5">
<div class="card-header">
<span class="fa fa-bell mx-2" t-translation="off">&amp;nbsp;</span>
<span class="text-uppercase">Security Control</span>
</div>
<div class="card-body">
<a href="/web/reset_password/" class="float-right">Forgot password?</a>
<h4 class="card-title">Please confirm your password to continue</h4>
<p class="card-text">
This is necessary for security-related changes. The authorization will last for a few minutes.
</p>
<div>
<label for="password"/>
<field class="col-4" name="password" autocomplete="current-password"
required="True" password="True"/>
</div>
<button string="Confirm Password" type="object" name="run_check" class="btn btn-primary mt-3"/>
</div>
</div>
</div>
<sheet clas="bg-primary">
<h3><strong>Please confirm your password to continue</strong></h3>
<p>This is necessary for security-related changes. The authorization will last for a few minutes.</p>
<div>
<label for="password" class="col-4 col-md-12 px-0"/>
<field class="col-10 col-md-6 px-0" name="password" autocomplete="current-password" required="True" password="True"/>
</div>
<footer><!-- no buttons --></footer>
</sheet>
<footer>
<button string="Confirm Password" type="object" name="run_check" class="btn btn-primary"/>
<button string="Cancel" special="cancel" class="btn btn-secondary"/>
<a href="/web/reset_password/" class="btn btn-link" role="button">Forgot password?</a>
</footer>
</form>
</field>
</record>
......
......@@ -24,7 +24,7 @@ tour.register('apikeys_tour_setup', {
trigger: 'button:contains("New API Key")',
}, {
content: "Check that we have to enter enhanced security mode",
trigger: '.card-title:contains("confirm your password")',
trigger: 'div:contains("confirm your password")',
run: () => {},
}, {
content: "Input password",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment