Twofactor authentication and strong password
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<title>Verificatiecode DBOIS</title>
|
||||
<link href="styles.css" media="all" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<style>
|
||||
/* Same styles as requestpassword_email.php */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
line-height: 1.6;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: block !important;
|
||||
max-width: 600px !important;
|
||||
margin: 0 auto !important;
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.main {
|
||||
background: #fff;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 0 0 20px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.alert.alert-warning {
|
||||
background: #ff9f00;
|
||||
}
|
||||
|
||||
.alert.alert-good {
|
||||
background: #68b90f;
|
||||
}
|
||||
|
||||
.otp-code {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 8px;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background-color: #f0f0f0;
|
||||
border: 2px dashed #348eda;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 640px) {
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.otp-code {
|
||||
font-size: 24px;
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="body-wrap">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="container" width="600">
|
||||
<div class="content">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="alert alert-good">
|
||||
Tweefactorauthenticatie - DBOIS
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-wrap">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<p>
|
||||
Beste <?= $user['firstname']?> <?=$user['middlename']?> <?=$user['lastname']?>
|
||||
</p>
|
||||
<p>
|
||||
U probeert in te loggen in DBOIS. Gebruik de onderstaande verificatiecode om uw login te voltooien.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<div class="otp-code">
|
||||
<?= $user['otp_code'] ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<p>
|
||||
Deze code is 10 minuten geldig.
|
||||
</p>
|
||||
<p>
|
||||
Als u niet heeft geprobeerd in te loggen, negeer dan deze e-mail.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,291 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tweefactorauthenticatie Instellingen - DBOIS</title>
|
||||
|
||||
<link rel="icon" href="/css/images/dbo-01-80x80.png" type="image/png">
|
||||
<link rel="stylesheet" href="/css/vendor/bootstrap.min.css?v=<?=$version?>">
|
||||
<link rel="stylesheet" href="/css/vendor/bootstrap-extend.css?v=<?=$version?>">
|
||||
<link rel="stylesheet" href="/css/vendor/site.min.css?v=<?=$version?>">
|
||||
|
||||
<style>
|
||||
.twofactor-container {
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.method-card {
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 15px 0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.method-card:hover {
|
||||
border-color: #348eda;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.method-card.active {
|
||||
border-color: #68b90f;
|
||||
background-color: #f0f8ff;
|
||||
}
|
||||
.qr-code-container {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.qr-code-container img {
|
||||
max-width: 250px;
|
||||
}
|
||||
.verification-code-input {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
letter-spacing: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.secret-code {
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
font-family: monospace;
|
||||
word-break: break-all;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert {
|
||||
margin: 15px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="twofactor-container">
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Tweefactorauthenticatie Instellingen</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<!-- Current Status -->
|
||||
<div class="alert alert-info" data-bind="visible: !enabled()">
|
||||
<strong>Tweefactorauthenticatie is momenteel uitgeschakeld.</strong>
|
||||
<p>Schakel 2FA in om een extra beveiligingslaag aan uw account toe te voegen.</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success" data-bind="visible: enabled">
|
||||
<strong>Tweefactorauthenticatie is ingeschakeld</strong>
|
||||
<p>Huidige methode: <span data-bind="text: currentMethod"></span></p>
|
||||
</div>
|
||||
|
||||
<!-- Enable/Disable Section -->
|
||||
<div data-bind="visible: !enabled()">
|
||||
<h4>Kies een 2FA methode:</h4>
|
||||
|
||||
<div class="method-card" data-bind="click: function() { selectMethod('email'); }, css: { active: selectedMethod() === 'email' }">
|
||||
<h5><i class="icon wb-envelope" aria-hidden="true"></i> E-mail</h5>
|
||||
<p>Ontvang een eenmalige code via e-mail bij elke inlogpoging.</p>
|
||||
</div>
|
||||
|
||||
<div class="method-card" data-bind="click: function() { selectMethod('authenticator'); }, css: { active: selectedMethod() === 'authenticator' }">
|
||||
<h5><i class="icon wb-mobile" aria-hidden="true"></i> Google Authenticator</h5>
|
||||
<p>Gebruik een authenticator app zoals Google Authenticator of Authy.</p>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-lg" data-bind="click: enableTwoFactor, enable: selectedMethod">
|
||||
2FA Inschakelen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Authenticator Setup -->
|
||||
<div data-bind="visible: showAuthenticatorSetup">
|
||||
<hr>
|
||||
<h4>Google Authenticator Instellen</h4>
|
||||
|
||||
<div class="qr-code-container">
|
||||
<p>Scan deze QR-code met uw authenticator app:</p>
|
||||
<img data-bind="attr: { src: qrCodeUrl }" alt="QR Code">
|
||||
|
||||
<p class="mt-20">Of voer deze code handmatig in:</p>
|
||||
<div class="secret-code" data-bind="text: secret"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Voer de 6-cijferige code in om te verifiëren:</label>
|
||||
<input type="text"
|
||||
class="form-control verification-code-input"
|
||||
maxlength="6"
|
||||
data-bind="textInput: verificationCode, event: { keyup: handleVerificationKeyup }">
|
||||
</div>
|
||||
|
||||
<button class="btn btn-success" data-bind="click: verifyAuthenticatorSetup, enable: verificationCode().length === 6">
|
||||
Verifiëren
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Change Method -->
|
||||
<div data-bind="visible: enabled() && !showAuthenticatorSetup()">
|
||||
<hr>
|
||||
<h4>Methode Wijzigen</h4>
|
||||
|
||||
<div class="method-card" data-bind="click: function() { selectMethod('email'); }, css: { active: changeToMethod() === 'email' }">
|
||||
<h5><i class="icon wb-envelope" aria-hidden="true"></i> E-mail</h5>
|
||||
<p>Ontvang een eenmalige code via e-mail bij elke inlogpoging.</p>
|
||||
</div>
|
||||
|
||||
<div class="method-card" data-bind="click: function() { selectMethod('authenticator'); }, css: { active: changeToMethod() === 'authenticator' }">
|
||||
<h5><i class="icon wb-mobile" aria-hidden="true"></i> Google Authenticator</h5>
|
||||
<p>Gebruik een authenticator app zoals Google Authenticator of Authy.</p>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary" data-bind="click: changeMethod, enable: changeToMethod() !== currentMethod()">
|
||||
Methode Wijzigen
|
||||
</button>
|
||||
|
||||
<hr>
|
||||
|
||||
<button class="btn btn-danger" data-bind="click: disableTwoFactor">
|
||||
2FA Uitschakelen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<a href="/" class="btn btn-default">Terug naar Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/vendor/jquery/jquery.js?v=<?=$version?>"></script>
|
||||
<script src="/js/vendor/bootstrap/bootstrap.js?v=<?=$version?>"></script>
|
||||
<script src="/js/vendor/Knockout.min.js?v=<?=$version?>"></script>
|
||||
|
||||
<script>
|
||||
function TwoFactorViewModel() {
|
||||
var self = this;
|
||||
|
||||
self.enabled = ko.observable(<?= $user->two_factor_enabled === 'T' ? 'true' : 'false' ?>);
|
||||
self.currentMethod = ko.observable('<?= $user->two_factor_method ?>');
|
||||
self.selectedMethod = ko.observable(null);
|
||||
self.changeToMethod = ko.observable(null);
|
||||
self.showAuthenticatorSetup = ko.observable(false);
|
||||
self.qrCodeUrl = ko.observable('');
|
||||
self.secret = ko.observable('');
|
||||
self.verificationCode = ko.observable('');
|
||||
|
||||
self.selectMethod = function(method) {
|
||||
if (!self.enabled()) {
|
||||
self.selectedMethod(method);
|
||||
} else {
|
||||
self.changeToMethod(method);
|
||||
}
|
||||
};
|
||||
|
||||
self.enableTwoFactor = function() {
|
||||
if (!self.selectedMethod()) {
|
||||
alert('Kies eerst een methode');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/beheer/TwoFactorController/enable',
|
||||
method: 'POST',
|
||||
data: { method: self.selectedMethod() },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
if (response.method === 'authenticator') {
|
||||
self.qrCodeUrl(response.qrCodeUrl);
|
||||
self.secret(response.secret);
|
||||
self.showAuthenticatorSetup(true);
|
||||
} else {
|
||||
alert(response.message);
|
||||
location.reload();
|
||||
}
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.verifyAuthenticatorSetup = function() {
|
||||
$.ajax({
|
||||
url: '/beheer/TwoFactorController/verifySetup',
|
||||
method: 'POST',
|
||||
data: { code: self.verificationCode() },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert('Google Authenticator succesvol ingesteld!');
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.disableTwoFactor = function() {
|
||||
if (!confirm('Weet u zeker dat u 2FA wilt uitschakelen?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/beheer/TwoFactorController/disable',
|
||||
method: 'POST',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert(response.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.changeMethod = function() {
|
||||
if (!self.changeToMethod()) {
|
||||
alert('Kies eerst een methode');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/beheer/TwoFactorController/changeMethod',
|
||||
method: 'POST',
|
||||
data: { method: self.changeToMethod() },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
if (response.method === 'authenticator') {
|
||||
self.enabled(false);
|
||||
self.selectedMethod('authenticator');
|
||||
self.qrCodeUrl(response.qrCodeUrl);
|
||||
self.secret(response.secret);
|
||||
self.showAuthenticatorSetup(true);
|
||||
} else {
|
||||
alert(response.message);
|
||||
location.reload();
|
||||
}
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.handleVerificationKeyup = function(data, event) {
|
||||
// Auto-verify when 6 digits entered
|
||||
if (self.verificationCode().length === 6 && event.keyCode === 13) {
|
||||
self.verifyAuthenticatorSetup();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
ko.applyBindings(new TwoFactorViewModel());
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -33,6 +33,131 @@
|
||||
<body class="animsition page-login-v3 layout-full">
|
||||
<!-- Page -->
|
||||
<?php $this->load->view('specials/tellme_modal'); ?>
|
||||
|
||||
<!-- Password Change Modal -->
|
||||
<div class="modal fade" id="password-change-modal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning">
|
||||
<h4 class="modal-title">
|
||||
<i class="icon wb-warning" aria-hidden="true"></i>
|
||||
Wachtwoord wijzigen verplicht
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-warning">
|
||||
<strong>Let op:</strong> Uw huidige wachtwoord voldoet niet aan de beveiligingseisen.
|
||||
U moet uw wachtwoord wijzigen om door te gaan.
|
||||
</div>
|
||||
|
||||
<h5>Wachtwoordeisen:</h5>
|
||||
<ul class="list-unstyled" data-bind="foreach: passwordRequirements">
|
||||
<li style="padding: 5px 0;">
|
||||
<i class="icon wb-check text-success" aria-hidden="true"></i>
|
||||
<span data-bind="text: $data"></span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- New Password Input -->
|
||||
<div class="form-group form-material floating" data-plugin="formMaterial" style="margin-top: 30px;">
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
id="newPassword"
|
||||
data-bind="textInput: newPassword"
|
||||
autocomplete="new-password" />
|
||||
<label class="floating-label">Nieuw wachtwoord</label>
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password Input -->
|
||||
<div class="form-group form-material floating" data-plugin="formMaterial">
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
id="confirmPassword"
|
||||
data-bind="textInput: confirmPassword, event: { keyup: handlePasswordChangeKeyup }"
|
||||
autocomplete="new-password" />
|
||||
<label class="floating-label">Bevestig wachtwoord</label>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div data-bind="visible: passwordChangeError()" class="alert alert-danger" style="margin-top: 20px;">
|
||||
<span data-bind="text: passwordChangeError"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button"
|
||||
class="btn btn-primary btn-lg btn-block"
|
||||
data-bind="click: changePassword, enable: newPassword().length >= 8 && confirmPassword().length >= 8 && !isChangingPassword()">
|
||||
<span data-bind="visible: !isChangingPassword()">Wachtwoord wijzigen</span>
|
||||
<span data-bind="visible: isChangingPassword()">Wijzigen...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2FA Verification Modal -->
|
||||
<div class="modal fade" id="twofactor-modal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">
|
||||
<i class="icon wb-lock" aria-hidden="true"></i>
|
||||
Tweefactorauthenticatie
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<!-- Email Method -->
|
||||
<div data-bind="visible: twoFactorMethod() === 'email'">
|
||||
<div style="font-size: 48px; color: #348eda; margin-bottom: 20px;">
|
||||
<i class="icon wb-envelope" aria-hidden="true"></i>
|
||||
</div>
|
||||
<p>Voer de 6-cijferige code in die naar uw e-mail is verzonden.</p>
|
||||
</div>
|
||||
|
||||
<!-- Authenticator Method -->
|
||||
<div data-bind="visible: twoFactorMethod() === 'authenticator'">
|
||||
<div style="font-size: 48px; color: #348eda; margin-bottom: 20px;">
|
||||
<i class="icon wb-mobile" aria-hidden="true"></i>
|
||||
</div>
|
||||
<p>Voer de 6-cijferige code in van uw authenticator app.</p>
|
||||
</div>
|
||||
|
||||
<!-- Code Input -->
|
||||
<div class="form-group" style="margin-top: 30px;">
|
||||
<input type="text"
|
||||
class="form-control text-center"
|
||||
id="twoFactorCode"
|
||||
maxlength="6"
|
||||
placeholder="000000"
|
||||
style="font-size: 32px; letter-spacing: 8px; font-weight: bold;"
|
||||
data-bind="textInput: twoFactorCode, event: { keyup: handleTwoFactorKeyup }"
|
||||
autocomplete="off" />
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div data-bind="visible: twoFactorError()" class="alert alert-danger" style="margin-top: 20px;">
|
||||
<span data-bind="text: twoFactorError"></span>
|
||||
</div>
|
||||
|
||||
<!-- Resend Button (Email only) -->
|
||||
<div data-bind="visible: twoFactorMethod() === 'email'" style="margin-top: 20px;">
|
||||
<a href="#" data-bind="click: resendOtp, enable: !isResending()">
|
||||
<span data-bind="visible: !isResending()">Code opnieuw verzenden</span>
|
||||
<span data-bind="visible: isResending()">Verzenden...</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-bind="click: cancelTwoFactor">Annuleren</button>
|
||||
<button type="button" class="btn btn-primary btn-lg" data-bind="click: verifyTwoFactor, enable: twoFactorCode().length === 6 && !isVerifying()">
|
||||
<span data-bind="visible: !isVerifying()">Verifiëren</span>
|
||||
<span data-bind="visible: isVerifying()">Verifiëren...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page vertical-align text-center" data-animsition-in="fade-in" data-animsition-out="fade-out">
|
||||
<div class="page-content vertical-align-middle animation-slide-top animation-duration-1">
|
||||
<div class="panel" id="login-form">
|
||||
@@ -116,6 +241,12 @@
|
||||
<script src="js/lib/modules/login/loginModule.js?v=<? $this->version ?>"></script>
|
||||
<script src="js/lib/modules/specials/tellmeModule.js?v=<? $this->version ?>"></script>
|
||||
<script src="js/lib/helpers.js?v=<? $this->version ?>"></script>
|
||||
<script>
|
||||
// Apply bindings for password change modal
|
||||
$(function() {
|
||||
ko.applyBindings(dbo.loginModel, document.getElementById('password-change-modal'));
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js css-menubar" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
|
||||
<title>Tweefactorauthenticatie - DBOIS</title>
|
||||
|
||||
<link rel="icon" href="css/images/dbo-01-80x80.png" type="image/png">
|
||||
|
||||
<!-- Stylesheets -->
|
||||
<link rel="stylesheet" href="css/vendor/bootstrap.min.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/vendor/bootstrap-extend.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/vendor/site.min.css?v=<?=$this->version?>">
|
||||
|
||||
<!-- Plugins -->
|
||||
<link rel="stylesheet" href="css/vendor/plugins/asscrollable/asScrollable.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/vendor/plugins/switchery/switchery.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/vendor/plugins/slidepanel/slidePanel.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/vendor/plugins/flag-icon-css/flag-icon.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="css/login-v3.css?v=<?=$this->version?>">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="fonts/web-icons/web-icons.min.css?v=<?=$this->version?>">
|
||||
<link rel="stylesheet" href="fonts/brand-icons/brand-icons.min.css?v=<?=$this->version?>">
|
||||
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Roboto:300,400,500,300italic'>
|
||||
|
||||
<style>
|
||||
.verification-code-input {
|
||||
text-align: center;
|
||||
font-size: 32px;
|
||||
letter-spacing: 8px;
|
||||
font-weight: bold;
|
||||
padding: 20px;
|
||||
}
|
||||
.resend-link {
|
||||
margin-top: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
.method-icon {
|
||||
font-size: 48px;
|
||||
color: #348eda;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="animsition page-login-v3 layout-full">
|
||||
<!-- Page -->
|
||||
<?php $this->load->view('specials/tellme_modal'); ?>
|
||||
<div class="page vertical-align text-center" data-animsition-in="fade-in" data-animsition-out="fade-out">
|
||||
<div class="page-content vertical-align-middle animation-slide-top animation-duration-1">
|
||||
<div class="panel" id="verify2fa-form">
|
||||
<div class="panel-body">
|
||||
<div class="brand">
|
||||
<img class="brand-img" src="css/images/logo_dbo.png" alt="DBOIS">
|
||||
<h2 class="brand-text font-size-18">projectbeheer</h2>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="method-icon" data-bind="visible: method() === 'email'">
|
||||
<i class="icon wb-envelope" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="method-icon" data-bind="visible: method() === 'authenticator'">
|
||||
<i class="icon wb-mobile" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<h3>Tweefactorauthenticatie</h3>
|
||||
|
||||
<p data-bind="visible: method() === 'email'">
|
||||
Voer de 6-cijferige code in die naar uw e-mail is verzonden.
|
||||
</p>
|
||||
<p data-bind="visible: method() === 'authenticator'">
|
||||
Voer de 6-cijferige code in van uw authenticator app.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-material floating mt-40" data-plugin="formMaterial">
|
||||
<input type="text"
|
||||
class="form-control verification-code-input"
|
||||
name="verification_code"
|
||||
maxlength="6"
|
||||
data-bind="textInput: verificationCode, event: { keyup: handleKeyup }"
|
||||
autocomplete="off"
|
||||
autofocus />
|
||||
<label class="floating-label">Verificatiecode</label>
|
||||
</div>
|
||||
|
||||
<div data-bind="visible: errorMessage()" class="alert alert-danger">
|
||||
<span data-bind="text: errorMessage"></span>
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-primary btn-block btn-lg mt-40"
|
||||
data-bind="click: verify, enable: verificationCode().length === 6 && !isVerifying()">
|
||||
<span data-bind="visible: !isVerifying()">Verifiëren</span>
|
||||
<span data-bind="visible: isVerifying()">Verifiëren...</span>
|
||||
</button>
|
||||
|
||||
<div data-bind="visible: method() === 'email'">
|
||||
<a href="#" class="resend-link" data-bind="click: resendOtp, enable: !isResending()">
|
||||
<span data-bind="visible: !isResending()">Code opnieuw verzenden</span>
|
||||
<span data-bind="visible: isResending()">Verzenden...</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-20">
|
||||
<a href="/login/logout">Annuleren</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="page-copyright page-copyright-inverse">
|
||||
<p>© 2018. De Beleidsonderzoekers</p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Page -->
|
||||
|
||||
<!-- Core -->
|
||||
<script src="js/vendor/jquery/jquery.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/vendor/popper-js/umd/popper.min.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/vendor/bootstrap/bootstrap.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/vendor/animsition/animsition.js?v=<?=$this->version?>"></script>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="js/vendor/Config.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/vendor/Knockout.min.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/lib/modules/specials/tellmeModule.js?v=<?=$this->version?>"></script>
|
||||
<script src="js/lib/helpers.js?v=<?=$this->version?>"></script>
|
||||
|
||||
<script>
|
||||
function Verify2FAViewModel() {
|
||||
var self = this;
|
||||
|
||||
self.method = ko.observable('<?= $method ?>');
|
||||
self.verificationCode = ko.observable('');
|
||||
self.errorMessage = ko.observable('');
|
||||
self.isVerifying = ko.observable(false);
|
||||
self.isResending = ko.observable(false);
|
||||
|
||||
self.verify = function() {
|
||||
if (self.verificationCode().length !== 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.errorMessage('');
|
||||
self.isVerifying(true);
|
||||
|
||||
$.ajax({
|
||||
url: '/login/verify2fa',
|
||||
method: 'POST',
|
||||
data: { code: self.verificationCode() },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// Redirect to main application
|
||||
window.location.href = '/';
|
||||
} else {
|
||||
self.errorMessage(response.message || 'Ongeldige verificatiecode');
|
||||
self.verificationCode('');
|
||||
}
|
||||
self.isVerifying(false);
|
||||
},
|
||||
error: function() {
|
||||
self.errorMessage('Er is een fout opgetreden. Probeer het opnieuw.');
|
||||
self.isVerifying(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.resendOtp = function() {
|
||||
self.isResending(true);
|
||||
self.errorMessage('');
|
||||
|
||||
$.ajax({
|
||||
url: '/login/resendOtp',
|
||||
method: 'POST',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert(response.message || 'Nieuwe code verzonden');
|
||||
} else {
|
||||
self.errorMessage(response.message || 'Kan code niet opnieuw verzenden');
|
||||
}
|
||||
self.isResending(false);
|
||||
},
|
||||
error: function() {
|
||||
self.errorMessage('Er is een fout opgetreden. Probeer het opnieuw.');
|
||||
self.isResending(false);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
self.handleKeyup = function(data, event) {
|
||||
// Clear error message on input
|
||||
self.errorMessage('');
|
||||
|
||||
// Auto-submit when 6 digits entered and Enter is pressed
|
||||
if (self.verificationCode().length === 6 && event.keyCode === 13) {
|
||||
self.verify();
|
||||
}
|
||||
|
||||
// Only allow digits
|
||||
var sanitized = self.verificationCode().replace(/[^0-9]/g, '');
|
||||
if (sanitized !== self.verificationCode()) {
|
||||
self.verificationCode(sanitized);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
ko.applyBindings(new Verify2FAViewModel());
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user