/**
* 密码强度检测器
* 提供密码强度分析和安全建议
*/
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');
}
});