Improve TOTP form
Based on https://bbbootstrap.com/snippets/bootstrap-5-verify-otp-validation-form-inputs-78878858
This commit is contained in:
		@@ -1,24 +1,83 @@
 | 
				
			|||||||
{% extends "base_login_page.html" %}
 | 
					{% extends "base_login_page.html" %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					#otp input {
 | 
				
			||||||
 | 
					  padding-left: 0px;
 | 
				
			||||||
 | 
					  padding-right: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div>
 | 
					<div>
 | 
				
			||||||
    <p>Please go to your authenticator app <i>{{ factor.name }}</i>, generate a new code and enter it here:</p>
 | 
					    <p>Please go to your authenticator app <i>{{ factor.name }}</i>, generate a new code and enter it here:</p>
 | 
				
			||||||
    <form method="post" action="{{ factor.login_url(_p.redirect_uri) }}">
 | 
					    <form id="totp_form" method="post" action="{{ factor.login_url(_p.redirect_uri) }}">
 | 
				
			||||||
 | 
					        <input type="hidden" id="code" name="code" />
 | 
				
			||||||
        <div class="form-group">
 | 
					        <div class="form-group">
 | 
				
			||||||
            <label for="code" class="form-label mt-4">Generated code</label>
 | 
					            <div id="otp" class="inputs d-flex flex-row justify-content-center mt-2">
 | 
				
			||||||
            <input type="text" name="code" minlength="6" maxlength="6" class="form-control" id="code"
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i1" maxlength="1" autofocus/>
 | 
				
			||||||
                   placeholder="XXXXXX" autofocus>
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i2" maxlength="1"/>
 | 
				
			||||||
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i3" maxlength="1"/>
 | 
				
			||||||
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i4" maxlength="1"/>
 | 
				
			||||||
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i5" maxlength="1"/>
 | 
				
			||||||
 | 
					                <input class="m-2 text-center form-control rounded" type="text" id="i6" maxlength="1"/>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					 | 
				
			||||||
        <button class="w-100 btn btn-primary" type="submit" style="margin: 20px 0px;">Login</button>
 | 
					 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div style="margin-top: 10px;">
 | 
					<div style="margin-top: 10px;">
 | 
				
			||||||
    <a href="/2fa_auth?redirect={{ _p.redirect_uri.get_encoded() }}">Sign in using another factor</a><br />
 | 
					    <a href="/2fa_auth?redirect={{ _p.redirect_uri.get_encoded() }}">Sign in using another factor</a><br/>
 | 
				
			||||||
    <a href="/logout">Sign out</a>
 | 
					    <a href="/logout">Sign out</a>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					function OTPInput() {
 | 
				
			||||||
 | 
					    const inputs = document.querySelectorAll('#otp > *[id]');
 | 
				
			||||||
 | 
					    for (let i = 0; i < inputs.length; i++) {
 | 
				
			||||||
 | 
					        // Reset form on init
 | 
				
			||||||
 | 
					        inputs[i].value = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inputs[i].addEventListener('keydown', (event) => {
 | 
				
			||||||
 | 
					            if (event.key === "Backspace") {
 | 
				
			||||||
 | 
					                if (inputs[i].value != "") {
 | 
				
			||||||
 | 
					                    inputs[i].value = '';
 | 
				
			||||||
 | 
					                } else if (i > 0) {
 | 
				
			||||||
 | 
					                    inputs[i - 1].value = "";
 | 
				
			||||||
 | 
					                    inputs[i - 1].focus();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Code has already been typed entirely
 | 
				
			||||||
 | 
					            else if (i === inputs.length - 1 && inputs[i].value !== '')
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add new digit
 | 
				
			||||||
 | 
					            else if (event.keyCode >= 48 && event.keyCode <= 57) {
 | 
				
			||||||
 | 
					                inputs[i].value = event.key;
 | 
				
			||||||
 | 
					                if (i !== inputs.length - 1)
 | 
				
			||||||
 | 
					                    inputs[i + 1].focus();
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    submitCode();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            event.preventDefault();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function submitCode() {
 | 
				
			||||||
 | 
					    const code = [...document.querySelectorAll('#otp > *[id]')]
 | 
				
			||||||
 | 
					        .map((i) => i.value)
 | 
				
			||||||
 | 
					        .join("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document.getElementById("code").value = code;
 | 
				
			||||||
 | 
					    document.getElementById("totp_form").submit();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener("DOMContentLoaded", () => OTPInput());
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% endblock content %}
 | 
					{% endblock content %}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user