Update templates and controllers for 2fa

This commit is contained in:
DariusIII
2025-06-05 16:50:38 +02:00
parent d0201e3dc5
commit 546dd7e2df
2 changed files with 155 additions and 4 deletions
+104 -4
View File
@@ -89,14 +89,19 @@
{{csrf_field()}}
<input type="hidden" name="redirect_to_profile" value="1">
<div class="mb-4">
<div class="input-group">
<span class="input-group-text"><i class="fas fa-key"></i></span>
<input id="verify-code" type="text" class="form-control" name="verify-code" required placeholder="Enter 6-digit code" autocomplete="off">
<div class="d-flex justify-content-between gap-2 mb-2">
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
<input type="text" class="form-control text-center otp-input" maxlength="1" pattern="[0-9]" inputmode="numeric" autocomplete="off" required>
</div>
<input id="verify-code" type="hidden" name="verify-code" required>
<div class="form-text">Enter the 6-digit code from your authenticator app</div>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-success">
<button type="submit" class="btn btn-success" id="verify-button">
<i class="fa fa-check-circle me-2"></i>Verify and Enable 2FA
</button>
<a href="{{url("/profileedit#security")}}" class="btn btn-outline-secondary">
@@ -136,16 +141,111 @@
.notification-fade.show {
opacity: 1;
}
.otp-input {
width: 45px;
height: 45px;
font-size: 1.2rem;
font-weight: bold;
}
@media (max-width: 576px) {
.otp-input {
width: 40px;
height: 40px;
font-size: 1.1rem;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Show notification alerts with animation
setTimeout(function() {
const alerts = document.querySelectorAll('.notification-fade');
alerts.forEach(function(alert) {
alert.classList.add('show');
});
}, 100);
// Handle OTP input functionality
const otpInputs = document.querySelectorAll('.otp-input');
const verifyCodeInput = document.getElementById('verify-code');
const verifyButton = document.getElementById('verify-button');
if (otpInputs.length > 0) {
// Set focus on first input on page load
otpInputs[0].focus();
// Add event listeners to each OTP input
otpInputs.forEach(function(input, index) {
// Handle number input and auto-focus
input.addEventListener('input', function(e) {
const value = e.target.value;
// Only allow digits
if (/^\d*$/.test(value)) {
// Auto advance to next input
if (value.length === 1 && index < otpInputs.length - 1) {
otpInputs[index + 1].focus();
}
// Combine all inputs into the hidden field
updateHiddenField();
} else {
// Clear non-numeric input
e.target.value = '';
}
});
// Handle backspace key
input.addEventListener('keydown', function(e) {
if (e.key === 'Backspace' && !e.target.value && index > 0) {
// Move to previous input when backspace is pressed on empty input
otpInputs[index - 1].focus();
}
});
// Handle paste event (allow pasting full 6-digit code)
input.addEventListener('paste', function(e) {
e.preventDefault();
const pasteData = (e.clipboardData || window.clipboardData).getData('text');
const digits = pasteData.replace(/\D/g, '').substring(0, 6).split('');
if (digits.length > 0) {
// Fill inputs with pasted digits
otpInputs.forEach((input, i) => {
if (i < digits.length) {
input.value = digits[i];
}
});
// Focus on appropriate field
if (digits.length >= 6) {
otpInputs[5].focus();
} else {
otpInputs[Math.min(digits.length, 5)].focus();
}
// Update hidden field
updateHiddenField();
}
});
});
// Submit form on full code entry
function updateHiddenField() {
const code = Array.from(otpInputs).map(input => input.value).join('');
verifyCodeInput.value = code;
// Auto submit if all 6 digits are entered
if (code.length === 6 && /^\d{6}$/.test(code)) {
setTimeout(() => {
verifyButton.classList.add('btn-pulse');
}, 200);
}
}
}
});
</script>
</body>
@@ -488,6 +488,57 @@
this.setAttribute('data-bs-original-title', 'Copy to clipboard');
}, 2000);
});
// Check if there's a hash in the URL to activate the appropriate tab
var hash = window.location.hash;
if (hash) {
var tabId = hash.substring(1);
var tabElement = document.getElementById(tabId + '-tab');
if (tabElement) {
var tab = new bootstrap.Tab(tabElement);
tab.show();
// If the security tab is opened and there are 2FA messages, animate them
if (tabId === 'security') {
animateAlerts();
}
}
}
// Animate alerts when they become visible
function animateAlerts() {
var alerts = document.querySelectorAll('#security .alert');
alerts.forEach(function(alert) {
if (alert.style.opacity !== '1') {
alert.style.opacity = '0';
alert.style.transition = 'opacity 0.4s ease-in-out';
setTimeout(function() {
alert.style.opacity = '1';
}, 100);
// Add auto-dismiss after 10 seconds for success alerts
if (alert.classList.contains('alert-success')) {
setTimeout(function() {
alert.style.opacity = '0';
setTimeout(function() {
alert.style.display = 'none';
}, 400);
}, 10000);
}
}
});
}
// Add event listener for tab changes
var tabElements = document.querySelectorAll('a[data-bs-toggle="tab"]');
tabElements.forEach(function(tabElement) {
tabElement.addEventListener('shown.bs.tab', function(event) {
// When security tab is shown, animate alerts
if (event.target.getAttribute('href') === '#security') {
animateAlerts();
}
});
});
});
{/literal}
</script>