jsir 2.5.1 → 2.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/oaa.js +5 -5
- package/deps/room.js +24 -19
- package/deps/server.js +16 -10
- package/deps/setting.js +1 -0
- package/deps/util.js +25 -15
- package/package.json +1 -1
package/cmd/oaa.js
CHANGED
|
@@ -645,7 +645,7 @@ async function _wrapperInput(str) {
|
|
|
645
645
|
if (strs[1] === '-') {
|
|
646
646
|
await offServer(uniqueName)
|
|
647
647
|
} else {
|
|
648
|
-
await joinServer(uniqueName)
|
|
648
|
+
await joinServer(uniqueName, strs[1] === '+')
|
|
649
649
|
}
|
|
650
650
|
} else {
|
|
651
651
|
console.log(String(fs.readFileSync(path)));
|
|
@@ -656,7 +656,7 @@ async function _wrapperInput(str) {
|
|
|
656
656
|
}
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
-
async function joinServer(uniqueName) {
|
|
659
|
+
async function joinServer(uniqueName, isApi) {
|
|
660
660
|
let exportLib = await _requireSource(setting.defaultSpace, uniqueName, true);
|
|
661
661
|
let asyncFnSize = 0
|
|
662
662
|
for (let key of Object.keys(exportLib)) {
|
|
@@ -675,12 +675,12 @@ async function joinServer(uniqueName) {
|
|
|
675
675
|
let val = exportLib[key];
|
|
676
676
|
Server.setRoute('get', `/${pair[0]}/${trimJsirFileName(pair[1])}/${key}`,async (req, res) => {
|
|
677
677
|
res.result = await val(...req);
|
|
678
|
-
})
|
|
678
|
+
}, isApi)
|
|
679
679
|
Server.setRoute('post', `/${pair[0]}/${trimJsirFileName(pair[1])}/${key}`,async (req, res) => {
|
|
680
680
|
res.result = await val(...req);
|
|
681
|
-
})
|
|
681
|
+
}, isApi)
|
|
682
682
|
}
|
|
683
|
-
console.msg(uniqueName,
|
|
683
|
+
console.msg(uniqueName, `has become a ${isApi ? "api ":""}service.`);
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
async function offServer(uniqueName) {
|
package/deps/room.js
CHANGED
|
@@ -54,7 +54,6 @@ async function localConfigs() {
|
|
|
54
54
|
function onRoom(wrapperInput) {
|
|
55
55
|
if (!setting.roomTid[0]) {
|
|
56
56
|
try {
|
|
57
|
-
setRoute("post", "/", (req, res) => setting.selfRoom)
|
|
58
57
|
setRoute("get", "/", (req, res) => setting.selfRoom)
|
|
59
58
|
setRoute("post", "/enter", async (req, res) => {
|
|
60
59
|
if (!getConfig("enableRemote", true)) {
|
|
@@ -114,44 +113,45 @@ function offRoom() {
|
|
|
114
113
|
function getSelfIP(nodes) {
|
|
115
114
|
let ips = getLocalIPs().ipv4;
|
|
116
115
|
ips = ips.filter(i => nodes.indexOf(i) !== -1);
|
|
117
|
-
return ips[0]
|
|
116
|
+
return ips[0] || '127.0.0.1'
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
async function getTailscaleNodes() {
|
|
121
120
|
let resp = await e(`${tailscalePath} status`);
|
|
122
121
|
let nodes = {}
|
|
123
122
|
for (let line of resp.split("\n").map(trim)) {
|
|
124
|
-
|
|
125
|
-
continue
|
|
126
|
-
}
|
|
123
|
+
let offline = line.indexOf('offline') !== -1
|
|
127
124
|
let ss = line.split(/\s+/);
|
|
128
125
|
if (/^\d+\.\d+\.\d+\.\d+$/.test(ss[0])) {
|
|
129
|
-
nodes[ss[0]] =
|
|
126
|
+
nodes[ss[0]] = {
|
|
127
|
+
name: ss[1],
|
|
128
|
+
offline
|
|
129
|
+
}
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
return nodes;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async function updateRoomInfo() {
|
|
136
|
-
|
|
137
|
-
let nodes = Object.keys(nodeMap)
|
|
136
|
+
setting.nodeMap = await getTailscaleNodes();
|
|
137
|
+
let nodes = Object.keys(setting.nodeMap)
|
|
138
138
|
let ip = getSelfIP(nodes)
|
|
139
139
|
await fileJson(roomDataFile, async room => {
|
|
140
|
+
room = {
|
|
141
|
+
jsirs: room.jsirs
|
|
142
|
+
}
|
|
140
143
|
// 设置roomName
|
|
141
|
-
let name = nodeMap[ip] || os.hostname();
|
|
144
|
+
let name = setting.nodeMap[ip]?.name || os.hostname();
|
|
142
145
|
if (!vl(room.name) || room.name !== name) {
|
|
143
146
|
room.name = name;
|
|
144
147
|
debug("set roomName", name)
|
|
145
148
|
}
|
|
146
149
|
room.selfNode = ip;
|
|
147
|
-
room.nodes = nodes;
|
|
148
150
|
room.lastUpdateTime = Date.now()
|
|
149
151
|
debug("init room", room.name)
|
|
150
152
|
|
|
151
|
-
// 提前设置一下
|
|
152
|
-
setting.selfRoom = Object.assign(setting.selfRoom || {}, room);
|
|
153
|
-
|
|
154
153
|
await cleanRoom(room)
|
|
154
|
+
return room;
|
|
155
155
|
})
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -161,10 +161,13 @@ async function syncRooms() {
|
|
|
161
161
|
|
|
162
162
|
let syncRooms = []
|
|
163
163
|
let fns = []
|
|
164
|
-
for (let node of
|
|
164
|
+
for (let node of Object.keys(setting.nodeMap)) {
|
|
165
165
|
if (node === room.selfNode) {
|
|
166
166
|
continue
|
|
167
167
|
}
|
|
168
|
+
if (setting.nodeMap[node]?.offline) {
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
168
171
|
fns.push(async () => {
|
|
169
172
|
let respBody = ''
|
|
170
173
|
try {
|
|
@@ -196,9 +199,8 @@ async function syncRooms() {
|
|
|
196
199
|
|
|
197
200
|
// 清理 roomsDir
|
|
198
201
|
let files = await fp.readdir(roomsDir)
|
|
199
|
-
let nodes = room.nodes;
|
|
200
202
|
for (let file of files) {
|
|
201
|
-
if (
|
|
203
|
+
if (!setting.nodeMap[file]) {
|
|
202
204
|
try {
|
|
203
205
|
await fp.unlink(roomsDir + '/' + file)
|
|
204
206
|
} catch (e) {
|
|
@@ -219,7 +221,7 @@ async function _syncSetting(room) {
|
|
|
219
221
|
let roomDir = getRoomsDir();
|
|
220
222
|
let rooms = []
|
|
221
223
|
let files = await fp.readdir(roomDir);
|
|
222
|
-
for (let node of setting.
|
|
224
|
+
for (let node of Object.keys(setting.nodeMap)) {
|
|
223
225
|
if (setting.selfRoom.selfNode === node) {
|
|
224
226
|
continue
|
|
225
227
|
}
|
|
@@ -247,6 +249,9 @@ async function _syncSetting(room) {
|
|
|
247
249
|
setting.services = {}
|
|
248
250
|
setting.serviceFns = {}
|
|
249
251
|
for (const room of setting.rooms) {
|
|
252
|
+
if (setting.nodeMap[room.selfNode]?.offline) {
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
250
255
|
for (const pid of Object.keys(room.jsirs || {})) {
|
|
251
256
|
let jsir = room.jsirs[pid];
|
|
252
257
|
for (const service of Object.keys(jsir.services || {})) {
|
|
@@ -281,7 +286,7 @@ async function initRoom() {
|
|
|
281
286
|
if (roomUpdateTouchTime) {
|
|
282
287
|
await fileLock(updateRoomInfoLockKey, updateRoomInfo, false)
|
|
283
288
|
fileLock(syncRoomsLockKey, syncRooms, false);
|
|
284
|
-
if (!configMain && setting.serviceFns
|
|
289
|
+
if (!configMain && setting.serviceFns[setting.configMainFnKey]) {
|
|
285
290
|
fileLock(syncConfigsLockKey, syncConfigs, false);
|
|
286
291
|
}
|
|
287
292
|
}
|
|
@@ -382,7 +387,7 @@ async function initRoomJsir(room) {
|
|
|
382
387
|
busy: await getEventLoopDelay() || (lastJsir ? lastJsir.busy:0),
|
|
383
388
|
back: isRunningInBackground(),
|
|
384
389
|
lastUpdateTime: Date.now(),
|
|
385
|
-
port: setting.server ? setting.server.address()
|
|
390
|
+
port: setting.server ? setting.server.address()?.port:null,
|
|
386
391
|
services: services,
|
|
387
392
|
newError: global.$newError,
|
|
388
393
|
version: packageJson.version,
|
package/deps/server.js
CHANGED
|
@@ -7,7 +7,6 @@ const preferredPort = setting.defaultPort;
|
|
|
7
7
|
// 路由存储
|
|
8
8
|
const routes = setting.routes;
|
|
9
9
|
let invokeStart = false;
|
|
10
|
-
const apiReg = /[^a-zA-Z]api[^a-zA-Z]|[^a-zA-Z]api$/i;
|
|
11
10
|
|
|
12
11
|
function debug(...args) {
|
|
13
12
|
if (global.$DEBUG) {
|
|
@@ -17,7 +16,7 @@ function debug(...args) {
|
|
|
17
16
|
|
|
18
17
|
function verifySign(sign) {
|
|
19
18
|
try {
|
|
20
|
-
let key = md5(
|
|
19
|
+
let key = md5(Object.keys(setting.nodeMap).sort().join(":")).substring(0, 16);
|
|
21
20
|
return parseInt(aesDecipher(sign, key), 10); // 假设sign是base64编码的毫秒数
|
|
22
21
|
} catch (e) {
|
|
23
22
|
return null; // 解码失败返回null
|
|
@@ -26,7 +25,7 @@ function verifySign(sign) {
|
|
|
26
25
|
|
|
27
26
|
function createSign() {
|
|
28
27
|
try {
|
|
29
|
-
let key = md5(
|
|
28
|
+
let key = md5(Object.keys(setting.nodeMap).sort().join(":")).substring(0, 16);
|
|
30
29
|
return aesCipher(String(Date.now()), key)
|
|
31
30
|
} catch (e) {
|
|
32
31
|
return null; // 解码失败返回null
|
|
@@ -34,8 +33,9 @@ function createSign() {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
async function process(routeKey, req, res, params) {
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
let router = routes[routeKey]
|
|
37
|
+
if (router) {
|
|
38
|
+
if ("get /" !== routeKey && !router.isApi) {
|
|
39
39
|
// 如果不是api接口,则校验签名
|
|
40
40
|
// 取header里的sign字段
|
|
41
41
|
const sign = req.headers['sign'];
|
|
@@ -70,7 +70,7 @@ async function process(routeKey, req, res, params) {
|
|
|
70
70
|
resolve()
|
|
71
71
|
})
|
|
72
72
|
})
|
|
73
|
-
await
|
|
73
|
+
await router.fn(body || params, res);
|
|
74
74
|
} catch (e) {
|
|
75
75
|
res.writeHead(500, {'Content-Type': 'text/plain'});
|
|
76
76
|
res.end(String(isError(e) ? e.message : e));
|
|
@@ -140,16 +140,22 @@ async function startServer() {
|
|
|
140
140
|
method, url, fn(req, res, err), null
|
|
141
141
|
err: {code, msg}
|
|
142
142
|
*/
|
|
143
|
-
function setRoute(method, url, fn, handler = jsonHandle) {
|
|
143
|
+
function setRoute(method, url, fn, handler = jsonHandle, isApi) {
|
|
144
144
|
startServer();
|
|
145
145
|
|
|
146
146
|
const routeKey = `${method.toLowerCase()} ${url}`;
|
|
147
147
|
if (handler) {
|
|
148
|
-
routes[routeKey] =
|
|
149
|
-
|
|
148
|
+
routes[routeKey] = {
|
|
149
|
+
fn: async (req, res) => {
|
|
150
|
+
await handler(req, res, fn)
|
|
151
|
+
},
|
|
152
|
+
isApi
|
|
150
153
|
};
|
|
151
154
|
} else {
|
|
152
|
-
routes[routeKey] =
|
|
155
|
+
routes[routeKey] = {
|
|
156
|
+
fn,
|
|
157
|
+
isApi
|
|
158
|
+
};
|
|
153
159
|
}
|
|
154
160
|
debug(`setRoute: ${method.toUpperCase()} ${url} ${handler ? handler.name:''}`);
|
|
155
161
|
return setting.server;
|
package/deps/setting.js
CHANGED
package/deps/util.js
CHANGED
|
@@ -935,21 +935,25 @@ function validStr(str, name) {
|
|
|
935
935
|
}
|
|
936
936
|
}
|
|
937
937
|
|
|
938
|
-
function aesCipher(str, key){
|
|
938
|
+
function aesCipher(str, key, useIv = false){
|
|
939
939
|
validStr(str, "str");
|
|
940
940
|
validStr(key, "key");
|
|
941
941
|
|
|
942
942
|
key = trim(key);
|
|
943
943
|
if (!key || key.length > 16) {
|
|
944
|
-
throw "aesCipher key length should between 1 and 16"
|
|
944
|
+
throw "aesCipher key length should be between 1 and 16"
|
|
945
945
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
946
|
+
if (useIv) {
|
|
947
|
+
// Generate random IV
|
|
948
|
+
const iv = crypto.randomBytes(16);
|
|
949
|
+
const cipher = crypto.createCipheriv('aes-128-cbc', pad(key, 16, '0'), iv);
|
|
950
|
+
|
|
951
|
+
// Return IV and ciphertext, as IV is needed for decryption
|
|
952
|
+
const ciphertext = cipher.update(str, 'utf8', 'hex') + cipher.final('hex');
|
|
953
|
+
return iv.toString('hex') + ':' + ciphertext; // Combine IV and ciphertext
|
|
952
954
|
}
|
|
955
|
+
const cipher = crypto.createCipheriv('aes-128-ecb', pad(key, 16, '0'), null);
|
|
956
|
+
return cipher.update(str, 'utf8', 'hex') + cipher.final('hex');
|
|
953
957
|
}
|
|
954
958
|
|
|
955
959
|
function aesDecipher(str, key){
|
|
@@ -958,15 +962,21 @@ function aesDecipher(str, key){
|
|
|
958
962
|
|
|
959
963
|
key = trim(key);
|
|
960
964
|
if (!key || key.length > 16) {
|
|
961
|
-
throw "aesCipher key length should between 1 and 16"
|
|
965
|
+
throw "aesCipher key length should be between 1 and 16";
|
|
962
966
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
967
|
+
|
|
968
|
+
// Extract IV and ciphertext
|
|
969
|
+
if(str.indexOf(":") !== -1) {
|
|
970
|
+
const [ivHex, ciphertext] = str.split(':');
|
|
971
|
+
if (!ivHex || !ciphertext) {
|
|
972
|
+
throw "Invalid encrypted string format";
|
|
973
|
+
}
|
|
974
|
+
const iv = Buffer.from(ivHex, 'hex');
|
|
975
|
+
const decipher = crypto.createDecipheriv('aes-128-cbc', pad(key, 16, '0'), iv);
|
|
976
|
+
return decipher.update(ciphertext, 'hex', 'utf8') + decipher.final('utf8');
|
|
969
977
|
}
|
|
978
|
+
const decipher = crypto.createDecipheriv('aes-128-ecb', pad(key, 16, '0'), null);
|
|
979
|
+
return decipher.update(str, 'hex', 'utf8') + decipher.final('utf8');
|
|
970
980
|
}
|
|
971
981
|
|
|
972
982
|
function getConfig(key, defaultVal) {
|