/** * 密码强度检测器 * 提供密码强度分析和安全建议 */ 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 = '检测中...'; } else if (hasPassword) { checkBtn.innerHTML = '🔍检测密码强度'; } else { checkBtn.innerHTML = '🔍请输入密码'; } } } /** * 处理密码检测 */ 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 = ` ${hasType ? '✅' : '❌'} ${types[key].label} `; } }); // 更新字符种类数量 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 = ` ⚠️ ${issue.text} `; } 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 = ` ${this.getTipIcon(index)} ${tip} `; 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'); } });