chore: 重写初始提交(清空历史,整理后全量提交)

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
+482
View File
@@ -0,0 +1,482 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔐 端到端加密聊天</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif
}
body {
background: #f0f2f5;
padding: 20px;
max-width: 900px;
margin: 0 auto
}
.header {
text-align: center;
margin-bottom: 20px;
padding: 15px;
background: #1a73e8;
color: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1)
}
.chat-container {
display: flex;
gap: 20px
}
.panel {
background: white;
border-radius: 12px;
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.1);
padding: 20px;
flex: 1
}
.title {
font-size: 18px;
margin-bottom: 15px;
color: #1a73e8;
display: flex;
align-items: center;
gap: 8px
}
.title i {
font-size: 20px
}
#chatBox {
height: 400px;
overflow-y: auto;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 15px;
margin-bottom: 15px;
background: #fafafa;
line-height: 1.6
}
.msg {
margin-bottom: 12px;
padding: 10px 15px;
border-radius: 18px;
max-width: 80%
}
.sent {
background: #e3f2fd;
margin-left: auto;
border-bottom-right-radius: 5px
}
.received {
background: #f1f8e9;
border-bottom-left-radius: 5px
}
.sys {
background: #fff8e1;
color: #5d4037;
font-size: 13px;
text-align: center;
margin: 5px 0
}
.input-area {
display: flex;
gap: 10px
}
textarea {
flex: 1;
padding: 12px;
border: 1px solid #ddd;
border-radius: 20px;
resize: none;
font-size: 15px;
height: 45px
}
button {
background: #1a73e8;
color: white;
border: none;
border-radius: 20px;
padding: 0 25px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s
}
button:hover {
background: #0d5bbb;
transform: scale(1.03)
}
button:disabled {
background: #b0b0b0;
cursor: not-allowed;
transform: none
}
.status {
padding: 8px;
border-radius: 6px;
margin-top: 10px;
font-size: 14px;
text-align: center
}
.status.connected {
background: #e8f5e9;
color: #2e7d32
}
.status.connecting {
background: #e3f2fd;
color: #1565c0
}
.status.error {
background: #ffebee;
color: #c62828
}
.debug {
background: #2d2d2d;
color: #64dd17;
padding: 10px;
border-radius: 6px;
margin-top: 15px;
font-family: monospace;
font-size: 13px;
max-height: 150px;
overflow: auto;
display: none
}
.badge {
background: #e3f2fd;
color: #1565c0;
padding: 2px 8px;
border-radius: 10px;
font-size: 12px;
margin-left: 5px
}
@media (max-width:768px) {
.chat-container {
flex-direction: column
}
}
</style>
</head>
<body>
<div class="header">
<h1>🔐 端到端加密聊天 <span class="badge">微信级安全</span></h1>
<div style="margin-top:8px; font-size:14px; opacity:0.9">AES-256-CBC加密 | SHA1签名验证 | 防篡改防重放</div>
</div>
<div class="chat-container">
<div class="panel">
<div class="title">💬 聊天窗口</div>
<div id="chatBox"></div>
<div class="input-area">
<textarea id="messageInput" placeholder="输入消息... (按Ctrl+Enter发送)" disabled></textarea>
<button id="sendBtn" disabled>发送</button>
</div>
<div id="statusBar" class="status connecting">⏳ 正在连接服务器...</div>
<button id="toggleDebug" style="margin-top:10px; padding:5px 15px; background:#f5f5f5; color:#5f6368">显示调试日志</button>
<div id="debugLog" class="debug"></div>
</div>
<div class="panel">
<div class="title">⚙️ 连接配置</div>
<div style="margin-bottom:15px">
<div style="margin-bottom:8px"><strong>用户ID:</strong></div>
<input type="text" id="userId" value="user_<?= bin2hex(random_bytes(4)) ?>" style="width:100%; padding:10px; border:1px solid #ddd; border-radius:6px">
</div>
<div style="margin-bottom:15px">
<div style="margin-bottom:8px"><strong>服务器地址:</strong></div>
<input type="text" id="serverUrl" value="wss://dev.xixingwl.cn:2346" style="width:100%; padding:10px; border:1px solid #ddd; border-radius:6px">
</div>
<button id="connectBtn" style="width:100%; background:#34a853">🔌 连接服务器</button>
<div style="margin-top:20px; padding:12px; background:#e8f0fe; border-radius:8px; font-size:13px; line-height:1.5">
<strong>🔒 安全说明:</strong><br>
• 所有消息端到端加密,服务器无法查看内容<br>
• 每条消息独立签名,防篡改防伪造<br>
• 时间戳验证,防止消息重放攻击
</div>
</div>
</div>
<script src="/assets/ywxapp/modules/aescgm.js"></script>
<script>
// =============== 聊天客户端 ===============
class ChatClient {
constructor() {
this.ws = null;
this.crypto = null;
this.userId = '';
this.isConnected = false;
this.initUI();
}
initUI() {
// DOM元素
this.chatBox = document.getElementById('chatBox');
this.messageInput = document.getElementById('messageInput');
this.sendBtn = document.getElementById('sendBtn');
this.statusBar = document.getElementById('statusBar');
this.connectBtn = document.getElementById('connectBtn');
this.toggleDebug = document.getElementById('toggleDebug');
this.debugLog = document.getElementById('debugLog');
// 事件绑定
this.connectBtn.onclick = () => this.connect();
this.sendBtn.onclick = () => this.sendMessage();
this.messageInput.onkeypress = (e) => {
if (e.ctrlKey && e.key === 'Enter') this.sendMessage();
};
this.toggleDebug.onclick = () => {
this.debugLog.style.display = this.debugLog.style.display === 'none' ? 'block' : 'none';
};
// 初始化状态
this.updateStatus('⏳ 未连接,请配置后点击连接', 'connecting');
}
log(msg, type = 'info') {
const prefix = type === 'error' ? '❌' : type === 'success' ? '✅' : '️';
this.debugLog.innerHTML += `<span style="color:${type === 'error' ? '#ff5252' : type === 'success' ? '#4caf50' : '#aaa'}">${prefix} ${msg}</span><br>`;
this.debugLog.scrollTop = this.debugLog.scrollHeight;
console.log(`[ChatClient] ${msg}`);
}
updateStatus(text, className) {
this.statusBar.textContent = text;
this.statusBar.className = `status ${className}`;
}
addMessage(text, type = 'received', user = '系统') {
const div = document.createElement('div');
div.className = type === 'sys' ? 'sys' : `msg ${type}`;
if (type === 'sys') {
div.innerHTML = text;
} else {
div.innerHTML = `<strong>${user}:</strong> ${this.escapeHtml(text)}`;
}
this.chatBox.appendChild(div);
this.chatBox.scrollTop = this.chatBox.scrollHeight;
}
escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
async connect() {
try {
this.userId = document.getElementById('userId').value.trim() || 'anonymous';
const serverUrl = document.getElementById('serverUrl').value.trim();
if (!serverUrl.startsWith('ws://') && !serverUrl.startsWith('wss://')) {
throw new Error('服务器地址必须以 ws:// 或 wss:// 开头');
}
this.updateStatus('🔄 正在连接...', 'connecting');
this.connectBtn.disabled = true;
// 创建WebSocket
this.ws = new WebSocket(serverUrl);
this.ws.onopen = () => {
this.log('WebSocket连接已建立');
// 发送认证请求
this.ws.send(JSON.stringify({
action: 'auth',
token: 'your_secure_token_123456', // 与服务端约定
user_id: this.userId
}));
};
this.ws.onmessage = (event) => this.handleMessage(event.data);
this.ws.onerror = (error) => {
this.log(`连接错误: ${error.message}`, 'error');
this.log(error);
this.updateStatus('❌ 连接失败: ' + error.message, 'error');
this.connectBtn.disabled = false;
};
this.ws.onclose = () => {
this.isConnected = false;
this.log('连接已关闭', 'error');
if (this.isConnected) {
this.updateStatus('⚠️ 连接意外断开', 'error');
this.addMessage('连接已断开', 'sys');
}
this.connectBtn.disabled = false;
this.messageInput.disabled = true;
this.sendBtn.disabled = true;
};
} catch (e) {
this.log(`连接异常: ${e.message}`, 'error');
this.updateStatus('❌ ' + e.message, 'error');
this.connectBtn.disabled = false;
}
}
handleMessage(data) {
try {
const msg = JSON.parse(data);
// 认证响应
if (msg.action === 'auth_success') {
// 初始化加密模块 (使用服务端返回的密钥)
this.crypto = new ChatCrypto(
msg.encodingAesKey,
'your_secure_token_123456',
'CHAT_APP_2024'
);
this.isConnected = true;
this.updateStatus(`✅ 已连接 | 会话ID: ${msg.session_id.substring(0, 8)}...`, 'connected');
this.addMessage(`欢迎 ${this.userId}!端到端加密已启用`, 'sys');
this.messageInput.disabled = false;
this.sendBtn.disabled = false;
this.connectBtn.textContent = '🔌 已连接';
this.connectBtn.style.background = '#9e9e9e';
this.connectBtn.disabled = true;
this.log('认证成功,加密模块已初始化', 'success');
return;
}
// 错误处理
if (msg.error) {
this.log(`服务端错误: ${msg.error} (代码: ${msg.code})`, 'error');
if (msg.code === 401) {
this.updateStatus('❌ 认证失败,请检查token', 'error');
this.ws.close();
}
this.addMessage(`[系统] ${msg.error}`, 'sys');
return;
}
// =============== 接收聊天消息 ===============
// 验证签名
if (!this.crypto.verifySignature(
msg.signature,
msg.timestamp,
msg.nonce,
msg.encrypt
)) {
this.addMessage(`[警告] 消息签名验证失败,来源: ${msg.from_user}`, 'sys');
this.log(`收到无效签名消息 (来源: ${msg.from_user})`, 'error');
return;
}
// 防重放检查
if (Math.abs(Date.now() / 1000 - msg.timestamp) > 300) {
this.log(`收到过期消息 (时间差: ${Math.abs(Date.now() / 1000 - msg.timestamp)}秒)`, 'error');
return;
}
// 解密消息
try {
const plainText = this.crypto.decrypt(msg.encrypt);
const chatData = JSON.parse(plainText);
this.addMessage(chatData.content, 'received', chatData.from_user || msg.from_user);
this.log(`收到消息: "${chatData.content.substring(0, 20)}..." (来源: ${msg.from_user})`, 'success');
} catch (e) {
this.addMessage(`[系统] 消息解密失败: ${e.message}`, 'sys');
this.log(`解密异常: ${e.message}`, 'error');
}
} catch (e) {
this.log(`消息处理异常: ${e.message}`, 'error');
console.error(e);
}
}
sendMessage() {
const content = this.messageInput.value.trim();
if (!content || !this.isConnected || !this.crypto) return;
try {
// 构建消息体
const chatMsg = {
content: content,
type: 'text',
timestamp: Math.floor(Date.now() / 1000)
};
console.log('原始消息体:', chatMsg);
console.log('加密前消息体字符串:', JSON.stringify(chatMsg));
console.log('加密前消息体字符串:', window.encryptJson(chatMsg, 'your_secure_token_123456'));
// 加密
const encryptMsg = this.crypto.encrypt(JSON.stringify(chatMsg));
// 生成签名参数
const timestamp = Math.floor(Date.now() / 1000);
const nonce = this.crypto.getRandomStr(10);
const signature = this.crypto.generateSignature(timestamp, nonce, encryptMsg);
// 发送
this.ws.send(JSON.stringify({
encrypt: encryptMsg,
signature: signature,
timestamp: timestamp,
nonce: nonce
}));
// 显示到聊天框
this.addMessage(content, 'sent', this.userId);
this.messageInput.value = '';
this.log(`发送消息: "${content.substring(0, 20)}..."`, 'success');
} catch (e) {
this.log(`发送失败: ${e.message}`, 'error');
alert('发送失败: ' + e.message);
}
}
}
const aes = new AESGCM();
// 加密示例
aes.encrypt('Hello World!', 'mypassword')
.then(encrypted => {
console.log('加密结果:', encrypted);
// 解密示例
return aes.decrypt(encrypted, 'mypassword');
})
.then(decrypted => {
console.log('解密结果:', decrypted);
})
.catch(error => {
console.error('操作失败:', error);
});
// 初始化
document.addEventListener('DOMContentLoaded', () => {
console.log('页面加载完成,正在初始化聊天客户端...');
window.chatClient = new ChatClient();
document.getElementById('messageInput').focus();
});
</script>
</body>
</html>