Add in 12 character threshold and crypto checking
This commit is contained in:
165
python-flask/smeserver-password-app/templates/admin_panel.html
Normal file
165
python-flask/smeserver-password-app/templates/admin_panel.html
Normal file
@@ -0,0 +1,165 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Password Strength Configuration - SME Server</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<style>
|
||||
.admin-panel {
|
||||
max-width: 600px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.config-option {
|
||||
margin: 15px 0;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
.config-option.active {
|
||||
background-color: #e8f4f8;
|
||||
border-color: #007bff;
|
||||
}
|
||||
.config-option label {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
.config-description {
|
||||
font-size: 11px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.update-button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.update-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<a href="{{ url_for('password_change') }}" class="back-link">← Back to Password Change</a>
|
||||
|
||||
<h1>Password Strength Configuration</h1>
|
||||
|
||||
<div class="admin-panel">
|
||||
<p><strong>Current Setting:</strong> {{ current_setting|title }}</p>
|
||||
<p><strong>Description:</strong> {{ requirements.description }}</p>
|
||||
|
||||
<form id="config-form">
|
||||
<div class="config-option {{ 'active' if current_setting == 'none' else '' }}">
|
||||
<label>
|
||||
<input type="radio" name="strength" value="none" {{ 'checked' if current_setting == 'none' else '' }}>
|
||||
None
|
||||
</label>
|
||||
<div class="config-description">
|
||||
No specific password requirements. Only basic validation.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-option {{ 'active' if current_setting == 'normal' else '' }}">
|
||||
<label>
|
||||
<input type="radio" name="strength" value="normal" {{ 'checked' if current_setting == 'normal' else '' }}>
|
||||
Normal
|
||||
</label>
|
||||
<div class="config-description">
|
||||
Minimum 12 characters with at least one uppercase letter, lowercase letter, number, and special character.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-option {{ 'active' if current_setting == 'strong' else '' }}">
|
||||
<label>
|
||||
<input type="radio" name="strength" value="strong" {{ 'checked' if current_setting == 'strong' else '' }}>
|
||||
Strong
|
||||
</label>
|
||||
<div class="config-description">
|
||||
Normal requirements plus protection against common passwords, keyboard patterns, and dictionary words.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="update-button">Update Password Strength Setting</button>
|
||||
</form>
|
||||
|
||||
<div id="status-message" style="margin-top: 15px;"></div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>{{ version if version else 'SME Server 11 (beta1)' }} - Admin Panel</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Handle form submission
|
||||
document.getElementById('config-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
const strength = formData.get('strength');
|
||||
const statusMessage = document.getElementById('status-message');
|
||||
|
||||
// Update visual selection
|
||||
document.querySelectorAll('.config-option').forEach(option => {
|
||||
option.classList.remove('active');
|
||||
});
|
||||
|
||||
const selectedOption = document.querySelector('input[name="strength"]:checked').closest('.config-option');
|
||||
selectedOption.classList.add('active');
|
||||
|
||||
// Send update request
|
||||
fetch('/api/password-config', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ strength: strength })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
statusMessage.innerHTML = '<div style="color: green; font-weight: bold;">✓ ' + data.message + '</div>';
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
statusMessage.innerHTML = '<div style="color: red; font-weight: bold;">✗ Error: ' + (data.error || 'Unknown error') + '</div>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
statusMessage.innerHTML = '<div style="color: red; font-weight: bold;">✗ Network error: ' + error.message + '</div>';
|
||||
});
|
||||
});
|
||||
|
||||
// Handle radio button changes for visual feedback
|
||||
document.querySelectorAll('input[name="strength"]').forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
document.querySelectorAll('.config-option').forEach(option => {
|
||||
option.classList.remove('active');
|
||||
});
|
||||
this.closest('.config-option').classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -14,6 +14,12 @@
|
||||
<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 -->
|
||||
@@ -41,19 +47,34 @@
|
||||
<tr>
|
||||
<td class="label-cell">Old password:</td>
|
||||
<td class="input-cell">
|
||||
<input type="password" name="old_password" id="old_password" required>
|
||||
<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">
|
||||
<input type="password" name="new_password" id="new_password" required>
|
||||
<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">
|
||||
<input type="password" name="verify_password" id="verify_password" required>
|
||||
<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>
|
||||
@@ -73,7 +94,21 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Simple client-side validation
|
||||
// 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;
|
||||
@@ -84,19 +119,71 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
// Basic length check (server will do full validation)
|
||||
if (newPassword.length < 12) {
|
||||
e.preventDefault();
|
||||
alert('Password must be at least 8 characters long');
|
||||
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) {
|
||||
// Simple client-side strength indicator
|
||||
let strength = 0;
|
||||
let feedback = [];
|
||||
|
||||
if (password.length >= 12) strength++;
|
||||
else feedback.push('At least 12 characters');
|
||||
|
||||
if (/[A-Z]/.test(password)) strength++;
|
||||
else feedback.push('Uppercase letter');
|
||||
|
||||
if (/[a-z]/.test(password)) strength++;
|
||||
else feedback.push('Lowercase letter');
|
||||
|
||||
if (/\d/.test(password)) strength++;
|
||||
else feedback.push('Number');
|
||||
|
||||
if (/[^a-zA-Z0-9]/.test(password)) strength++;
|
||||
else feedback.push('Special character');
|
||||
|
||||
// Update visual indicator if it exists
|
||||
const indicator = document.getElementById('password-strength-indicator');
|
||||
if (indicator) {
|
||||
const strengthLevels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong'];
|
||||
const strengthColors = ['#ff4444', '#ff8800', '#ffaa00', '#88aa00', '#44aa44'];
|
||||
|
||||
indicator.textContent = strengthLevels[strength] || 'Very Weak';
|
||||
indicator.style.color = strengthColors[strength] || '#ff4444';
|
||||
|
||||
if (feedback.length > 0) {
|
||||
indicator.textContent += ' (Missing: ' + feedback.join(', ') + ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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>
|
||||
|
Reference in New Issue
Block a user