feat(2fa): updated and UI fixes
- configure 2fa - setup 2fa - various small improvements
This commit is contained in:
parent
0628f37e75
commit
aad99df521
4 changed files with 56 additions and 52 deletions
|
|
@ -34,7 +34,7 @@ from pyramid.renderers import render
|
|||
from pyramid.response import Response
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
|
||||
import rhodecode
|
||||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.authentication.base import authenticate, HTTP_TYPE
|
||||
from rhodecode.authentication.plugins import auth_rhodecode
|
||||
|
|
@ -510,9 +510,10 @@ class LoginView(BaseAppView):
|
|||
# only then we should persist it
|
||||
secret = user_instance.init_secret_2fa(persist=False)
|
||||
|
||||
totp_name = f'RhodeCode token ({self.request.user.username})'
|
||||
instance_name = rhodecode.ConfigGet().get_str('app.base_url', 'rhodecode')
|
||||
totp_name = f'{instance_name}:{self.request.user.username}'
|
||||
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
||||
qr = qrcode.QRCode(version=1, box_size=5, border=4)
|
||||
qr.add_data(pyotp.totp.TOTP(secret).provisioning_uri(name=totp_name))
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color='black', back_color='white')
|
||||
|
|
|
|||
|
|
@ -919,7 +919,7 @@ class User(Base, BaseModel):
|
|||
return ''
|
||||
|
||||
def get_secret_2fa(self) -> str:
|
||||
secret_2fa = self.user_data['secret_2fa']
|
||||
secret_2fa = self.user_data.get('secret_2fa')
|
||||
if secret_2fa:
|
||||
strict_mode = ConfigGet().get_bool('rhodecode.encrypted_values.strict', missing=True)
|
||||
return safe_str(
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@
|
|||
· ${h.branding(c.rhodecode_name)}
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
<style>body{background-color:#eeeeee;}</style>
|
||||
|
||||
<div class="loginbox">
|
||||
<div class="loginbox" style="width: 600px">
|
||||
|
||||
<div class="header-account">
|
||||
<div id="header-inner" class="title">
|
||||
<div id="logo">
|
||||
|
|
@ -22,66 +24,67 @@
|
|||
</div>
|
||||
|
||||
<div class="loginwrapper">
|
||||
<h1>${_('Setup the authenticator app')}</h1>
|
||||
|
||||
<p>Authenticator apps like <a href='https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2' target="_blank" rel="noopener noreferrer">Google Authenticator</a>, etc. generate one-time passwords that are used as a second factor to verify you identity.</p>
|
||||
<rhodecode-toast id="notifications"></rhodecode-toast>
|
||||
|
||||
<div id="setup_2fa">
|
||||
<div class="sign-in-title">
|
||||
<h1>${_('Set up the authenticator app')} - ${_('scan the QR code')}</h1>
|
||||
</div>
|
||||
<div class="inner form">
|
||||
${h.secure_form(h.route_path('setup_2fa'), request=request, id='totp_form')}
|
||||
<div class="sign-in-title">
|
||||
<h1>${_('Scan the QR code')}: "${totp_name}"</h1>
|
||||
</div>
|
||||
<p>${_('Use an authenticator app to scan.')}</p>
|
||||
<img alt="qr-code" src="data:image/png;base64, ${qr}"/>
|
||||
<strong>${_('Use an authenticator app to scan.')}</strong><br/>
|
||||
|
||||
<p>${_('Unable to scan?')} <a id="toggleLink">${_('Click here')}</a></p>
|
||||
<div id="secretDiv" class="hidden">
|
||||
<p>${_('Copy and use this code to manually set up an authenticator app')}</p>
|
||||
<input type="text" class="input-monospace" value="${key}" id="secret_totp" name="secret_totp" style="width: 400px"/>
|
||||
<i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${key}" title="${_('Copy the secret key')}"></i>
|
||||
## QR CODE
|
||||
<code>${_('Account')}: ${totp_name}</code><br/>
|
||||
<div class="qr-code-container">
|
||||
<img alt="qr-code" src="data:image/png;base64, ${qr}"/>
|
||||
</div>
|
||||
|
||||
<div id="verify_2fa">
|
||||
<div id="alternativeCode" style="margin: -10px 0 5px 0">${_('Unable to scan?')} <a id="toggleLink">${_('Click here')}</a></div>
|
||||
|
||||
<div class="form mt-4">
|
||||
<div class="field">
|
||||
<p>
|
||||
<div class="label">
|
||||
<label for="totp" class="form-label text-dark font-weight-bold" style="text-align: left;">${_('Verify the code from the app')}:</label>
|
||||
</div>
|
||||
</p>
|
||||
<p>
|
||||
<div>
|
||||
<div class="input-group">
|
||||
${h.text('totp', class_='form-control', style='width: 40%;')}
|
||||
<div id="formErrors">
|
||||
% if 'totp' in errors:
|
||||
<span class="error-message">${errors.get('totp')}</span>
|
||||
<br />
|
||||
% endif
|
||||
</div>
|
||||
<div class="input-group-append">
|
||||
${h.submit('verify_2fa',_('Verify'),class_="btn btn-primary", style='width: 40%;')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
## Secret alternative code
|
||||
<div id="secretDiv" style="display: none">
|
||||
|
||||
<div style="padding: 10px 0">
|
||||
<strong style="padding: 4px 0">${_('Copy and use this code to manually set up an authenticator app')}</strong>
|
||||
<code>${key}</code><i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${key}" title="${_('Copy the secret key')}" ></i><br/>
|
||||
<code>${_('type')}: time-based</code>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<label for="totp">${_('Verify the code from the app')}:</label>
|
||||
${h.text('totp', class_='form-control', )}
|
||||
<div id="formErrors">
|
||||
% if 'totp' in errors:
|
||||
<span class="error-message">${errors.get('totp')}</span>
|
||||
<br />
|
||||
% endif
|
||||
% if 'secret_totp' in errors:
|
||||
<span class="error-message">SECRET:${errors.get('secret_totp')}</span>
|
||||
<br />
|
||||
% endif
|
||||
</div>
|
||||
${h.hidden('secret_totp', key)}
|
||||
${h.submit('verify_2fa',_('Verify'), class_="btn sign-in")}
|
||||
|
||||
${h.end_form()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script type="text/javascript">
|
||||
|
||||
document.getElementById('toggleLink').addEventListener('click', function() {
|
||||
let hiddenField = document.getElementById('secretDiv');
|
||||
if (hiddenField.classList.contains('hidden')) {
|
||||
hiddenField.classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
$(document).ready(function() {
|
||||
|
||||
$( "#toggleLink" ).on("click", function() {
|
||||
$( "#secretDiv" ).toggle();
|
||||
$( "#alternativeCode").hide();
|
||||
$('#totp').focus();
|
||||
});
|
||||
|
||||
$('#totp').focus();
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</%def>
|
||||
<style>body{background-color:#eeeeee;}</style>
|
||||
|
||||
<div class="loginbox">
|
||||
<div class="loginbox" style="width: 600px">
|
||||
<div class="header-account">
|
||||
<div id="header-inner" class="title">
|
||||
<div id="logo">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue