202 lines
9.2 KiB
HTML
202 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Change account password - SME Server</title>
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>Change account password</h1>
|
|
|
|
<div class="instructions">
|
|
<p>To change your account password, please fill out the following form. You will need to provide the name of your account, your old password, and your desired new password. (You must type the new password twice.)</p>
|
|
|
|
<p>If you cannot change your password because you have forgotten the old one, your local system administrator can reset your password using the <em>server manager</em>.</p>
|
|
|
|
{% if password_requirements %}
|
|
<div class="password-requirements">
|
|
<p><strong>Password Requirements ({{ password_requirements.level|title }}):</strong> {{ password_requirements.description }}</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Flash messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
<div class="messages">
|
|
{% for category, message in messages %}
|
|
<div class="message {{ category }}">{{ message }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<form method="POST" class="password-form">
|
|
<div class="form-container">
|
|
<table class="form-table">
|
|
<tr>
|
|
<td class="label-cell">Your account:</td>
|
|
<td class="input-cell">
|
|
<input type="text" name="username" id="username"
|
|
value="{{ request.form.username if request.form.username else '' }}"
|
|
required>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label-cell">Old password:</td>
|
|
<td class="input-cell">
|
|
<div class="password-input-container">
|
|
<input type="password" name="old_password" id="old_password" required>
|
|
<button type="button" class="password-toggle" onclick="togglePassword('old_password')" aria-label="Toggle password visibility">
|
|
<span id="old_password_toggle_text">Show</span>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label-cell">New password:</td>
|
|
<td class="input-cell">
|
|
<div class="password-input-container">
|
|
<input type="password" name="new_password" id="new_password" required>
|
|
<button type="button" class="password-toggle" onclick="togglePassword('new_password')" aria-label="Toggle password visibility">
|
|
<span id="new_password_toggle_text">Show</span>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label-cell">New password (verify):</td>
|
|
<td class="input-cell">
|
|
<div class="password-input-container">
|
|
<input type="password" name="verify_password" id="verify_password" required>
|
|
<button type="button" class="password-toggle" onclick="togglePassword('verify_password')" aria-label="Toggle password visibility">
|
|
<span id="verify_password_toggle_text">Show</span>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div class="button-container">
|
|
<input type="submit" value="Change Password" class="submit-button">
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="footer">
|
|
<p>{{ version if version else 'SME Server 11 (beta1)' }}</p>
|
|
<p>{{ copyright_info.mitel if copyright_info else 'Copyright 1999-2006 Mitel Corporation' }}</p>
|
|
<p>{{ copyright_info.rights if copyright_info else 'All rights reserved.' }}</p>
|
|
<p>{{ copyright_info.koozali if copyright_info else 'Copyright (C) 2013 - 2021 Koozali Foundation Inc.' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Password visibility toggle functionality
|
|
function togglePassword(fieldId) {
|
|
const passwordField = document.getElementById(fieldId);
|
|
const toggleText = document.getElementById(fieldId + '_toggle_text');
|
|
|
|
if (passwordField.type === 'password') {
|
|
passwordField.type = 'text';
|
|
toggleText.textContent = 'Hide';
|
|
} else {
|
|
passwordField.type = 'password';
|
|
toggleText.textContent = 'Show';
|
|
}
|
|
}
|
|
|
|
// Enhanced client-side validation
|
|
document.querySelector('.password-form').addEventListener('submit', function(e) {
|
|
const newPassword = document.getElementById('new_password').value;
|
|
const verifyPassword = document.getElementById('verify_password').value;
|
|
|
|
if (newPassword !== verifyPassword) {
|
|
e.preventDefault();
|
|
alert('New password and verification do not match');
|
|
return false;
|
|
}
|
|
|
|
// Basic length check (server will do full validation)
|
|
if (newPassword.length < 12) {
|
|
e.preventDefault();
|
|
alert('Password must be at least 12 characters long');
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Real-time password strength indicator
|
|
document.getElementById('new_password').addEventListener('input', function() {
|
|
const password = this.value;
|
|
updatePasswordStrengthIndicator(password);
|
|
});
|
|
|
|
function updatePasswordStrengthIndicator(password) {
|
|
const indicator = document.getElementById('password-strength-indicator');
|
|
if (!indicator) return;
|
|
|
|
if (password.length === 0) {
|
|
indicator.textContent = 'Enter password to see strength';
|
|
indicator.style.color = '#888';
|
|
return;
|
|
}
|
|
|
|
fetch('/api/password-strength', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ password: password, username: document.getElementById('username').value }),
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.error) {
|
|
indicator.textContent = 'Error checking strength';
|
|
indicator.style.color = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
const strengthLevels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong'];
|
|
const strengthColors = ['#ff4444', '#ff8800', '#ffaa00', '#88aa00', '#44aa44'];
|
|
|
|
let displayLevel = data.strength_level;
|
|
let displayColor = strengthColors[strengthLevels.indexOf(data.strength_level)];
|
|
|
|
if (data.errors && data.errors.length > 0) {
|
|
displayLevel += ' (Missing: ' + data.errors.join(', ') + ')';
|
|
displayColor = '#ff4444'; // Indicate error with red color
|
|
}
|
|
|
|
indicator.textContent = displayLevel;
|
|
indicator.style.color = displayColor;
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
indicator.textContent = 'Network Error';
|
|
indicator.style.color = '#ff4444';
|
|
});
|
|
}
|
|
|
|
// Clear password fields on page load for security
|
|
window.addEventListener('load', function() {
|
|
document.getElementById('old_password').value = '';
|
|
document.getElementById('new_password').value = '';
|
|
document.getElementById('verify_password').value = '';
|
|
});
|
|
|
|
// Add password strength indicator after new password field
|
|
window.addEventListener('DOMContentLoaded', function() {
|
|
const newPasswordCell = document.getElementById('new_password').parentNode;
|
|
const strengthIndicator = document.createElement('div');
|
|
strengthIndicator.id = 'password-strength-indicator';
|
|
strengthIndicator.className = 'password-strength-indicator';
|
|
strengthIndicator.textContent = 'Enter password to see strength';
|
|
newPasswordCell.appendChild(strengthIndicator);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|