From ec5fcf1ee755ce1cb54dc7ee635b87d53dcabb91 Mon Sep 17 00:00:00 2001 From: Miao_Spring <539943419@qq.com> Date: Fri, 22 Mar 2024 16:38:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BF=83=E8=B7=B3=E5=8C=85?= =?UTF-8?q?=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 15 ++++++ package.json | 3 ++ server.js | 122 +++++++++++++++++++++++++++------------------ src/func/upload.js | 16 ++++-- src/views/chat.vue | 60 ++++++++++++++++------ 5 files changed, 149 insertions(+), 67 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4da92f9..c1521ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,12 @@ "js-base64": "^3.7.6", "pinia": "^2.1.7", "sm-crypto": "^0.3.13", + "uuid": "^9.0.1", "vicons": "^0.0.1", "vue": "^3.4.15", "vue-clipboard3": "^2.0.0", "vue-router": "^4.2.5", + "websocket-heartbeat-js": "^1.1.3", "ws": "^8.16.0" }, "devDependencies": { @@ -2359,6 +2361,14 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", @@ -2514,6 +2524,11 @@ "vue": "^3.0.11" } }, + "node_modules/websocket-heartbeat-js": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/websocket-heartbeat-js/-/websocket-heartbeat-js-1.1.3.tgz", + "integrity": "sha512-wiCMVsWK7KflVCC5f+rSTyzILDZX88A7BJfdJXt5THNDut7uUNP83r5AvdZ1El/8yOwGujC7K3iuxj96CT4gbQ==" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 4292980..f25e9d3 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "type": "module", "scripts": { + "vite": "vite", "dev": "concurrently \"node server.js\" \"vite\"", "server": "concurrently \"node server.js\"", "miaoShare": "concurrently \"node server.js\" \"vite\"", @@ -18,10 +19,12 @@ "js-base64": "^3.7.6", "pinia": "^2.1.7", "sm-crypto": "^0.3.13", + "uuid": "^9.0.1", "vicons": "^0.0.1", "vue": "^3.4.15", "vue-clipboard3": "^2.0.0", "vue-router": "^4.2.5", + "websocket-heartbeat-js": "^1.1.3", "ws": "^8.16.0" }, "devDependencies": { diff --git a/server.js b/server.js index c75f17e..c3b7997 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ import Database from "better-sqlite3"; import fs from "fs"; import { WebSocketServer } from "ws"; import http from "http"; +import { v4 as uuid4 } from "uuid"; // import Config from "./miaoShareConfig.json" const HOST = "0.0.0.0"; @@ -122,9 +123,9 @@ function generateId(isGID) { charStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (var i = 0; i < range; i++) { - if(isGID === true && i == 0){ + if (isGID === true && i == 0) { var index = parseInt(Math.random() * 26); - }else{ + } else { var index = parseInt(Math.random() * 36); } returnStr += charStr.substring(index, index + 1); @@ -232,19 +233,20 @@ const groupsMap = {}; // 三天不活跃的群组将被清除 const LifeOfGroup = millisecondsOfOneDay * 3; // const LifeOfGroup = 0; - +// 根据uuid查询加入的群组 +const uuid2Groups={} db.exec( `CREATE TABLE IF NOT EXISTS GROUPS ( gID CHAR(8) PRIMARY KEY UNIQUE NOT NULL, verify TEXT NOT NULL, activeTimestamp INT NOT NULL -);`) - +);` +); const stmt_getExpiredGroups = db.prepare(`SELECT gID FROM GROUPS WHERE activeTimestamp < ? `); -const stmt_getGroupVerify = db.prepare(`SELECT verify FROM GROUPS WHERE gID = ? `) +const stmt_getGroupVerify = db.prepare(`SELECT verify FROM GROUPS WHERE gID = ? `); const stmt_insertGROUPS = db.prepare(`INSERT INTO GROUPS (gID,verify, activeTimestamp) VALUES (?, ?, ?)`); @@ -252,98 +254,113 @@ const stmt_updateGROUPS_ActiveTimestamp = db.prepare(`UPDATE GROUPS SET activeTi const stmt_deleteGroup = db.prepare(`DELETE FROM GROUPS WHERE gID=?`); -const generateStmt_insertMessage_map = {} - +const generateStmt_insertMessage_map = {}; const updateGROUPS = () => { // console.log(1) try { let gIDs = stmt_getExpiredGroups.all(parseInt(Date.now()) - LifeOfGroup); for (let row of gIDs) { - let gID = row.gID - db.exec(`DROP TABLE IF EXISTS ${gID}`) - stmt_deleteGroup.run(gID) + let gID = row.gID; + db.exec(`DROP TABLE IF EXISTS ${gID}`); + stmt_deleteGroup.run(gID); } } catch (e) { console.log(e); return; } }; -updateGROUPS() -setInterval(updateGROUPS,1000*3600*3) +updateGROUPS(); +setInterval(updateGROUPS, 1000 * 3600 * 3); // 创建群组的数据库 -function createGroupTableDB(gID,verify){ +function createGroupTableDB(gID, verify) { db.exec( `CREATE TABLE IF NOT EXISTS ${gID} ( message TEXT NOT NULL, type TEXT NOT NULL, sender TEXT NOT NULL, timestamp INT NOT NULL - );`) - stmt_insertGROUPS.run(gID,verify,parseInt(Date.now())) + );` + ); + stmt_insertGROUPS.run(gID, verify, parseInt(Date.now())); } // 插入信息 -function insertMessageByGID(gID,msg,sender){ - if(!generateStmt_insertMessage_map[gID]){ +function insertMessageByGID(gID, msg, from) { + if (!generateStmt_insertMessage_map[gID]) { generateStmt_insertMessage_map[gID] = db.prepare(`INSERT INTO ${gID} (message,type,sender, timestamp) VALUES (?, ?, ?, ?)`); } - generateStmt_insertMessage_map[gID].run(msg,'gMsg',sender,parseInt(Date.now())) + generateStmt_insertMessage_map[gID].run(msg, "gMsg", from, parseInt(Date.now())); } -function updateActiveTimestamp(gID){ - stmt_updateGROUPS_ActiveTimestamp.run(parseInt(Date.now()),gID) +function updateActiveTimestamp(gID) { + stmt_updateGROUPS_ActiveTimestamp.run(parseInt(Date.now()), gID); } function createGroup(verify) { // 暂时不考虑id随机生成时重复的问题 let gID = generateId(true); groupsMap[gID] = { verify, member: [], msgHistory: [] }; - createGroupTableDB(gID,verify) + createGroupTableDB(gID, verify); return gID; } function getGroupVerify(gID) { - if(!groupsMap[gID]){ - let verify = stmt_getGroupVerify.get(gID).verify - // 暂时这么写 - let msgHistory = db.prepare(`SELECT message,type FROM ${gID}`).all().map(v=>{ - return {msg: v.message,type:v.type} - }) - // console.log(msgHistory) - groupsMap[gID] = { verify, member: [], msgHistory}; - } + initMsgHistory(gID) return groupsMap[gID].verify; } // 正式加入群组 function joinGroup(socket, gID, callback) { + initMsgHistory(gID) groupsMap[gID].member.push(socket); - updateActiveTimestamp(gID) + updateActiveTimestamp(gID); callback(); } // 暂时这么写 function getHistory(gID) { + initMsgHistory(gID) return groupsMap[gID].msgHistory; } -function broadcastMsg(gID, msg) { - updateActiveTimestamp(gID) - insertMessageByGID(gID,msg,'NULL') +function broadcastMsg(gID, msg, from) { + initMsgHistory(gID) + updateActiveTimestamp(gID); + insertMessageByGID(gID, msg, from); - let bmsg = JSON.stringify({ type: "gMsg", gID, msg }) - groupsMap[gID].msgHistory.push({ type: "gMsg", msg }); + let bmsg = JSON.stringify({ type: "gMsg", gID, msg }); + groupsMap[gID].msgHistory.push({ type: "gMsg", msg, from }); for (let socket of groupsMap[gID].member) { socket.send(bmsg); } } +function initMsgHistory(gID){ + if (!groupsMap[gID]) { + let verify = stmt_getGroupVerify.get(gID).verify; + // 暂时这么写 + let msgHistory = db + .prepare(`SELECT message,type FROM ${gID}`) + .all() + .map(v => { + return { msg: v.message, type: v.type }; + }); + // console.log(msgHistory) + groupsMap[gID] = { verify, member: [], msgHistory }; + } +} + +// 灵车 wss.on("connection", socket => { console.log("新的连接已建立"); const no = wss.clients.size; - const joinedGroup = [] + const joinedGroup = []; + var uuid = uuid4(); + function setUuid(new_uuid){ + uuid = new_uuid + } socket.on("message", message => { try { console.log(message.toString()); @@ -357,38 +374,45 @@ wss.on("connection", socket => { // 加入群组——客端验证key if (msg.type1 === "verify") { // 已经加入则return - if(joinedGroup.includes(msg.gID)){ - return + if (joinedGroup.includes(msg.gID)) { + return; } socket.send(JSON.stringify({ type: "sMsg", type1: "joinVerify", verify: getGroupVerify(msg.gID), gID: msg.gID })); } else if (msg.type1 === "success") { - if(joinedGroup.includes(msg.gID)){ - return + if (joinedGroup.includes(msg.gID)) { + return; } // 成功加入 joinGroup(socket, msg.gID, () => { - joinedGroup.push(msg.gID) + joinedGroup.push(msg.gID); // 不考虑失败属于是 - socket.send(JSON.stringify({ type: "sMsg",gID:msg.gID, type1: "history", history: JSON.stringify(getHistory(msg.gID)) })); + socket.send(JSON.stringify({ type: "sMsg", gID: msg.gID, type1: "history", history: JSON.stringify(getHistory(msg.gID)) })); }); } } else if (type === "message") { let gID = msg.gID; - broadcastMsg(gID, msg.msg); + broadcastMsg(gID, msg.msg,uuid); + } else if (type === "heartbeat") { + socket.send(JSON.stringify({ type: "sMsg", type1: "heartbeat" })); + } else if (type === "uuid") { + if (msg.type1 === "get") { + socket.send(JSON.stringify({ type: "sMsg", type1: "uuid", uuid })); + } else if (msg.type1 === "set") { + uuid = msg.uuid + } } } } catch (e) { - console.log(e); } }); socket.on("close", () => { - for(let gID of joinedGroup){ - groupsMap[gID].member = groupsMap[gID].member.filter(v=>v!==socket) + for (let gID of joinedGroup) { + groupsMap[gID].member = groupsMap[gID].member.filter(v => v !== socket); } console.log(`No.${no} exit.`); - console.log(groupsMap) + console.log(groupsMap); }); }); diff --git a/src/func/upload.js b/src/func/upload.js index aa4cca3..1cb6bb8 100644 --- a/src/func/upload.js +++ b/src/func/upload.js @@ -61,12 +61,16 @@ const SM4 = (key,data)=>{ return new Uint8Array(encryptedBytes); } const encrypt = (key, data, fileName, setting, message) => { + // if(!encryptFunction){ + // encryptFunction = setting.activeFuction + // } + let encryptFunction = {0:'不加密',16:'AES128',19:'SM4',32:'AES256'}[key.length] return blob2Uint8Array(data).then(data => { let encrypted_data = null - if(setting.activeFuction === "不加密"){ + if(encryptFunction === "不加密"|| key === ''){ encrypted_data = data // AES - }else if(setting.activeFuction != "SM4"){ + }else if(encryptFunction != "SM4"){ message.info(`开始加密${fileName}`); encrypted_data = AES(key,data) message.info(`${fileName}加密完成`); @@ -83,11 +87,15 @@ const encrypt = (key, data, fileName, setting, message) => { // setting为pinia存储的setting。。。 const encryptString = (key, str, setting) => { + // if(!encryptFunction){ + // encryptFunction = setting.activeFuction + // } // console.log(key,key.length) - if(setting.activeFuction === "不加密" || key === ''){ + let encryptFunction = {0:'不加密',16:'AES128',19:'SM4',32:'AES256'}[key.length] + if(encryptFunction === "不加密" || key === ''){ // return sm4.encrypt(str, 'miaospringmiaospringmiaospringao') return Base64.encode(str) - }else if(setting.activeFuction !== "SM4"){ + }else if(encryptFunction !== "SM4"){ key = aesjs.utils.utf8.toBytes(key); var data = aesjs.utils.utf8.toBytes(str); var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); diff --git a/src/views/chat.vue b/src/views/chat.vue index ca56dfc..901f8d8 100644 --- a/src/views/chat.vue +++ b/src/views/chat.vue @@ -38,6 +38,7 @@ import {NText,NDataTable,NButton,NInput} from 'naive-ui' import { useSettingStore } from "@/pinia/store"; import { generateKey,encryptString } from '@/func/upload'; import { decryptString } from '@/func/download'; +import WebsocketHeartbeatJs from 'websocket-heartbeat-js'; @@ -61,18 +62,26 @@ const codeInput = ref('') const key = ref('') const msg = ref('') const joinedGroup = [] +const uuid = ref('') const gID2key = {} +const options = { + url: baseUrl, + pingTimeout: 20000, + pongTimeout: 10000, + reconnectTimeout: 3000, + pingMsg: JSON.stringify({type:'heartbeat'}) +} +let socket = new WebsocketHeartbeatJs(options); + +// const socket = new WebSocket(baseUrl); +// socket.addEventListener("open", (event) => { +// // socket.send(""); +// }); -const socket = new WebSocket(baseUrl); -socket.addEventListener("open", (event) => { -// socket.send(""); -}); - - -socket.addEventListener("message", (event) => { +socket.onmessage= (event) => { const msg = JSON.parse(event.data) data.value.push({from:'server',msg:event.data}) if(msg.type){ @@ -83,8 +92,8 @@ socket.addEventListener("message", (event) => { gID.value=msg.gID }else if(type1 === 'joinVerify'){ let gID = msg.gID - let key = gID2key[gID] - console.log(gID2key,gID,key) + let key = gID2key[gID].key + // console.log(gID2key,gID,key) let res = decryptString(key,msg.verify) console.log(res,key,msg.verify) if(res === 'miaoSpring'){ @@ -93,18 +102,40 @@ socket.addEventListener("message", (event) => { } }else if(type1 === 'history'){ let gID = msg.gID - let key = gID2key[gID] + let key = gID2key[gID].key for(let m of JSON.parse(msg.history)){ data.value.push({from:'decrypt',msg:decryptString(key,m.msg)}) } + }else if(type1 === 'uuid'){ + uuid.value = msg.uuid } }else if(type === 'gMsg'){ let gID = msg.gID - let key = gID2key[gID] + let key = gID2key[gID].key data.value.push({from:'decrypt',msg:decryptString(key,msg.msg)}) } } -}); +}; + +socket.onopen = ()=>{ + if(uuid.value){ + socket.send(JSON.stringify({type:'uuid',type1:'set',uuid:uuid.value})) + }else{ + socket.send(JSON.stringify({type:'uuid',type1:'get'})) + } + console.log(joinedGroup) + let toJoin = [...joinedGroup] + joinedGroup.length = 0 + for(let gID of toJoin){ + let code = gID+gID2key[gID].key + console.log(code) + joinGroup(code) + } +} + +socket.onreconnect = (e) => { + console.log('reconnecting...'); +} function createGroup(){ let keyt = generateKey(setting) @@ -118,7 +149,8 @@ function joinGroup(code){ if(joinedGroup.includes(gID)){ return } - gID2key[gID] = key + gID2key[gID] = {} + gID2key[gID].key = key joinGroup_Verify(gID) } @@ -127,7 +159,7 @@ function joinGroup_Verify(gID){ } function sendMsg(gID,msg){ - let key = gID2key[gID] + let key = gID2key[gID].key msg = encryptString(key,msg,setting) socket.send(JSON.stringify({type:'message',msg,gID})) }