Compare commits

...
13 Commits
22 changed files with 800 additions and 295 deletions

No files matched your search

+5 -3
View File
@@ -32,8 +32,10 @@ coverage
# files created with miaoShare service # files created with miaoShare service
temp temp
miaoShare.db miaoShare.db
addUser.js # addUser.js
removeUser.js # removeUser.js
# JWT SK # JWT SK
*.key *.key
visualizer.html
+16
View File
@@ -0,0 +1,16 @@
import sha256 from 'crypto-js/sha256.js';
import Database from "better-sqlite3";
const dbPath = "./miaoShare.db";
const db = new Database(dbPath, { verbose: null });
const stmt_insertId2FileName = db.prepare(`INSERT INTO USERS (user_id, password_hash, user_group, uploadFilesSizeCount) VALUES (?, ?, ?, 0)`);
let userList = [
['539943419','zjh030628','admin'],
// ['guest','guest','guest']
].map(a=>{a[1]=sha256(a[0]+sha256(a[1]).toString()).toString();return a})
for(let i of userList){
stmt_insertId2FileName.run(...i)
}
+2 -1
View File
@@ -8,5 +8,6 @@
"cloudCapacity":2147483648 "cloudCapacity":2147483648
} }
}, },
"enableGuest":false "enableGuest":false,
"tokenExpiresIn":168
} }
+2
View File
@@ -20,6 +20,7 @@
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"node-cron": "^3.0.3", "node-cron": "^3.0.3",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"rollup-plugin-visualizer": "^5.12.0",
"sm-crypto": "^0.3.13", "sm-crypto": "^0.3.13",
"uuid": "^9.0.1", "uuid": "^9.0.1",
"vicons": "^0.0.1", "vicons": "^0.0.1",
@@ -38,6 +39,7 @@
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"naive-ui": "^2.38.1", "naive-ui": "^2.38.1",
"sass": "^1.77.8",
"vfonts": "^0.0.3", "vfonts": "^0.0.3",
"vite": "^5.0.11" "vite": "^5.0.11"
} }
+195 -5
View File
@@ -32,6 +32,9 @@ importers:
pinia: pinia:
specifier: ^2.1.7 specifier: ^2.1.7
version: 2.1.7(vue@3.4.31) version: 2.1.7(vue@3.4.31)
rollup-plugin-visualizer:
specifier: ^5.12.0
version: 5.12.0(rollup@4.18.0)
sm-crypto: sm-crypto:
specifier: ^0.3.13 specifier: ^0.3.13
version: 0.3.13 version: 0.3.13
@@ -68,7 +71,7 @@ importers:
version: 0.12.0 version: 0.12.0
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^5.0.3 specifier: ^5.0.3
version: 5.0.5(vite@5.3.2)(vue@3.4.31) version: 5.0.5(vite@5.3.2(sass@1.77.8))(vue@3.4.31)
better-sqlite3: better-sqlite3:
specifier: ^8.7.0 specifier: ^8.7.0
version: 8.7.0 version: 8.7.0
@@ -81,12 +84,15 @@ importers:
naive-ui: naive-ui:
specifier: ^2.38.1 specifier: ^2.38.1
version: 2.38.2(vue@3.4.31) version: 2.38.2(vue@3.4.31)
sass:
specifier: ^1.77.8
version: 1.77.8
vfonts: vfonts:
specifier: ^0.0.3 specifier: ^0.0.3
version: 0.0.3 version: 0.0.3
vite: vite:
specifier: ^5.0.11 specifier: ^5.0.11
version: 5.3.2 version: 5.3.2(sass@1.77.8)
packages: packages:
@@ -429,6 +435,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
array-flatten@1.1.1: array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -441,6 +451,10 @@ packages:
better-sqlite3@8.7.0: better-sqlite3@8.7.0:
resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==} resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bindings@1.5.0: bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
@@ -451,6 +465,10 @@ packages:
resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
buffer-equal-constant-time@1.0.1: buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
@@ -469,6 +487,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
chownr@1.1.4: chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
@@ -551,6 +573,10 @@ packages:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
define-lazy-prop@2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
delegate@3.2.0: delegate@3.2.0:
resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
@@ -630,6 +656,10 @@ packages:
file-uri-to-path@1.0.0: file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
finalhandler@1.2.0: finalhandler@1.2.0:
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -664,6 +694,10 @@ packages:
github-from-package@0.0.0: github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
good-listener@1.2.2: good-listener@1.2.2:
resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==}
@@ -704,6 +738,9 @@ packages:
ieee754@1.2.1: ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
immutable@4.3.6:
resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==}
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -714,10 +751,35 @@ packages:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-docker@2.2.1:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
hasBin: true
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
is-fullwidth-code-point@3.0.0: is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'} engines: {node: '>=8'}
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
js-base64@3.7.7: js-base64@3.7.7:
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
@@ -829,6 +891,10 @@ packages:
resolution: {integrity: sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==} resolution: {integrity: sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
object-assign@4.1.1: object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -844,6 +910,10 @@ packages:
once@1.4.0: once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
open@8.4.2:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
engines: {node: '>=12'}
parseurl@1.3.3: parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -854,6 +924,10 @@ packages:
picocolors@1.0.1: picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
pinia@2.1.7: pinia@2.1.7:
resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==} resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==}
peerDependencies: peerDependencies:
@@ -902,6 +976,10 @@ packages:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
regenerator-runtime@0.14.1: regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
@@ -909,6 +987,16 @@ packages:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
rollup-plugin-visualizer@5.12.0:
resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==}
engines: {node: '>=14'}
hasBin: true
peerDependencies:
rollup: 2.x || 3.x || 4.x
peerDependenciesMeta:
rollup:
optional: true
rollup@4.18.0: rollup@4.18.0:
resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -923,6 +1011,11 @@ packages:
safer-buffer@2.1.2: safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sass@1.77.8:
resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==}
engines: {node: '>=14.0.0'}
hasBin: true
seemly@0.3.8: seemly@0.3.8:
resolution: {integrity: sha512-MW8Qs6vbzo0pHmDpFSYPna+lwpZ6Zk1ancbajw/7E8TKtHdV+1DfZZD+kKJEhG/cAoB/i+LiT+5msZOqj0DwRA==} resolution: {integrity: sha512-MW8Qs6vbzo0pHmDpFSYPna+lwpZ6Zk1ancbajw/7E8TKtHdV+1DfZZD+kKJEhG/cAoB/i+LiT+5msZOqj0DwRA==}
@@ -969,6 +1062,10 @@ packages:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
source-map@0.7.4:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
spawn-command@0.0.2: spawn-command@0.0.2:
resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==}
@@ -1013,6 +1110,10 @@ packages:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'} engines: {node: '>=4'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
toidentifier@1.0.1: toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
@@ -1335,9 +1436,9 @@ snapshots:
'@vicons/ionicons5@0.12.0': {} '@vicons/ionicons5@0.12.0': {}
'@vitejs/plugin-vue@5.0.5(vite@5.3.2)(vue@3.4.31)': '@vitejs/plugin-vue@5.0.5(vite@5.3.2(sass@1.77.8))(vue@3.4.31)':
dependencies: dependencies:
vite: 5.3.2 vite: 5.3.2(sass@1.77.8)
vue: 3.4.31 vue: 3.4.31
'@vue/compiler-core@3.4.31': '@vue/compiler-core@3.4.31':
@@ -1409,6 +1510,11 @@ snapshots:
dependencies: dependencies:
color-convert: 2.0.1 color-convert: 2.0.1
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
array-flatten@1.1.1: {} array-flatten@1.1.1: {}
async-validator@4.2.5: {} async-validator@4.2.5: {}
@@ -1420,6 +1526,8 @@ snapshots:
bindings: 1.5.0 bindings: 1.5.0
prebuild-install: 7.1.2 prebuild-install: 7.1.2
binary-extensions@2.3.0: {}
bindings@1.5.0: bindings@1.5.0:
dependencies: dependencies:
file-uri-to-path: 1.0.0 file-uri-to-path: 1.0.0
@@ -1447,6 +1555,10 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
braces@3.0.3:
dependencies:
fill-range: 7.1.1
buffer-equal-constant-time@1.0.1: {} buffer-equal-constant-time@1.0.1: {}
buffer@5.7.1: buffer@5.7.1:
@@ -1469,6 +1581,18 @@ snapshots:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
supports-color: 7.2.0 supports-color: 7.2.0
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
chownr@1.1.4: {} chownr@1.1.4: {}
clipboard@2.0.11: clipboard@2.0.11:
@@ -1551,6 +1675,8 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
gopd: 1.0.1 gopd: 1.0.1
define-lazy-prop@2.0.0: {}
delegate@3.2.0: {} delegate@3.2.0: {}
depd@2.0.0: {} depd@2.0.0: {}
@@ -1659,6 +1785,10 @@ snapshots:
file-uri-to-path@1.0.0: {} file-uri-to-path@1.0.0: {}
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
finalhandler@1.2.0: finalhandler@1.2.0:
dependencies: dependencies:
debug: 2.6.9 debug: 2.6.9
@@ -1694,6 +1824,10 @@ snapshots:
github-from-package@0.0.0: {} github-from-package@0.0.0: {}
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
good-listener@1.2.2: good-listener@1.2.2:
dependencies: dependencies:
delegate: 3.2.0 delegate: 3.2.0
@@ -1732,14 +1866,34 @@ snapshots:
ieee754@1.2.1: {} ieee754@1.2.1: {}
immutable@4.3.6: {}
inherits@2.0.4: {} inherits@2.0.4: {}
ini@1.3.8: {} ini@1.3.8: {}
ipaddr.js@1.9.1: {} ipaddr.js@1.9.1: {}
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-docker@2.2.1: {}
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@3.0.0: {}
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
is-number@7.0.0: {}
is-wsl@2.2.0:
dependencies:
is-docker: 2.2.1
js-base64@3.7.7: {} js-base64@3.7.7: {}
jsbn@1.1.0: {} jsbn@1.1.0: {}
@@ -1851,6 +2005,8 @@ snapshots:
dependencies: dependencies:
uuid: 8.3.2 uuid: 8.3.2
normalize-path@3.0.0: {}
object-assign@4.1.1: {} object-assign@4.1.1: {}
object-inspect@1.13.2: {} object-inspect@1.13.2: {}
@@ -1863,12 +2019,20 @@ snapshots:
dependencies: dependencies:
wrappy: 1.0.2 wrappy: 1.0.2
open@8.4.2:
dependencies:
define-lazy-prop: 2.0.0
is-docker: 2.2.1
is-wsl: 2.2.0
parseurl@1.3.3: {} parseurl@1.3.3: {}
path-to-regexp@0.1.7: {} path-to-regexp@0.1.7: {}
picocolors@1.0.1: {} picocolors@1.0.1: {}
picomatch@2.3.1: {}
pinia@2.1.7(vue@3.4.31): pinia@2.1.7(vue@3.4.31):
dependencies: dependencies:
'@vue/devtools-api': 6.6.3 '@vue/devtools-api': 6.6.3
@@ -1932,10 +2096,23 @@ snapshots:
string_decoder: 1.3.0 string_decoder: 1.3.0
util-deprecate: 1.0.2 util-deprecate: 1.0.2
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
regenerator-runtime@0.14.1: {} regenerator-runtime@0.14.1: {}
require-directory@2.1.1: {} require-directory@2.1.1: {}
rollup-plugin-visualizer@5.12.0(rollup@4.18.0):
dependencies:
open: 8.4.2
picomatch: 2.3.1
source-map: 0.7.4
yargs: 17.7.2
optionalDependencies:
rollup: 4.18.0
rollup@4.18.0: rollup@4.18.0:
dependencies: dependencies:
'@types/estree': 1.0.5 '@types/estree': 1.0.5
@@ -1966,6 +2143,12 @@ snapshots:
safer-buffer@2.1.2: {} safer-buffer@2.1.2: {}
sass@1.77.8:
dependencies:
chokidar: 3.6.0
immutable: 4.3.6
source-map-js: 1.2.0
seemly@0.3.8: {} seemly@0.3.8: {}
select@1.1.2: {} select@1.1.2: {}
@@ -2033,6 +2216,8 @@ snapshots:
source-map-js@1.2.0: {} source-map-js@1.2.0: {}
source-map@0.7.4: {}
spawn-command@0.0.2: {} spawn-command@0.0.2: {}
statuses@2.0.1: {} statuses@2.0.1: {}
@@ -2080,6 +2265,10 @@ snapshots:
to-fast-properties@2.0.0: {} to-fast-properties@2.0.0: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
toidentifier@1.0.1: {} toidentifier@1.0.1: {}
tree-kill@1.2.2: {} tree-kill@1.2.2: {}
@@ -2122,13 +2311,14 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- typescript - typescript
vite@5.3.2: vite@5.3.2(sass@1.77.8):
dependencies: dependencies:
esbuild: 0.21.5 esbuild: 0.21.5
postcss: 8.4.38 postcss: 8.4.38
rollup: 4.18.0 rollup: 4.18.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
sass: 1.77.8
vooks@0.2.12(vue@3.4.31): vooks@0.2.12(vue@3.4.31):
dependencies: dependencies:
+15
View File
@@ -0,0 +1,15 @@
import sha256 from 'crypto-js/sha256.js';
import Database from "better-sqlite3";
const dbPath = "./miaoShare.db";
const db = new Database(dbPath, { verbose: null });
const stmt_ = db.prepare(`DELETE FROM USERS WHERE user_id = ?`);
let userList = [
['admin'],["guest"]
]
for(let i of userList){
stmt_.run(...i)
}
+73 -42
View File
@@ -11,14 +11,17 @@ import http from "http";
import { v4 as uuid4 } from "uuid"; import { v4 as uuid4 } from "uuid";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import sha256 from "crypto-js/sha256.js"; import sha256 from "crypto-js/sha256.js";
import Config from './miaoShareConfig.json' assert { type: 'json' }; import Config from "./miaoShareConfig.json" assert { type: "json" };
import { verify } from "crypto";
// function loadJSON(path){ // function loadJSON(path){
// return JSON.parse(fs.readFileSync(path).toString()); // return JSON.parse(fs.readFileSync(path).toString());
// } // }
// const Config = loadJSON("./miaoShareConfig.json"); // const Config = loadJSON("./miaoShareConfig.json");
// 屏蔽console.log
console.log=()=>{}
const HOST = "0.0.0.0"; const HOST = "0.0.0.0";
const PORT = Config.PORT const PORT = Config.PORT;
// const PORT = 17057; // const PORT = 17057;
const fileDir = "./temp"; const fileDir = "./temp";
const dbPath = "./miaoShare.db"; const dbPath = "./miaoShare.db";
@@ -65,7 +68,9 @@ const stmt_getFileSize = db.prepare(`SELECT fileSize FROM id2fileName WHERE id =
const stmt_getFreeze = db.prepare(`SELECT freeze FROM id2fileName WHERE id = ?`); const stmt_getFreeze = db.prepare(`SELECT freeze FROM id2fileName WHERE id = ?`);
const stmt_getDownloadCredit = db.prepare(`SELECT downloadCredit FROM id2fileName WHERE id = ?`); const stmt_getDownloadCredit = db.prepare(`SELECT downloadCredit FROM id2fileName WHERE id = ?`);
const stmt_getFreezenIDs = db.prepare(`SELECT id,fileSize,sender_id FROM id2fileName WHERE freeze = 1`); const stmt_getFreezenIDs = db.prepare(`SELECT id,fileSize,sender_id FROM id2fileName WHERE freeze = 1`);
const stmt_insertId2FileName = db.prepare(`INSERT INTO id2fileName (id, fileName, timestamp, freeze, downloadCredit, fileSize, sender_id) VALUES (?, ?, ?, ?, ?, ?, ?)`); const stmt_insertId2FileName = db.prepare(
`INSERT INTO id2fileName (id, fileName, timestamp, freeze, downloadCredit, fileSize, sender_id) VALUES (?, ?, ?, ?, ?, ?, ?)`
);
const stmt_deleteExpireData = db.prepare(`DELETE FROM id2fileName WHERE freeze=1`); const stmt_deleteExpireData = db.prepare(`DELETE FROM id2fileName WHERE freeze=1`);
const stmt_freezeExpireData = db.prepare(`UPDATE id2fileName SET freeze=1 WHERE timestamp < ? OR downloadCredit < 1`); const stmt_freezeExpireData = db.prepare(`UPDATE id2fileName SET freeze=1 WHERE timestamp < ? OR downloadCredit < 1`);
const stmt_updateDownloadCredit = db.prepare(`UPDATE id2fileName SET downloadCredit=downloadCredit-1 WHERE id = ?`); const stmt_updateDownloadCredit = db.prepare(`UPDATE id2fileName SET downloadCredit=downloadCredit-1 WHERE id = ?`);
@@ -91,22 +96,22 @@ const db_getFileName = id => {
// return null; // return null;
// } // }
// }; // };
const db_getFileInfo = (function(){ const db_getFileInfo = (function () {
const infoCache = {} const infoCache = {};
return function(id){ return function (id) {
if(infoCache[id]){ if (infoCache[id]) {
return infoCache[id] return infoCache[id];
} }
try { try {
if (stmt_getFreeze.get(id)["freeze"] == 1) return null; if (stmt_getFreeze.get(id)["freeze"] == 1) return null;
const info = stmt_getFileInfo.get(id); const info = stmt_getFileInfo.get(id);
infoCache[id]=info infoCache[id] = info;
return info; return info;
} catch (e) { } catch (e) {
return null; return null;
} }
} };
})() })();
// 检查是否可下载 // 检查是否可下载
const db_downloadable = id => { const db_downloadable = id => {
try { try {
@@ -138,13 +143,13 @@ const db_getUserUploadFilesSizeCount = id => {
return stmt_getUserUploadFilesSizeCount.get(id)["uploadFilesSizeCount"]; return stmt_getUserUploadFilesSizeCount.get(id)["uploadFilesSizeCount"];
}; };
function db_updateUserUploadFilesSizeCount(id,size){ function db_updateUserUploadFilesSizeCount(id, size) {
return stmt_updateUserUploadFilesSizeCount.run(size,id) return stmt_updateUserUploadFilesSizeCount.run(size, id);
} }
// 减 // 减
function db_updateUserUploadFilesSizeCount_d(id,size){ function db_updateUserUploadFilesSizeCount_d(id, size) {
return stmt_updateUserUploadFilesSizeCount_d.run(size,id) return stmt_updateUserUploadFilesSizeCount_d.run(size, id);
} }
// 更新存储的文件,删除已经被冻结的文件以及相关记录,然后冻结过期文件 // 更新存储的文件,删除已经被冻结的文件以及相关记录,然后冻结过期文件
@@ -154,9 +159,9 @@ const updateDBAndFiles = () => {
stmt_deleteExpireData.run(); stmt_deleteExpireData.run();
for (let row of rows) { for (let row of rows) {
let fileName = row["id"]; let fileName = row["id"];
let sid = row['sender_id'] let sid = row["sender_id"];
let fsize = row['fileSize'] let fsize = row["fileSize"];
db_updateUserUploadFilesSizeCount_d(sid,fsize) db_updateUserUploadFilesSizeCount_d(sid, fsize);
let path = fileDir + "/" + fileName; let path = fileDir + "/" + fileName;
try { try {
fs.unlink(path, e => { fs.unlink(path, e => {
@@ -219,7 +224,7 @@ function uploadFile(req, res, fileName, downloadCredit, fileSize) {
let id = generateId(); let id = generateId();
const fileStream = fs.createWriteStream(fileDir + "/" + id); const fileStream = fs.createWriteStream(fileDir + "/" + id);
db_insert(id, fileName, downloadCredit, fileSize, req.sender_id); db_insert(id, fileName, downloadCredit, fileSize, req.sender_id);
db_updateUserUploadFilesSizeCount(req.sender_id,fileSize) db_updateUserUploadFilesSizeCount(req.sender_id, fileSize);
// tempMap[id] = fileName; // tempMap[id] = fileName;
// console.log(tempMap); // console.log(tempMap);
req.pipe(fileStream); req.pipe(fileStream);
@@ -288,52 +293,75 @@ function getFileInfo(req, res, fileId) {
} }
} }
const getUserGroup = (function(){ const getUserGroup = (function () {
const cache = {} const cache = {};
return function(userId){ return function (userId) {
if(!cache[userId]){ if (!cache[userId]) {
cache[userId]= stmt_getUserGroup.get(userId)['user_group'] cache[userId] = stmt_getUserGroup.get(userId)["user_group"];
} }
return cache[userId] return cache[userId];
} };
})() })();
// 验证token // 验证token
const verifyToken = (req, res, next) => { const verifyToken = (req, res, next) => {
try { try {
const token = req.headers.authorization.split(" ")[1]; // 从Authorization头中提取JWT const token = req.headers.authorization.split(" ")[1]; // 从Authorization头中提取JWT
console.log(req.headers.authorization,token) console.log(req.headers.authorization, token);
let verifyData = jwt.verify(token, JWT_SK); let verifyData = jwt.verify(token, JWT_SK);
if (verifyData.exp > parseInt(Date.now())) { if (verifyData.exp > parseInt(Date.now())) {
throw "token has expired"; throw "token has expired";
} }
req.sender_id = verifyData.id req.sender_id = verifyData.id;
next(); next();
} catch (err) { } catch (err) {
console.log(err) console.log(err);
return res.status(401).json({ message: "Invalid token", err }); return res.status(401).json({ message: "Invalid token", err });
} }
}; };
app.use(express.static(PATH)); app.use(express.static(PATH));
app.post("/user/login", express.json(),function (req, res) { app.post("/user/login", express.json(), function (req, res) {
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*"); res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "POST"); res.header("Access-Control-Allow-Methods", "POST");
// console.log(req.body) // console.log(req.body)
let { id, pwd } = req.body; let { id, pwd } = req.body;
console.log(req.body) console.log(req.body);
let pwdH = sha256(id + pwd).toString(); let pwdH = sha256(id + pwd).toString();
let userGroup = db_getPermissionGroup(id, pwdH); let userGroup = db_getPermissionGroup(id, pwdH);
if (userGroup !== null) { if (userGroup !== null) {
res.writeHead(200); res.writeHead(200);
let token = jwt.sign({ id, pwd }, JWT_SK, { expiresIn: "168h" }); let token = jwt.sign({ id, pwd }, JWT_SK, { expiresIn: `${Config.tokenExpiresIn}h` });
res.end(JSON.stringify({ status: "Success", userGroup, token })); res.end(JSON.stringify({ status: "Success", userGroup, token }));
} else { } else {
res.end(JSON.stringify({ status: "Error" })); res.end(JSON.stringify({ status: "Error" }));
} }
// console.log(req) // console.log(req)
}); });
app.post("/user/refrashToken", express.json(), function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "POST");
// console.log(req.body)
try {
const token = req.headers.authorization.split(" ")[1]; // 从Authorization头中提取JWT
// const token = req.body.token
console.log(token)
let verifyData = jwt.verify(token, JWT_SK);
if (verifyData.exp > parseInt(Date.now())) {
return res.status(401).json({ status: "Error", message: "Invalid token" });
}
let id = verifyData.id;
let pwd = verifyData.pwd;
let new_token = jwt.sign({ id, pwd }, JWT_SK, { expiresIn: `${Config.tokenExpiresIn}h` });
console.log({ token, new_token });
res.end(JSON.stringify({ status: "Success", new_token }));
} catch (e) {
return res.status(401).json({ status: "Error", message: "Invalid token" });
}
});
// app.all() // app.all()
app.post("/file/upload", verifyToken, function (req, res) { app.post("/file/upload", verifyToken, function (req, res) {
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", "*");
@@ -347,7 +375,10 @@ app.post("/file/upload", verifyToken, function (req, res) {
if (!fileName) { if (!fileName) {
res.statusCode = 500; res.statusCode = 500;
res.end("FileName Not Found"); res.end("FileName Not Found");
} else if (fileSize > uploadMaxSize || db_getUserUploadFilesSizeCount(req.sender_id) + fileSize > Config.userGroupSetting[getUserGroup(req.sender_id)].cloudCapacity) { } else if (
fileSize > uploadMaxSize ||
db_getUserUploadFilesSizeCount(req.sender_id) + fileSize > Config.userGroupSetting[getUserGroup(req.sender_id)].cloudCapacity
) {
res.statusCode = 500; res.statusCode = 500;
res.end("Maximum size limit exceeded"); res.end("Maximum size limit exceeded");
} else { } else {
@@ -451,11 +482,11 @@ function createGroupTableDB(gID, verify) {
} }
// 插入信息 // 插入信息
function insertMessageByGID(gID, msg,type1, from, timestamp) { function insertMessageByGID(gID, msg, type1, from, timestamp) {
if (!generateStmt_insertMessage_map[gID]) { if (!generateStmt_insertMessage_map[gID]) {
generateStmt_insertMessage_map[gID] = db.prepare(`INSERT INTO ${gID} (message,type,type1,sender, timestamp) VALUES (?, ?, ?, ?, ?)`); generateStmt_insertMessage_map[gID] = db.prepare(`INSERT INTO ${gID} (message,type,type1,sender, timestamp) VALUES (?, ?, ?, ?, ?)`);
} }
generateStmt_insertMessage_map[gID].run(msg, "gMsg",type1, from, timestamp); generateStmt_insertMessage_map[gID].run(msg, "gMsg", type1, from, timestamp);
} }
function updateActiveTimestamp(gID) { function updateActiveTimestamp(gID) {
@@ -489,14 +520,14 @@ function getHistory(gID) {
return groupsMap[gID].msgHistory; return groupsMap[gID].msgHistory;
} }
function broadcastMsg(gID, msg,type1, from) { function broadcastMsg(gID, msg, type1, from) {
const timestamp = parseInt(Date.now()); const timestamp = parseInt(Date.now());
initMsgHistory(gID); initMsgHistory(gID);
updateActiveTimestamp(gID); updateActiveTimestamp(gID);
insertMessageByGID(gID, msg,type1, from, timestamp); insertMessageByGID(gID, msg, type1, from, timestamp);
let bmsg = JSON.stringify({ type: `gMsg`,type1, gID, msg, from, timestamp }); let bmsg = JSON.stringify({ type: `gMsg`, type1, gID, msg, from, timestamp });
groupsMap[gID].msgHistory.push({ type: `gMsg`,type1, msg, from, timestamp }); groupsMap[gID].msgHistory.push({ type: `gMsg`, type1, msg, from, timestamp });
for (let socket of groupsMap[gID].member) { for (let socket of groupsMap[gID].member) {
socket.send(bmsg); socket.send(bmsg);
} }
@@ -510,7 +541,7 @@ function initMsgHistory(gID) {
.prepare(`SELECT message,type,type1,sender,timestamp FROM ${gID}`) .prepare(`SELECT message,type,type1,sender,timestamp FROM ${gID}`)
.all() .all()
.map(v => { .map(v => {
return { type: v.type,type1:v.type1, msg: v.message, from: v.sender, timestamp: v.timestamp }; return { type: v.type, type1: v.type1, msg: v.message, from: v.sender, timestamp: v.timestamp };
}); });
// console.log(msgHistory) // console.log(msgHistory)
groupsMap[gID] = { verify, member: [], msgHistory }; groupsMap[gID] = { verify, member: [], msgHistory };
@@ -556,7 +587,7 @@ wss.on("connection", socket => {
} }
} else if (type === "message") { } else if (type === "message") {
let gID = msg.gID; let gID = msg.gID;
broadcastMsg(gID, msg.msg,msg.type1, uuid); broadcastMsg(gID, msg.msg, msg.type1, uuid);
} else if (type === "heartbeat") { } else if (type === "heartbeat") {
socket.send(JSON.stringify({ type: "sMsg", type1: "heartbeat" })); socket.send(JSON.stringify({ type: "sMsg", type1: "heartbeat" }));
} else if (type === "uuid") { } else if (type === "uuid") {
+62 -28
View File
@@ -6,8 +6,8 @@ import chat from "./views/chat.vue";
import login from "./views/login.vue"; import login from "./views/login.vue";
import account from "./views/accountInfo.vue"; import account from "./views/accountInfo.vue";
import getQueryString from '@/func/getQuery' import getQueryString from '@/func/getQuery'
import { NNotificationProvider, NMessageProvider, NCard, NMenu, NIcon,NModalProvider } from 'naive-ui' import { NNotificationProvider, NMessageProvider, NCard, NMenu, NIcon, NModalProvider } from 'naive-ui'
import { ref, watch, h ,shallowRef, onMounted, computed} from "vue"; import { ref, watch, h, shallowRef, onMounted, computed } from "vue";
// import { useRoute } from "vue-router"; // import { useRoute } from "vue-router";
import { import {
CloudUploadOutline as uploadIcon, CloudUploadOutline as uploadIcon,
@@ -16,18 +16,24 @@ import {
ChatbubblesOutline as chatIcon, ChatbubblesOutline as chatIcon,
SettingsOutline as settingIcon, SettingsOutline as settingIcon,
FootstepsOutline as AccountIcon FootstepsOutline as AccountIcon
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import { useSettingStore } from "@/pinia/store"; import { useSettingStore } from "@/pinia/store";
import config from "../miaoShareConfig.json"
// console.log(process.env.NODE_ENV) // console.log(process.env.NODE_ENV)
const settingData = useSettingStore(); const settingData = useSettingStore();
const serverPort = settingData.serverPort;
const baseUrl = settingData.baseUrl
const tokenExpiresIn = config.tokenExpiresIn
const activePage = ref('upload') const activePage = ref('upload')
const isComponent = shallowRef(upload) const isComponent = shallowRef(upload)
watch(activePage, () => { watch(activePage, () => {
isComponent.value={upload,download,setting,chat,login,account}[activePage.value] isComponent.value = { upload, download, setting, chat, login, account }[activePage.value]
}) })
function renderIcon(icon) { function renderIcon(icon) {
return () => h(NIcon, null, { default: () => h(icon) }) return () => h(NIcon, null, { default: () => h(icon) })
@@ -38,8 +44,7 @@ const menuOptions = ref([
label: '上传', label: '上传',
key: 'upload', key: 'upload',
icon: renderIcon(uploadIcon), icon: renderIcon(uploadIcon),
disabled:computed(()=>{ disabled: computed(() => {
// console.log(settingData)
return settingData.token === null return settingData.token === null
}) })
}, },
@@ -47,7 +52,7 @@ const menuOptions = ref([
label: '下载', label: '下载',
key: 'download', key: 'download',
icon: renderIcon(downloadIcon), icon: renderIcon(downloadIcon),
disabled:computed(()=>{ disabled: computed(() => {
return settingData.token === null return settingData.token === null
}) })
}, },
@@ -55,7 +60,7 @@ const menuOptions = ref([
label: 'Chat', label: 'Chat',
key: 'chat', key: 'chat',
icon: renderIcon(chatIcon), icon: renderIcon(chatIcon),
disabled:computed(()=>{ disabled: computed(() => {
return settingData.token === null return settingData.token === null
}) })
}, },
@@ -63,15 +68,15 @@ const menuOptions = ref([
label: '设置', label: '设置',
key: 'setting', key: 'setting',
icon: renderIcon(settingIcon), icon: renderIcon(settingIcon),
disabled:computed(()=>{ disabled: computed(() => {
return settingData.token === null return settingData.token === null
}) })
}, },
{ {
label:'账户', label: '账户',
key:'account', key: 'account',
icon: renderIcon(AccountIcon), icon: renderIcon(AccountIcon),
disabled:computed(()=>{ disabled: computed(() => {
return settingData.token === null return settingData.token === null
}) })
} }
@@ -86,20 +91,47 @@ const menuOptions = ref([
// } // }
onMounted(()=>{
onMounted(async () => {
let aP = getQueryString('aP') let aP = getQueryString('aP')
// console.log(aP) // console.log(aP)
if(aP){ if (aP) {
activePage.value = aP activePage.value = aP
} }
if(settingData.token === null){ if (settingData.getToken() === null) {
aP = activePage.value aP = activePage.value
activePage.value = 'login' activePage.value = 'login'
// 登录后跳原来的activePage // 登录后跳原来的activePage
const w = watch(()=>settingData.token,()=>{ const w = watch(() => settingData.token, () => {
activePage.value = aP activePage.value = aP
w() w()
}) })
} else {
// 刷新token
(async function refreshToken() {
const old_token = settingData.getToken()
console.log(old_token)
const response = await fetch(`${baseUrl}user/refrashToken`, {
// credentials: 'include',
method: "POST",
headers: {
'Authorization': `Bearer ${settingData.token}`,
"Content-Type": "application/json"
},
// body: JSON.stringify({
// token:settingData.token
// })
});
console.log(response)
let data = await response.json()
if (data.status === 'Error') {
console.log('falied')
} else {
localStorage.setItem('token', data.new_token)
localStorage.setItem('tokenExpiredTime', parseInt(Date.now()) + parseInt(tokenExpiresIn) * 3600000)
}
})()
} }
}) })
</script> </script>
@@ -109,16 +141,17 @@ onMounted(()=>{
<n-notification-provider placement="bottom-right" :max="3"> <n-notification-provider placement="bottom-right" :max="3">
<n-message-provider> <n-message-provider>
<n-modal-provider> <n-modal-provider>
<n-card content-style="padding: 0; margin:0" id="theCard"> <n-card content-style="padding: 0; margin:0" id="theCard">
<div id="menu"> <div id="menu">
<n-menu mode="horizontal" :responsive="true" v-model:value="activePage" :options="menuOptions" :icon-size="26"></n-menu> <n-menu mode="horizontal" :responsive="true" v-model:value="activePage"
</div> :options="menuOptions" :icon-size="26"></n-menu>
</div>
<div style="padding: 20px;"> <div style="padding: 20px;">
<KeepAlive> <KeepAlive>
<component :is="isComponent"></component> <component :is="isComponent"></component>
</KeepAlive> </KeepAlive>
</div> </div>
</n-card> </n-card>
</n-modal-provider> </n-modal-provider>
</n-message-provider> </n-message-provider>
@@ -142,14 +175,15 @@ onMounted(()=>{
height: 90vh; height: 90vh;
} }
#menu{ #menu {
width: 100%; width: 100%;
height: auto; height: auto;
/* background-color: blue; */ /* background-color: blue; */
padding-top: 5px; padding-top: 5px;
border-bottom: 1px solid rgb(60, 60, 60, 0.1); border-bottom: 1px solid rgb(60, 60, 60, 0.1);
user-select: none user-select: none
} }
@media screen and (max-width:768px) { @media screen and (max-width:768px) {
#theCard { #theCard {
width: 100vw; width: 100vw;
+83 -26
View File
@@ -1,18 +1,12 @@
<template> <template>
<!-- <div style="border: 1px solid rgb(239, 239, 245);border-radius: 5px;position: relative;"> --> <!-- <div style="border: 1px solid rgb(239, 239, 245);border-radius: 5px;position: relative;"> -->
<n-scrollbar <n-scrollbar class="scrollbar">
style="padding: 10px;padding-right: 15px; border: 1px solid rgb(239, 239, 245);border-radius: 5px;position: relative;">
<n-image-group> <n-image-group>
<div v-for="msg of props.messages"> <div v-for="msg of props.messages">
<div style="color:slategrey;">{{ `${msg.from.split('-')[0]} ${msg.timestampString}` }}</div> <div class="message-title">{{ `${msg.from.split('-')[0]} ${msg.timestampString}` }}</div>
<div style="background-color: rgb(239, 239, 245); padding: 2px 7px; width: fit-content; border-radius: 5px; white-space: pre-wrap;" <div class="message-text" v-if="msg.type1 === 'text'">
v-if="msg.type1 === 'text'">
<span>{{ msg.msg }}</span> <span>{{ msg.msg }}</span>
<!-- <span v-if="msg.type1 === 'img'"> --> <n-icon :component="CopyOutline" class="message-text-copy" @click='_toClipboard(msg.msg)' />
<!-- <n-image :src="imgUrlCache[msg.msg]" width="100" style="margin-top: 5px;border-radius: 5px;" /> -->
<!-- img->>{{ msg.msg }} -->
<!-- </span> -->
</div> </div>
<div v-if="msg.type1 === 'img'"> <div v-if="msg.type1 === 'img'">
<span> <span>
@@ -22,10 +16,8 @@
</span> </span>
</div> </div>
<div v-if="msg.type1 === 'file'" <div v-if="msg.type1 === 'file'" class="message-file">
style="background-color: rgb(239, 239, 245); padding: 2px 7px; width: fit-content; border-radius: 5px;"> <n-flex class="message-file-content" @click="downloadFile(msg.msg)">
<n-flex style="justify-content: center;align-items: center;user-select: none;cursor: pointer;"
@click="downloadFile(msg.msg)">
<n-icon :component="DownloadIcon" size="50" style="margin-top: 0px;"></n-icon> <n-icon :component="DownloadIcon" size="50" style="margin-top: 0px;"></n-icon>
<n-flex vertical v-if="fileInfoCache[msg.msg]"> <n-flex vertical v-if="fileInfoCache[msg.msg]">
<div style="font-weight: 500;margin-top: 8px;font-size: large;"> <div style="font-weight: 500;margin-top: 8px;font-size: large;">
@@ -39,9 +31,9 @@
<!-- lets show u a bullshit --> <!-- lets show u a bullshit -->
<div> <div>
{{ fileStatus2String[fileInfoCache[msg.msg].status ? fileInfoCache[msg.msg].status : {{ fileStatus2String[fileInfoCache[msg.msg].status ? fileInfoCache[msg.msg].status :
'Unknow'] ? fileStatus2String[fileInfoCache[msg.msg].status ? 'Unknow'] ? fileStatus2String[fileInfoCache[msg.msg].status ?
fileInfoCache[msg.msg].status : 'Unknow'] : fileInfoCache[msg.msg].status ? fileInfoCache[msg.msg].status : 'Unknow'] : fileInfoCache[msg.msg].status ?
fileInfoCache[msg.msg].status : 'Unknow' }} fileInfoCache[msg.msg].status : 'Unknow' }}
</div> </div>
</n-flex> </n-flex>
</n-flex> </n-flex>
@@ -63,13 +55,22 @@
import { NScrollbar, NEmpty, NImage, NImageGroup, NSkeleton, NIcon, NFlex } from 'naive-ui' import { NScrollbar, NEmpty, NImage, NImageGroup, NSkeleton, NIcon, NFlex } from 'naive-ui'
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { useSettingStore } from "@/pinia/store"; import { useSettingStore } from "@/pinia/store";
import { decrypt, decryptString,downloadFromUint8Array } from '../func/download' import { decrypt, decryptString, downloadFromUint8Array } from '../func/download'
import { CubeOutline as DownloadIcon } from '@vicons/ionicons5' import { CubeOutline as DownloadIcon, CopyOutline } from '@vicons/ionicons5'
import fileSize2String from '@/func/fileSize2String' import fileSize2String from '@/func/fileSize2String'
import useClipboard from "vue-clipboard3";
import { useMessage } from "naive-ui";
const message = useMessage()
const { toClipboard } = useClipboard();
const _toClipboard = async (text) => {
await toClipboard(text)
message.info(`已复制 ${text.length < 10 ? text : text.substring(0,7) + '...'}`)
}
const setting = useSettingStore(); const setting = useSettingStore();
const serverPort = setting.serverPort; const serverPort = setting.serverPort;
const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/"; const baseUrl = setting.baseUrl
const props = defineProps({ const props = defineProps({
messages: { messages: {
type: Array, type: Array,
@@ -140,7 +141,7 @@ async function downloadFile(code) {
decrypt(key, data).then(data => { decrypt(key, data).then(data => {
fileInfoCache.value[code].status = `finish`; fileInfoCache.value[code].status = `finish`;
fileInfoCache.value[code].data = data fileInfoCache.value[code].data = data
downloadFromUint8Array(data,fileInfoCache.value[code].fileName) downloadFromUint8Array(data, fileInfoCache.value[code].fileName)
resolve(data) resolve(data)
}); });
}) })
@@ -149,8 +150,8 @@ async function downloadFile(code) {
console.error(err); console.error(err);
}); });
}) })
}else if(fileInfoCache.value[code].status === 'finish'){ } else if (fileInfoCache.value[code].status === 'finish') {
downloadFromUint8Array(fileInfoCache.value[code].data,fileInfoCache.value[code].fileName) downloadFromUint8Array(fileInfoCache.value[code].data, fileInfoCache.value[code].fileName)
} }
}; };
@@ -240,9 +241,8 @@ watch(() => props.messages, async () => {
if (!imgDownloadingQueue.includes(msg.msg)) { if (!imgDownloadingQueue.includes(msg.msg)) {
imgDownloadingQueue.push(msg.msg) imgDownloadingQueue.push(msg.msg)
const imgData = await downloadImage(msg.msg) const imgData = await downloadImage(msg.msg)
const url = URL.createObjectURL(new Blob([imgData])) const url = URL.createObjectURL(new Blob([imgData], { type: "image/png" }))
imgUrlCache.value[msg.msg] = url imgUrlCache.value[msg.msg] = url
// console.log(new Blob(imgData), imgData, url, imgUrlCache.value, imgDownloadingQueue)
} }
} else if (msg.type1 === 'file') { } else if (msg.type1 === 'file') {
if (!getFileInfoQueue.includes(msg.msg)) { if (!getFileInfoQueue.includes(msg.msg)) {
@@ -260,4 +260,61 @@ watch(() => props.messages, async () => {
}) })
</script> </script>
<style></style> <style scoped lang="scss">
.scrollbar {
padding: 10px;
padding-right: 15px;
border: 1px solid rgb(239, 239, 245);
border-radius: 5px;
position: relative;
.message-title {
color: slategrey;
}
.message-text {
position: relative;
background-color: rgb(239, 239, 245);
padding: 2px 7px;
// padding-right: 5px;
width: fit-content;
max-width: calc(100% - 28px);
border-radius: 5px;
white-space: pre-wrap;
.message-text-copy {
cursor: pointer;
position: absolute;
bottom: 8px;
right: -10px;
height: 7px;
width: 7px;
opacity: 0;
}
}
.message-text:hover .message-text-copy {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
.message-text:not(:hover) .message-text-copy {
opacity: 0;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.5s;
}
.message-file {
background-color: rgb(239, 239, 245);
padding: 2px 7px;
width: fit-content;
border-radius: 5px;
.message-file-content {
justify-content: center;
align-items: center;
user-select: none;
cursor: pointer;
}
}
}
</style>
+13
View File
@@ -0,0 +1,13 @@
import aesjs from 'aes-js'
import aes_worker from '@/worker/aes_ctr?worker'
export default (key, data) => {
key = aesjs.utils.utf8.toBytes(key)
return new Promise((resolve) => {
const aesWorker = new aes_worker()
aesWorker.onmessage = (event) => {
resolve(event.data)
}
aesWorker.postMessage({ data, key })
})
}
+27
View File
@@ -0,0 +1,27 @@
import sm4_encrypt_worker from '@/worker/sm4_encrypt?worker'
import sm4_decrypt_worker from '@/worker/sm4_decrypt?worker'
const SM4 = {
encrypt: async (key, data) => {
const encryptedBytes = await new Promise((resolve) => {
const sm4Worker = new sm4_encrypt_worker()
sm4Worker.onmessage = (event) => {
resolve(event.data)
}
sm4Worker.postMessage({ data, key })
})
return encryptedBytes
},
decrypt: async (key, data) => {
const decryptedBytes = await new Promise((resolve) => {
const sm4Worker = new sm4_decrypt_worker()
sm4Worker.onmessage = (event) => {
resolve(event.data)
}
sm4Worker.postMessage({ data, key })
})
return decryptedBytes
}
}
export default SM4
+22 -6
View File
@@ -2,6 +2,8 @@ import aesjs from "aes-js";
import { Base64 } from "js-base64"; import { Base64 } from "js-base64";
import { saveAs } from "file-saver"; import { saveAs } from "file-saver";
import { sm4 } from "sm-crypto"; import { sm4 } from "sm-crypto";
import AES from './AES'
import SM4 from './SM4'
const blob2Uint8Array = function (blob) { const blob2Uint8Array = function (blob) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -19,7 +21,7 @@ const blob2Uint8Array = function (blob) {
}; };
const decrypt = (key, data) => { const decrypt = (key, data) => {
key = key.trim() key = key.trim()
return blob2Uint8Array(data).then(data => { return blob2Uint8Array(data).then(async data => {
// 无加密 // 无加密
if (key.length === 0) { if (key.length === 0) {
return data; return data;
@@ -28,14 +30,17 @@ const decrypt = (key, data) => {
if (key.length === 19) { if (key.length === 19) {
key = [...aesjs.utils.utf8.toBytes(key.substring(3))]; key = [...aesjs.utils.utf8.toBytes(key.substring(3))];
// console.log([...data]) // console.log([...data])
var decryptedBytes = new Uint8Array(sm4.decrypt([...data], key, { output: "array" })); // var decryptedBytes = new Uint8Array(sm4.decrypt([...data], key, { output: "array" }));
let decryptedBytes = await SM4.decrypt(key, data)
return decryptedBytes; return decryptedBytes;
} else { } else {
// AES // AES
key = aesjs.utils.utf8.toBytes(key); // key = aesjs.utils.utf8.toBytes(key);
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); // var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5));
var decryptedBytes = aesCtr.decrypt(data); // var decryptedBytes = aesCtr.decrypt(data);
return decryptedBytes; // return decryptedBytes;
const decryptedBytes = await AES(key, data)
return decryptedBytes
} }
}); });
}; };
@@ -70,11 +75,22 @@ const decryptString = (key, str) => {
return decryptedStr; return decryptedStr;
}; };
const _saveAs = (blob,fileName)=>{
const blobUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.download = fileName;
a.href = blobUrl;
a.click();
}
const downloadFromUint8Array = (data, fileName) => { const downloadFromUint8Array = (data, fileName) => {
let uint8Array = data; let uint8Array = data;
let blob = new Blob([uint8Array], { type: "application/octet-stream" }); let blob = new Blob([uint8Array], { type: "application/octet-stream" });
// const blobUrl = window.URL.createObjectURL(blob);
// 使用file-saver.js // 使用file-saver.js
saveAs(blob, fileName); saveAs(blob, fileName);
// _saveAs(blob, fileName);
}; };
export { blob2Uint8Array, decrypt, decryptString, downloadFromUint8Array }; export { blob2Uint8Array, decrypt, decryptString, downloadFromUint8Array };
+120 -102
View File
@@ -1,120 +1,138 @@
import aesjs from "aes-js"; import aesjs from "aes-js";
import { Base64 } from "js-base64"; import { Base64 } from "js-base64";
import { sm4 } from 'sm-crypto' import { sm4 } from "sm-crypto";
import AES from "./AES";
import SM4 from "./SM4";
// const setting = useSettingStore(); // const setting = useSettingStore();
// const message = useMessage(); // const message = useMessage();
// 生成密钥 // 生成密钥
const generateKey = function(setting) { const generateKey = function (setting) {
if(setting.activeFuction === "不加密"){ if (setting.activeFuction === "不加密") {
return '' return "";
} }
var charMap = "" var charMap = "";
for(let i of setting.activeKeyMap){ for (let i of setting.activeKeyMap) {
if(i === 'A-Z'){ if (i === "A-Z") {
charMap = charMap + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' charMap = charMap + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}else if(i === "a-z"){ } else if (i === "a-z") {
charMap = charMap + 'abcdefghijklmnopqrstuvwxyz' charMap = charMap + "abcdefghijklmnopqrstuvwxyz";
}else if(i === '0-9'){ } else if (i === "0-9") {
charMap = charMap + '0123456789' charMap = charMap + "0123456789";
} }
} }
var returnStr = "", var returnStr = "",
length = setting.activeFuction !== "AES256" ? 16 : 32 length = setting.activeFuction !== "AES256" ? 16 : 32;
// charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var index = parseInt(Math.random() * charMap.length); var index = parseInt(Math.random() * charMap.length);
returnStr += charMap.substring(index, index + 1); returnStr += charMap.substring(index, index + 1);
} }
if(setting.activeFuction === "SM4"){ if (setting.activeFuction === "SM4") {
returnStr = 'SM4' + returnStr returnStr = "SM4" + returnStr;
} }
// console.log(returnStr,returnStr.length) // console.log(returnStr,returnStr.length)
return returnStr; return returnStr;
}; };
const blob2Uint8Array = function(blob) { const blob2Uint8Array = function (blob) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let reader = new FileReader(); let reader = new FileReader();
reader.readAsArrayBuffer(blob); reader.readAsArrayBuffer(blob);
reader.onload = function() { reader.onload = function () {
let buffer = reader.result; let buffer = reader.result;
let uint8array = new Uint8Array(buffer); let uint8array = new Uint8Array(buffer);
resolve(uint8array); resolve(uint8array);
}; };
reader.onerror = function() { reader.onerror = function () {
reject(reader.error); reject(reader.error);
}; };
}); });
}; };
// const AES = (key, data) => {
const AES = (key,data)=>{ // key = aesjs.utils.utf8.toBytes(key)
key = aesjs.utils.utf8.toBytes(key); // // var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5))
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); // // var encryptedBytes = aesCtr.encrypt(data)
var encryptedBytes = aesCtr.encrypt(data); // // return encryptedBytes
return encryptedBytes; // return new Promise((resolve) => {
} // const aesWorker = new aes_worker()
const SM4 = (key,data)=>{ // aesWorker.onmessage = (event) => {
// console.log(key) // resolve(event.data)
var encryptedBytes = sm4.encrypt(data,key,{padding: 'pkcs#7',output:'array'}); // }
// console.log(encryptedBytes, sm4.decrypt(encryptedBytes, key,{output:'array'})) // aesWorker.postMessage({ data, key })
return new Uint8Array(encryptedBytes); // })
} // }
// const SM4 = (key, data) => {
// // console.log(key)
// var encryptedBytes = sm4.encrypt(data, key, {
// padding: 'pkcs#7',
// output: 'array'
// })
// // console.log(encryptedBytes, sm4.decrypt(encryptedBytes, key,{output:'array'}))
// return new Uint8Array(encryptedBytes)
// }
const encrypt = (key, data, fileName, setting, message) => { const encrypt = (key, data, fileName, setting, message) => {
// if(!encryptFunction){ // if(!encryptFunction){
// encryptFunction = setting.activeFuction // encryptFunction = setting.activeFuction
// } // }
let encryptFunction = {0:'不加密',16:'AES128',19:'SM4',32:'AES256'}[key.length] let encryptFunction = {
return blob2Uint8Array(data).then(data => { 0: "不加密",
let encrypted_data = null 16: "AES128",
if(encryptFunction === "不加密"|| key === ''){ 19: "SM4",
encrypted_data = data 32: "AES256"
// AES }[key.length];
}else if(encryptFunction != "SM4"){ return blob2Uint8Array(data).then(async data => {
if(message) let encrypted_data = null;
message.info(`开始加密${fileName}`); if (encryptFunction === "不加密" || key === "") {
encrypted_data = AES(key,data) encrypted_data = data;
if(message) // AES
message.info(`${fileName}加密完成`); } else if (encryptFunction != "SM4") {
// SM4 if (message) message.info(`开始加密${fileName}`);
}else{ encrypted_data = await AES(key, data);
if(message) if (message) message.info(`${fileName}加密完成`);
message.info(`开始加密${fileName}`); // SM4
key = [...aesjs.utils.utf8.toBytes(key.substring(3))]; } else {
encrypted_data = SM4(key,data) if (message) message.info(`开始加密${fileName}`);
if(message) key = [...aesjs.utils.utf8.toBytes(key.substring(3))];
message.info(`${fileName}加密完成`); encrypted_data = await SM4.encrypt(key, data);
} if (message) message.info(`${fileName}加密完成`);
return encrypted_data }
}); console.log(encrypted_data);
return encrypted_data;
});
}; };
// setting为pinia存储的setting。。。 // setting为pinia存储的setting。。。
const encryptString = (key, str, setting) => { const encryptString = (key, str, setting) => {
// if(!encryptFunction){ // if(!encryptFunction){
// encryptFunction = setting.activeFuction // encryptFunction = setting.activeFuction
// } // }
// console.log(key,key.length) // console.log(key,key.length)
let encryptFunction = {0:'不加密',16:'AES128',19:'SM4',32:'AES256'}[key.length] let encryptFunction = {
if(encryptFunction === "不加密" || key === ''){ 0: "不加密",
// return sm4.encrypt(str, 'miaospringmiaospringmiaospringao') 16: "AES128",
return Base64.encode(str) 19: "SM4",
}else if(encryptFunction !== "SM4"){ 32: "AES256"
key = aesjs.utils.utf8.toBytes(key); }[key.length];
// var data = aesjs.utils.utf8.toBytes(str); if (encryptFunction === "不加密" || key === "") {
var data = new TextEncoder().encode(str) // return sm4.encrypt(str, 'miaospringmiaospringmiaospringao')
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); return Base64.encode(str);
var encryptedBytes = aesCtr.encrypt(data); } else if (encryptFunction !== "SM4") {
var res = Base64.fromUint8Array(encryptedBytes,true); key = aesjs.utils.utf8.toBytes(key);
// console.log(encryptedBytes,res) // var data = aesjs.utils.utf8.toBytes(str);
return res; var data = new TextEncoder().encode(str);
}else{ var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5));
key = [...aesjs.utils.utf8.toBytes(key.substring(3))]; var encryptedBytes = aesCtr.encrypt(data);
// console.log(key) var res = Base64.fromUint8Array(encryptedBytes, true);
return sm4.encrypt(str, key) // console.log(encryptedBytes,res)
} return res;
} else {
key = [...aesjs.utils.utf8.toBytes(key.substring(3))];
// console.log(key)
return sm4.encrypt(str, key);
}
}; };
export {encrypt,encryptString,generateKey} export { encrypt, encryptString, generateKey };
+67 -44
View File
@@ -1,60 +1,83 @@
import { defineStore } from "pinia"; import { defineStore } from 'pinia'
import config from "../../miaoShareConfig.json" import config from '../../miaoShareConfig.json'
const userID = localStorage.getItem('userID'); console.log(location)
const userGroup = localStorage.getItem('userGroup');
const token = localStorage.getItem('token'); const userID = localStorage.getItem('userID')
// console.log(token) const userGroup = localStorage.getItem('userGroup')
const tokenExpiresIn = config.tokenExpiresIn
if (
localStorage.getItem('tokenExpiredTime') == null ||
parseInt(localStorage.getItem('tokenExpiredTime')) < parseInt(Date.now())
) {
localStorage.removeItem('token')
}
const token = localStorage.getItem('token')
var activeFuctionLocal = localStorage.getItem('activeFuction') var activeFuctionLocal = localStorage.getItem('activeFuction')
if (activeFuctionLocal == null){ if (activeFuctionLocal == null) {
activeFuctionLocal = 'AES128' activeFuctionLocal = 'AES128'
localStorage.setItem('activeFuction',activeFuctionLocal) localStorage.setItem('activeFuction', activeFuctionLocal)
} }
// localStorage.removeItem('activeKeyMap') // localStorage.removeItem('activeKeyMap')
var activeKeyMap = localStorage.getItem('activeKeyMap') var activeKeyMap = localStorage.getItem('activeKeyMap')
if (activeKeyMap == null ){ if (activeKeyMap == null) {
activeKeyMap = JSON.stringify(['A-Z','0-9']) activeKeyMap = JSON.stringify(['A-Z', '0-9'])
localStorage.setItem('activeKeyMap',activeKeyMap) localStorage.setItem('activeKeyMap', activeKeyMap)
} }
// 开发环境下服务器端口使用设置的端口,否则使用与页面相同的端口 // 开发环境下服务器端口使用设置的端口,否则使用与页面相同的端口
const serverPort = process.env.NODE_ENV === 'development' ? config.PORT : location.port const serverPort =
process.env.NODE_ENV === 'development' ? config.PORT : location.port
const baseUrl =
location.protocol + '//' + location.hostname + ':' + serverPort + '/'
const wsBaseUrl = 'ws' + '://' + location.hostname + ':' + serverPort
// console.log(process.env.NODE_ENV,config.DEVPORT,location.port,serverPort) // console.log(process.env.NODE_ENV,config.DEVPORT,location.port,serverPort)
export const useSettingStore = defineStore("setting", { export const useSettingStore = defineStore('setting', {
state: () => ({ state: () => ({
activeFuction: activeFuctionLocal, activeFuction: activeFuctionLocal,
activeKeyMap:JSON.parse(activeKeyMap), activeKeyMap: JSON.parse(activeKeyMap),
enableGuest:config.enableGuest, enableGuest: config.enableGuest,
serverPort, serverPort,
token, token,
userID, userID,
userGroup userGroup,
baseUrl,
wsBaseUrl
}), }),
getters: { getters: {
// double: state => state.count * 2 // double: state => state.count * 2
}, },
actions: { actions: {
setJWT( token,keepTokenLocal ){ setJWT(token, keepTokenLocal) {
this.token = token this.token = token
if(keepTokenLocal) if (keepTokenLocal) {
localStorage.setItem('token',token) localStorage.setItem('token', token)
}, localStorage.setItem(
setUserID( id,keepTokenLocal ){ 'tokenExpiredTime',
this.userID = id parseInt(Date.now()) + parseInt(tokenExpiresIn) * 3600000
if(keepTokenLocal) )
localStorage.setItem('userID',id) }
}, },
setUserGroup( g,keepTokenLocal ){ setUserID(id, keepTokenLocal) {
this.userGroup = g this.userID = id
if(keepTokenLocal) if (keepTokenLocal) localStorage.setItem('userID', id)
localStorage.setItem('userGroup',g) },
} setUserGroup(g, keepTokenLocal) {
// increment() { this.userGroup = g
// this.count++; if (keepTokenLocal) localStorage.setItem('userGroup', g)
// } },
} getToken() {
}); return localStorage.getItem('token')
}
// increment() {
// this.count++;
// }
}
})
+18 -11
View File
@@ -3,7 +3,7 @@
<n-flex style="padding-top: 10px;"> <n-flex style="padding-top: 10px;">
<n-input v-model:value="groupCode" type="text" placeholder="输入邀请码" style="flex:1"> <n-input v-model:value="groupCode" type="text" placeholder="输入邀请码" style="flex:1">
<template #suffix> <template #suffix>
<n-icon :component="CopyOutline" style="cursor: pointer;" @click='toClipboard(groupCode)' /> <n-icon :component="CopyOutline" style="cursor: pointer;" @click='_toClipboard(groupCode)' />
</template> </template>
</n-input> </n-input>
<n-flex> <n-flex>
@@ -37,7 +37,7 @@
<div style="flex:1; position: relative;min-height: none;"> <div style="flex:1; position: relative;min-height: none;">
<chatui style="margin-bottom: 10px; height: 65vh" <chatui style="margin-bottom: 10px; height: 65vh"
:messages="activeGID ? Messages[activeGID].map(v => { v.timestampString = new Date(v.timestamp).toLocaleString(); return v }).reverse() : []"/> :messages="activeGID ? Messages[activeGID].map(v => { v.timestampString = new Date(v.timestamp).toLocaleString(); return v }).reverse() : []"/>
<n-input v-model:value="msgInput" type="textarea" placeholder="发送信息" :autosize="{ <n-input v-model:value="msgInput" type="textarea" placeholder="发送信息" :autosize="{
minRows: 1, minRows: 1,
maxRows: 2 maxRows: 2
@@ -48,7 +48,7 @@
<n-icon :component="SendOutline" style="cursor: pointer;" @click='sendMsg(activeGID, msgInput)'/> <n-icon :component="SendOutline" style="cursor: pointer;" @click='sendMsg(activeGID, msgInput)'/>
</template> </template>
</n-input> </n-input>
<!-- <n-button @click="sendMsg(activeGID, msg)" :disabled="msg === '' || activeGID === null" <!-- <n-button @click="sendMsg(activeGID, msg)" :disabled="msg === '' || activeGID === null"
:type="msg === '' || activeGID === null ? 'default' : 'primary'"> :type="msg === '' || activeGID === null ? 'default' : 'primary'">
发送消息 发送消息
@@ -58,7 +58,7 @@
<!-- {{ dataTest }} --> <!-- {{ dataTest }} -->
<!-- {{ Messages }} --> <!-- {{ Messages }} -->
<n-modal v-model:show="showModal"> <n-modal v-model:show="showModal">
<n-card <n-card
style="width: fit-content;" style="width: fit-content;"
@@ -68,8 +68,8 @@
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
> >
<n-qr-code :value="QRCodeData" style="padding: 0;" :size="256" error-correction-level="Q" :v-if="showModal" <n-qr-code :value="QRCodeData" style="padding: 0;" :size="256" error-correction-level="Q" :v-if="showModal"
:icon-src='0?QRIconUrl:null' :icon-src='0?QRIconUrl:null'
:icon-size="128"/> :icon-size="128"/>
</n-card> </n-card>
</n-modal> </n-modal>
@@ -98,11 +98,18 @@ const message = useMessage()
// const modal = useModal(); // const modal = useModal();
const { toClipboard } = useClipboard(); const { toClipboard } = useClipboard();
const _toClipboard = async (text) => {
await toClipboard(text)
message.info(`已复制 ${text.length < 10 ? text : text.substring(0,7) + '...'}`)
}
const setting = useSettingStore(); const setting = useSettingStore();
const serverPort = setting.serverPort; const serverPort = setting.serverPort;
const wsBaseUrl = 'ws' + "://" + location.hostname + ":" + serverPort; // const wsBaseUrl = 'ws' + "://" + location.hostname + ":" + serverPort;
const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/"; const wsBaseUrl = setting.wsBaseUrl
const QRIconUrl = ref(location.protocol + "//" + location.hostname + ":" + serverPort + "/favicon.ico") // const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/";
const baseUrl = setting.baseUrl
const QRIconUrl = ref(baseUrl + "favicon.ico")
const columns = [ const columns = [
{ {
@@ -285,7 +292,7 @@ function joinGroup_Verify(gID) {
} }
function sendMsg(gID, msg) { function sendMsg(gID, msg) {
if(msg === '' || msg === null || activeGID.value === null)return if(msg === '' || msg === null || activeGID.value === null)return
let key = gID2key[gID].key let key = gID2key[gID].key
msg = encryptString(key, msg, setting) msg = encryptString(key, msg, setting)
socket.send(JSON.stringify({ type: 'message',type1:'text', msg, gID })) socket.send(JSON.stringify({ type: 'message',type1:'text', msg, gID }))
@@ -301,7 +308,7 @@ function sendMsg(gID, msg) {
// } // }
async function uploadFile(file){ async function uploadFile(file){
if(activeGID.value === null)return if(activeGID.value === null)return
var fileName = file.name; var fileName = file.name;
let key = gID2key[activeGID.value].key let key = gID2key[activeGID.value].key
const encryptedFileName = encryptString(key, fileName, setting); const encryptedFileName = encryptString(key, fileName, setting);
+2 -2
View File
@@ -40,8 +40,8 @@ const setting = useSettingStore();
// 服务端端口 // 服务端端口
const serverPort = setting.serverPort; const serverPort = setting.serverPort;
var baseUrl = // const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/";
location.protocol + "//" + location.hostname + ":" + serverPort + "/"; const baseUrl = setting.baseUrl
// console.log(baseUrl); // console.log(baseUrl);
// const blob2Uint8Array = function(blob) { // const blob2Uint8Array = function(blob) {
+2 -2
View File
@@ -43,8 +43,8 @@ const serverPort = settingData.serverPort;
const userIDInput = ref('') const userIDInput = ref('')
const userPasswordInput = ref('') const userPasswordInput = ref('')
const isLogining = ref(false) const isLogining = ref(false)
const baseUrl = // const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/";
location.protocol + "//" + location.hostname + ":" + serverPort + "/"; const baseUrl = settingData.baseUrl
const Token = computed(() => settingData.token) const Token = computed(() => settingData.token)
const keepTokenLocal = ref(true) const keepTokenLocal = ref(true)
+4 -3
View File
@@ -19,7 +19,7 @@
</n-p> </n-p>
</n-upload-dragger> </n-upload-dragger>
</n-upload> </n-upload>
<n-flex justify="end" style="margin: 10px 0;position:relative"> <n-flex justify="end" style="margin: 10px 0;position:relative">
<n-input-number v-model:value="downloadCredit" placeholder="可下载次数,默认无限" clearable :min="1" :max="2147483647" style="width:max-content"/> <n-input-number v-model:value="downloadCredit" placeholder="可下载次数,默认无限" clearable :min="1" :max="2147483647" style="width:max-content"/>
<n-button type="primary" @click="clickUpload">开始上传</n-button> <n-button type="primary" @click="clickUpload">开始上传</n-button>
@@ -94,8 +94,9 @@ var file_Code_Map = ref([]);
var uploadProcess = ref(0); var uploadProcess = ref(0);
const baseUrl = // const baseUrl = location.protocol + "//" + location.hostname + ":" + serverPort + "/";
location.protocol + "//" + location.hostname + ":" + serverPort + "/"; const baseUrl = setting.baseUrl
console.log(baseUrl)
// const blob2Uint8Array = function(blob) { // const blob2Uint8Array = function(blob) {
+9
View File
@@ -0,0 +1,9 @@
import aesjs from 'aes-js'
self.onmessage = async function (event) {
const data = event.data.data
const key = event.data.key
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(7058))
const encryptData = aesCtr.encrypt(data)
self.postMessage(encryptData)
}
+9
View File
@@ -0,0 +1,9 @@
import { sm4 } from 'sm-crypto'
self.onmessage = async function (event) {
const data = event.data.data
const key = event.data.key
self.postMessage(
new Uint8Array(sm4.decrypt([...data], key, { output: 'array' }))
)
}
+11
View File
@@ -0,0 +1,11 @@
import { sm4 } from 'sm-crypto'
self.onmessage = async function (event) {
const data = event.data.data
const key = event.data.key
const encryptData = sm4.encrypt(data, key, {
padding: 'pkcs#7',
output: 'array'
})
self.postMessage(new Uint8Array(encryptData))
}
+43 -20
View File
@@ -1,24 +1,47 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from "node:url";
import { visualizer } from "rollup-plugin-visualizer";
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import vue from '@vitejs/plugin-vue' import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
vue(), vue(),
], visualizer({
resolve: { open: true,
alias: { filename: "visualizer.html" //分析图生成的文件名
'@': fileURLToPath(new URL('./src', import.meta.url)) })
} ],
}, resolve: {
server:{ alias: {
// host:'0.0.0.0', "@": fileURLToPath(new URL("./src", import.meta.url))
port:'17058', }
open:true, },
}, server: {
esbuild: { // host:'0.0.0.0',
drop: ['console', 'debugger'], port: "17058",
}, open: true
}) },
esbuild: {
drop: ["console", "debugger"]
},
build: {
minify: true,
rollupOptions: {
output: {
// 打包输出的配置
manualChunks: id => {
// 这个ID,就是所有文件的绝对路径
if (id.includes("node_modules")) {
// 因为 node_modules 中的依赖通常是不会改变的
// 所以直接单独打包出去
// 这个return 的值就是打包的名称
// return id.split('node_modules')[1]
return "modules";
}
}
}
}
}
});