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 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, 'has become a service.');
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
- if (line.indexOf('offline') !== -1) {
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]] = ss[1]
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
- let nodeMap = await getTailscaleNodes();
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 room.nodes) {
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 (nodes.indexOf(file) === -1) {
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.selfRoom.nodes) {
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.hasOwnProperty(setting.configMainFnKey)) {
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().port:null,
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([...setting.selfRoom.nodes].sort().join(":")).substring(0, 16);
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([...setting.selfRoom.nodes].sort().join(":")).substring(0, 16);
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
- if (routes[routeKey]) {
38
- if (!apiReg.test(routeKey)) {
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 routes[routeKey](body || params, res);
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] = async (req, res) => {
149
- await handler(req, res, fn)
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] = fn;
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
@@ -22,6 +22,7 @@ module.exports = {
22
22
  workspaceMap: {},
23
23
  enableNextLine: true,
24
24
  roomTid: [],
25
+ nodeMap: {},
25
26
  selfRoom: {},
26
27
  rooms: [],
27
28
  server: null,
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
- try {
947
- const cipher = crypto.createCipheriv('aes-128-ecb', pad(key, 16, '0'), null);
948
- return cipher.update(str, 'utf8', 'hex') + cipher.final('hex');
949
- } catch(err) {
950
- $log(err)
951
- throw 'aesCipher failed: ' + String(err)
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
- try {
964
- const decipher = crypto.createDecipheriv('aes-128-ecb', pad(key, 16, '0'), null);
965
- return decipher.update(str, 'hex', 'utf8') + decipher.final('utf8');
966
- } catch(err) {
967
- $log(err)
968
- throw 'aesDecipher failed: ' + String(err)
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsir",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "JavaScript Script Management Tool",
5
5
  "main": "index.js",
6
6
  "scripts": {