LibreTV / js /password.js
DD
Upload 47 files
f11ad89 verified
// 密码保护功能
/**
* 检查是否设置了密码保护
* 通过读取页面上嵌入的环境变量来检查
*/
function isPasswordProtected() {
// 只检查普通密码
const pwd = window.__ENV__ && window.__ENV__.PASSWORD;
// 检查普通密码是否有效
return typeof pwd === 'string' && pwd.length === 64 && !/^0+$/.test(pwd);
}
/**
* 检查是否强制要求设置密码
* 如果没有设置有效的 PASSWORD,则认为需要强制设置密码
* 为了安全考虑,所有部署都必须设置密码
*/
function isPasswordRequired() {
return !isPasswordProtected();
}
/**
* 强制密码保护检查 - 防止绕过
* 在关键操作前都应该调用此函数
*/
function ensurePasswordProtection() {
if (isPasswordRequired()) {
showPasswordModal();
throw new Error('Password protection is required');
}
if (isPasswordProtected() && !isPasswordVerified()) {
showPasswordModal();
throw new Error('Password verification required');
}
return true;
}
window.isPasswordProtected = isPasswordProtected;
window.isPasswordRequired = isPasswordRequired;
/**
* 验证用户输入的密码是否正确(异步,使用SHA-256哈希)
*/
async function verifyPassword(password) {
try {
const correctHash = window.__ENV__?.PASSWORD;
if (!correctHash) return false;
const inputHash = await sha256(password);
const isValid = inputHash === correctHash;
if (isValid) {
localStorage.setItem(PASSWORD_CONFIG.localStorageKey, JSON.stringify({
verified: true,
timestamp: Date.now(),
passwordHash: correctHash
}));
}
return isValid;
} catch (error) {
console.error('验证密码时出错:', error);
return false;
}
}
// 验证状态检查
function isPasswordVerified() {
try {
if (!isPasswordProtected()) return true;
const stored = localStorage.getItem(PASSWORD_CONFIG.localStorageKey);
if (!stored) return false;
const { timestamp, passwordHash } = JSON.parse(stored);
const currentHash = window.__ENV__?.PASSWORD;
return timestamp && passwordHash === currentHash &&
Date.now() - timestamp < PASSWORD_CONFIG.verificationTTL;
} catch (error) {
console.error('检查密码验证状态时出错:', error);
return false;
}
}
// 更新全局导出
window.isPasswordProtected = isPasswordProtected;
window.isPasswordRequired = isPasswordRequired;
window.isPasswordVerified = isPasswordVerified;
window.verifyPassword = verifyPassword;
window.ensurePasswordProtection = ensurePasswordProtection;
// SHA-256实现,可用Web Crypto API
async function sha256(message) {
if (window.crypto && crypto.subtle && crypto.subtle.digest) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// HTTP 下调用原始 js‑sha256
if (typeof window._jsSha256 === 'function') {
return window._jsSha256(message);
}
throw new Error('No SHA-256 implementation available.');
}
/**
* 显示密码验证弹窗
*/
function showPasswordModal() {
const passwordModal = document.getElementById('passwordModal');
if (passwordModal) {
// 防止出现豆瓣区域滚动条
document.getElementById('doubanArea').classList.add('hidden');
document.getElementById('passwordCancelBtn').classList.add('hidden');
// 检查是否需要强制设置密码
if (isPasswordRequired()) {
// 修改弹窗内容提示用户需要先设置密码
const title = passwordModal.querySelector('h2');
const description = passwordModal.querySelector('p');
if (title) title.textContent = '需要设置密码';
if (description) description.textContent = '请先在部署平台设置 PASSWORD 环境变量来保护您的实例';
// 隐藏密码输入框和提交按钮,只显示提示信息
const form = passwordModal.querySelector('form');
const errorMsg = document.getElementById('passwordError');
if (form) form.style.display = 'none';
if (errorMsg) {
errorMsg.textContent = '为确保安全,必须设置 PASSWORD 环境变量才能使用本服务,请联系管理员进行配置';
errorMsg.classList.remove('hidden');
errorMsg.className = 'text-red-500 mt-2 font-medium'; // 改为更醒目的红色
}
} else {
// 正常的密码验证模式
const title = passwordModal.querySelector('h2');
const description = passwordModal.querySelector('p');
if (title) title.textContent = '访问验证';
if (description) description.textContent = '请输入密码继续访问';
const form = passwordModal.querySelector('form');
if (form) form.style.display = 'block';
}
passwordModal.style.display = 'flex';
// 只有在非强制设置密码模式下才聚焦输入框
if (!isPasswordRequired()) {
// 确保输入框获取焦点
setTimeout(() => {
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.focus();
}
}, 100);
}
}
}
/**
* 隐藏密码验证弹窗
*/
function hidePasswordModal() {
const passwordModal = document.getElementById('passwordModal');
if (passwordModal) {
// 隐藏密码错误提示
hidePasswordError();
// 清空密码输入框
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) passwordInput.value = '';
passwordModal.style.display = 'none';
// 如果启用豆瓣区域则显示豆瓣区域
if (localStorage.getItem('doubanEnabled') === 'true') {
document.getElementById('doubanArea').classList.remove('hidden');
initDouban();
}
}
}
/**
* 显示密码错误信息
*/
function showPasswordError() {
const errorElement = document.getElementById('passwordError');
if (errorElement) {
errorElement.classList.remove('hidden');
}
}
/**
* 隐藏密码错误信息
*/
function hidePasswordError() {
const errorElement = document.getElementById('passwordError');
if (errorElement) {
errorElement.classList.add('hidden');
}
}
/**
* 处理密码提交事件(异步)
*/
async function handlePasswordSubmit() {
const passwordInput = document.getElementById('passwordInput');
const password = passwordInput ? passwordInput.value.trim() : '';
if (await verifyPassword(password)) {
hidePasswordModal();
// 触发密码验证成功事件
document.dispatchEvent(new CustomEvent('passwordVerified'));
} else {
showPasswordError();
if (passwordInput) {
passwordInput.value = '';
passwordInput.focus();
}
}
}
/**
* 初始化密码验证系统
*/
function initPasswordProtection() {
// 如果需要强制设置密码,显示警告弹窗
if (isPasswordRequired()) {
showPasswordModal();
return;
}
// 如果设置了密码但用户未验证,显示密码输入框
if (isPasswordProtected() && !isPasswordVerified()) {
showPasswordModal();
return;
}
}
// 在页面加载完成后初始化密码保护
document.addEventListener('DOMContentLoaded', function () {
initPasswordProtection();
});