Files
InfoGenie/frontend/60sapi/实用功能/密码强度检测/js/script.js

516 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 密码强度检测器
* 提供密码强度分析和安全建议
*/
class PasswordStrengthChecker {
constructor() {
this.apiUrl = 'https://60s.api.shumengya.top/v2/password/check';
this.isChecking = false;
this.currentPassword = '';
this.init();
}
/**
* 初始化应用
*/
init() {
this.bindEvents();
this.setupFormValidation();
this.hideResultContainer();
this.hideErrorContainer();
console.log('密码强度检测器初始化完成');
}
/**
* 绑定事件监听器
*/
bindEvents() {
// 密码输入框事件
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.addEventListener('input', this.handlePasswordInput.bind(this));
passwordInput.addEventListener('keypress', this.handleKeyPress.bind(this));
}
// 显示/隐藏密码按钮
const toggleBtn = document.getElementById('toggleVisibility');
if (toggleBtn) {
toggleBtn.addEventListener('click', this.togglePasswordVisibility.bind(this));
}
// 检测按钮
const checkBtn = document.getElementById('checkBtn');
if (checkBtn) {
checkBtn.addEventListener('click', this.handleCheckPassword.bind(this));
}
// 重试按钮
const retryBtn = document.getElementById('retryBtn');
if (retryBtn) {
retryBtn.addEventListener('click', this.handleRetry.bind(this));
}
}
/**
* 设置表单验证
*/
setupFormValidation() {
const form = document.querySelector('.input-container');
if (form) {
form.addEventListener('submit', (e) => {
e.preventDefault();
this.handleCheckPassword();
});
}
}
/**
* 处理密码输入
*/
handlePasswordInput(event) {
const password = event.target.value;
this.currentPassword = password;
// 更新按钮状态
this.updateCheckButtonState();
// 如果密码为空,隐藏结果
if (!password.trim()) {
this.hideResultContainer();
this.hideErrorContainer();
}
}
/**
* 处理键盘事件
*/
handleKeyPress(event) {
if (event.key === 'Enter' && !this.isChecking) {
event.preventDefault();
this.handleCheckPassword();
}
}
/**
* 切换密码可见性
*/
togglePasswordVisibility() {
const passwordInput = document.getElementById('passwordInput');
const toggleBtn = document.getElementById('toggleVisibility');
if (passwordInput && toggleBtn) {
const isPassword = passwordInput.type === 'password';
passwordInput.type = isPassword ? 'text' : 'password';
toggleBtn.innerHTML = isPassword ? '🙈' : '👁️';
toggleBtn.title = isPassword ? '隐藏密码' : '显示密码';
}
}
/**
* 更新检测按钮状态
*/
updateCheckButtonState() {
const checkBtn = document.getElementById('checkBtn');
const hasPassword = this.currentPassword.trim().length > 0;
if (checkBtn) {
checkBtn.disabled = !hasPassword || this.isChecking;
if (this.isChecking) {
checkBtn.innerHTML = '<span class="btn-icon">⏳</span>检测中...';
} else if (hasPassword) {
checkBtn.innerHTML = '<span class="btn-icon">🔍</span>检测密码强度';
} else {
checkBtn.innerHTML = '<span class="btn-icon">🔍</span>请输入密码';
}
}
}
/**
* 处理密码检测
*/
async handleCheckPassword() {
const password = this.currentPassword.trim();
if (!password) {
this.showToast('请输入要检测的密码', 'error');
return;
}
if (this.isChecking) {
return;
}
try {
this.setLoadingState(true);
this.hideErrorContainer();
const result = await this.checkPasswordStrength(password);
if (result.code === 200 && result.data) {
this.displayResults(result.data);
this.showResultContainer();
this.showToast('密码强度检测完成', 'success');
} else {
throw new Error(result.message || '检测失败');
}
} catch (error) {
console.error('密码检测错误:', error);
this.showError(error.message || '检测服务暂时不可用,请稍后重试');
} finally {
this.setLoadingState(false);
}
}
/**
* 调用API检测密码强度
*/
async checkPasswordStrength(password) {
const url = new URL(this.apiUrl);
url.searchParams.append('password', password);
url.searchParams.append('encoding', 'utf-8');
const response = await fetch(url.toString(), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
/**
* 显示检测结果
*/
displayResults(data) {
this.updateStrengthOverview(data);
this.updateDetailedInfo(data);
this.updateRecommendations(data);
}
/**
* 更新强度概览
*/
updateStrengthOverview(data) {
// 更新分数圆圈
const scoreCircle = document.getElementById('scoreCircle');
const scoreValue = document.getElementById('scoreValue');
const strengthLevel = document.getElementById('strengthLevel');
const strengthDescription = document.getElementById('strengthDescription');
const barFill = document.getElementById('strengthBar');
if (scoreValue) {
scoreValue.textContent = data.score || 0;
}
if (strengthLevel) {
strengthLevel.textContent = this.getStrengthText(data.strength);
const strengthClass = this.getStrengthClass(data.strength);
strengthLevel.className = `strength-level strength-${strengthClass}`;
}
if (strengthDescription) {
strengthDescription.textContent = this.getStrengthDescription(data.strength);
}
// 更新分数圆圈
if (scoreCircle) {
const percentage = (data.score / 100) * 360;
scoreCircle.style.setProperty('--score-deg', `${percentage}deg`);
// 将中文强度转换为CSS类名
const strengthClass = this.getStrengthClass(data.strength);
scoreCircle.className = `score-circle score-${strengthClass}`;
}
// 更新强度条
if (barFill) {
setTimeout(() => {
barFill.style.width = `${data.score}%`;
}, 100);
}
}
/**
* 更新详细信息
*/
updateDetailedInfo(data) {
// 基本信息
this.updateElement('passwordLength', data.length || 0);
this.updateElement('entropyValue', data.entropy ? data.entropy.toFixed(2) : '0.00');
this.updateElement('crackTime', data.time_to_crack || '未知');
// 字符类型分析
this.updateCharacterAnalysis(data.character_analysis || {});
}
/**
* 更新字符类型分析
*/
updateCharacterAnalysis(analysis) {
const types = {
'has_lowercase': { element: 'hasLowercase', label: '小写字母', icon: '🔤' },
'has_uppercase': { element: 'hasUppercase', label: '大写字母', icon: '🔠' },
'has_numbers': { element: 'hasNumbers', label: '数字', icon: '🔢' },
'has_symbols': { element: 'hasSymbols', label: '特殊符号', icon: '🔣' }
};
Object.keys(types).forEach(key => {
const element = document.getElementById(types[key].element);
if (element) {
const hasType = analysis[key] || false;
element.className = `char-type ${hasType ? 'has-type' : ''}`;
element.innerHTML = `
<span class="type-icon">${hasType ? '✅' : '❌'}</span>
<span>${types[key].label}</span>
`;
}
});
// 更新字符种类数量
this.updateElement('characterVariety', analysis.character_variety || 0);
// 更新问题提示
this.updateCharacterIssues(analysis);
}
/**
* 更新字符问题提示
*/
updateCharacterIssues(analysis) {
const issues = [
{ id: 'hasRepeated', condition: analysis.has_repeated, text: '包含重复字符' },
{ id: 'hasSequential', condition: analysis.has_sequential, text: '包含连续字符' }
];
issues.forEach(issue => {
const element = document.getElementById(issue.id);
if (element) {
if (issue.condition) {
element.style.display = 'flex';
element.innerHTML = `
<span class="issue-icon">⚠️</span>
<span class="issue-text">${issue.text}</span>
`;
} else {
element.style.display = 'none';
}
}
});
}
/**
* 更新建议和提示
*/
updateRecommendations(data) {
// 更新建议列表
const recommendationsList = document.getElementById('recommendationsList');
if (recommendationsList && data.recommendations) {
recommendationsList.innerHTML = '';
data.recommendations.forEach(recommendation => {
const li = document.createElement('li');
li.textContent = recommendation;
recommendationsList.appendChild(li);
});
}
// 更新安全提示
const tipsContainer = document.getElementById('securityTips');
if (tipsContainer && data.security_tips) {
tipsContainer.innerHTML = '';
data.security_tips.forEach((tip, index) => {
const tipElement = document.createElement('div');
tipElement.className = 'tip-item';
tipElement.innerHTML = `
<span class="tip-icon">${this.getTipIcon(index)}</span>
<span class="tip-text">${tip}</span>
`;
tipsContainer.appendChild(tipElement);
});
}
}
/**
* 获取提示图标
*/
getTipIcon(index) {
const icons = ['🛡️', '🔐', '⚡', '🎯', '💡', '🔄'];
return icons[index % icons.length];
}
/**
* 获取强度文本
*/
getStrengthText(strength) {
// API直接返回中文强度无需映射
return strength || '未知';
}
/**
* 获取强度CSS类名
*/
getStrengthClass(strength) {
const classMap = {
'弱': 'weak',
'中等': 'medium',
'强': 'strong',
'非常强': 'very-strong'
};
return classMap[strength] || 'unknown';
}
/**
* 获取强度描述
*/
getStrengthDescription(strength) {
const descriptions = {
'弱': '密码强度较弱,建议增加复杂度',
'中等': '密码强度中等,可以进一步优化',
'强': '密码强度良好,安全性较高',
'非常强': '密码强度非常好,安全性很高'
};
return descriptions[strength] || '无法评估密码强度';
}
/**
* 设置加载状态
*/
setLoadingState(loading) {
this.isChecking = loading;
this.updateCheckButtonState();
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.disabled = loading;
}
}
/**
* 显示结果容器
*/
showResultContainer() {
const container = document.getElementById('resultContainer');
if (container) {
container.style.display = 'block';
container.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
/**
* 隐藏结果容器
*/
hideResultContainer() {
const container = document.getElementById('resultContainer');
if (container) {
container.style.display = 'none';
}
}
/**
* 显示错误
*/
showError(message) {
const errorContainer = document.getElementById('errorContainer');
const errorMessage = document.getElementById('errorMessage');
if (errorContainer && errorMessage) {
errorMessage.textContent = message;
errorContainer.style.display = 'block';
this.hideResultContainer();
errorContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
/**
* 隐藏错误容器
*/
hideErrorContainer() {
const container = document.getElementById('errorContainer');
if (container) {
container.style.display = 'none';
}
}
/**
* 处理重试
*/
handleRetry() {
this.hideErrorContainer();
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.focus();
}
}
/**
* 更新元素内容
*/
updateElement(id, content) {
const element = document.getElementById(id);
if (element) {
element.textContent = content;
}
}
/**
* 显示提示消息
*/
showToast(message, type = 'success') {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
if (toast && toastMessage) {
toastMessage.textContent = message;
toast.className = `toast toast-${type}`;
toast.style.display = 'block';
// 3秒后自动隐藏
setTimeout(() => {
toast.style.display = 'none';
}, 3000);
}
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
try {
window.passwordChecker = new PasswordStrengthChecker();
console.log('密码强度检测器已启动');
} catch (error) {
console.error('初始化失败:', error);
}
});
// 页面可见性变化处理
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible' && window.passwordChecker) {
console.log('页面重新激活');
}
});
// 全局错误处理
window.addEventListener('error', (event) => {
console.error('全局错误:', event.error);
if (window.passwordChecker) {
window.passwordChecker.showToast('发生了意外错误,请刷新页面重试', 'error');
}
});
// 网络状态监听
window.addEventListener('online', () => {
if (window.passwordChecker) {
window.passwordChecker.showToast('网络连接已恢复', 'success');
}
});
window.addEventListener('offline', () => {
if (window.passwordChecker) {
window.passwordChecker.showToast('网络连接已断开', 'error');
}
});