asaihost-nodejs 0.0.6 → 0.0.9
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/dist/asaihost-nodejs.cjs +591 -485
- package/dist/asaihost-nodejs.cjs.map +1 -1
- package/dist/asaihost-nodejs.es.js +280 -174
- package/dist/asaihost-nodejs.es.js.map +1 -1
- package/package.json +1 -1
|
@@ -399,7 +399,7 @@ var LogBuffer = class _LogBuffer {
|
|
|
399
399
|
}
|
|
400
400
|
};
|
|
401
401
|
function saveLog($asai, src, logstr) {
|
|
402
|
-
return new Promise((
|
|
402
|
+
return new Promise((resolve6, reject) => {
|
|
403
403
|
try {
|
|
404
404
|
const bufferKey = `${$asai.id || "default"}_${src}`;
|
|
405
405
|
let logBuffer = logBuffers.get(bufferKey);
|
|
@@ -408,7 +408,7 @@ function saveLog($asai, src, logstr) {
|
|
|
408
408
|
logBuffers.set(bufferKey, logBuffer);
|
|
409
409
|
}
|
|
410
410
|
logBuffer.add(logstr);
|
|
411
|
-
|
|
411
|
+
resolve6();
|
|
412
412
|
} catch (err) {
|
|
413
413
|
console.error(err);
|
|
414
414
|
reject(err);
|
|
@@ -915,7 +915,7 @@ import * as https from "https";
|
|
|
915
915
|
import { WebSocketServer } from "ws";
|
|
916
916
|
|
|
917
917
|
// src/ws/auth.ts
|
|
918
|
-
import { WebSocket } from "ws";
|
|
918
|
+
import { WebSocket as WebSocket2 } from "ws";
|
|
919
919
|
|
|
920
920
|
// src/utils/userinfo.ts
|
|
921
921
|
function deUserInfoWithAsai(userinfo, $asai) {
|
|
@@ -940,6 +940,79 @@ function deUserInfoWithAsai(userinfo, $asai) {
|
|
|
940
940
|
}
|
|
941
941
|
__name(deUserInfoWithAsai, "deUserInfoWithAsai");
|
|
942
942
|
|
|
943
|
+
// src/ws/ws-probe.ts
|
|
944
|
+
import { WebSocket } from "ws";
|
|
945
|
+
function isWsStillActive(ws2) {
|
|
946
|
+
if (!ws2) return false;
|
|
947
|
+
const state = ws2.readyState;
|
|
948
|
+
return state === WebSocket.CONNECTING || state === WebSocket.OPEN;
|
|
949
|
+
}
|
|
950
|
+
__name(isWsStillActive, "isWsStillActive");
|
|
951
|
+
function getWsProbeTimeoutMs($asai) {
|
|
952
|
+
return $asai?.hostconfig?.tm?.d || 3e3;
|
|
953
|
+
}
|
|
954
|
+
__name(getWsProbeTimeoutMs, "getWsProbeTimeoutMs");
|
|
955
|
+
function probeWsAlive($asai, wsclient, timeoutMs) {
|
|
956
|
+
const waitMs = timeoutMs ?? getWsProbeTimeoutMs($asai);
|
|
957
|
+
return new Promise((resolve6) => {
|
|
958
|
+
if (!wsclient || !isWsStillActive(wsclient)) {
|
|
959
|
+
resolve6(false);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
let settled = false;
|
|
963
|
+
const finish = /* @__PURE__ */ __name((alive) => {
|
|
964
|
+
if (settled) return;
|
|
965
|
+
settled = true;
|
|
966
|
+
clearTimeout(timer);
|
|
967
|
+
try {
|
|
968
|
+
wsclient.off?.("message", onMessage);
|
|
969
|
+
} catch {
|
|
970
|
+
}
|
|
971
|
+
resolve6(alive);
|
|
972
|
+
}, "finish");
|
|
973
|
+
const onMessage = /* @__PURE__ */ __name(() => finish(true), "onMessage");
|
|
974
|
+
const timer = setTimeout(() => finish(false), waitMs);
|
|
975
|
+
try {
|
|
976
|
+
wsclient.once?.("message", onMessage);
|
|
977
|
+
wsclient.send(JSON.stringify({ ty: "publish/web", db: "pong" }));
|
|
978
|
+
} catch {
|
|
979
|
+
finish(false);
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
__name(probeWsAlive, "probeWsAlive");
|
|
984
|
+
function terminateWs(wsclient) {
|
|
985
|
+
if (!wsclient) return;
|
|
986
|
+
try {
|
|
987
|
+
wsclient.terminate?.();
|
|
988
|
+
} catch {
|
|
989
|
+
}
|
|
990
|
+
try {
|
|
991
|
+
wsclient.close?.();
|
|
992
|
+
} catch {
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
__name(terminateWs, "terminateWs");
|
|
996
|
+
async function clearStaleWsIfDead($asai, hostdir, us, existingWs) {
|
|
997
|
+
if (!us || us === "asai") return true;
|
|
998
|
+
const map = $asai.connectionsws?.[hostdir];
|
|
999
|
+
if (!existingWs) {
|
|
1000
|
+
if (map?.[us]) delete map[us];
|
|
1001
|
+
return true;
|
|
1002
|
+
}
|
|
1003
|
+
if (!isWsStillActive(existingWs)) {
|
|
1004
|
+
terminateWs(existingWs);
|
|
1005
|
+
if (map?.[us] === existingWs) delete map[us];
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
1008
|
+
const alive = await probeWsAlive($asai, existingWs);
|
|
1009
|
+
if (alive) return false;
|
|
1010
|
+
terminateWs(existingWs);
|
|
1011
|
+
if (map?.[us] === existingWs) delete map[us];
|
|
1012
|
+
return true;
|
|
1013
|
+
}
|
|
1014
|
+
__name(clearStaleWsIfDead, "clearStaleWsIfDead");
|
|
1015
|
+
|
|
943
1016
|
// src/ws/auth.ts
|
|
944
1017
|
function getWsUserinfo(req, $asai) {
|
|
945
1018
|
try {
|
|
@@ -1006,12 +1079,6 @@ async function removeSessionOnWsClose($asai, us, token) {
|
|
|
1006
1079
|
}
|
|
1007
1080
|
}
|
|
1008
1081
|
__name(removeSessionOnWsClose, "removeSessionOnWsClose");
|
|
1009
|
-
function isWsStillActive(ws2) {
|
|
1010
|
-
if (!ws2) return false;
|
|
1011
|
-
const state = ws2.readyState;
|
|
1012
|
-
return state === WebSocket.CONNECTING || state === WebSocket.OPEN;
|
|
1013
|
-
}
|
|
1014
|
-
__name(isWsStillActive, "isWsStillActive");
|
|
1015
1082
|
function rejectIncomingWs(ws2, db) {
|
|
1016
1083
|
const payload = JSON.stringify({ ty: "publish/web", db: { exit: 1, type: "err", ...db } });
|
|
1017
1084
|
try {
|
|
@@ -1029,7 +1096,7 @@ function rejectIncomingWs(ws2, db) {
|
|
|
1029
1096
|
}
|
|
1030
1097
|
}
|
|
1031
1098
|
__name(rejectIncomingWs, "rejectIncomingWs");
|
|
1032
|
-
function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
|
|
1099
|
+
async function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
|
|
1033
1100
|
const [us, , tk] = ws2.Userinfo || [];
|
|
1034
1101
|
if (!us) {
|
|
1035
1102
|
ws2.close();
|
|
@@ -1053,12 +1120,16 @@ function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
|
|
|
1053
1120
|
delete $asai.connectionsws[hostdir][us];
|
|
1054
1121
|
return true;
|
|
1055
1122
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1123
|
+
const cleared = await clearStaleWsIfDead($asai, hostdir, us, existingWs);
|
|
1124
|
+
if (!cleared) {
|
|
1125
|
+
rejectIncomingWs(ws2, {
|
|
1126
|
+
lang: "logged",
|
|
1127
|
+
langpm: `${us}`,
|
|
1128
|
+
con: `${us} logged in!`
|
|
1129
|
+
});
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|
|
1132
|
+
return true;
|
|
1062
1133
|
}
|
|
1063
1134
|
if (us !== "asai") {
|
|
1064
1135
|
const connections = $asai.connectionsws[hostdir] || {};
|
|
@@ -1109,13 +1180,13 @@ function loginWs($asai, hostdir, ws2, req, hostcfg, wsWorkHandler, logWsMessage)
|
|
|
1109
1180
|
if (us && token && !isUserOnlineOnWs($asai, us, hostdir)) {
|
|
1110
1181
|
void removeSessionOnWsClose($asai, us, String(token));
|
|
1111
1182
|
}
|
|
1112
|
-
if (ws2.readyState !==
|
|
1183
|
+
if (ws2.readyState !== WebSocket2.CLOSED && ws2.readyState !== WebSocket2.CLOSING) ws2.close();
|
|
1113
1184
|
});
|
|
1114
1185
|
}
|
|
1115
1186
|
__name(loginWs, "loginWs");
|
|
1116
1187
|
|
|
1117
1188
|
// src/ws/message.ts
|
|
1118
|
-
import { WebSocket as
|
|
1189
|
+
import { WebSocket as WebSocket3 } from "ws";
|
|
1119
1190
|
function clearWsServerTasks($asai, hostdir) {
|
|
1120
1191
|
const tasks = $asai.tasksws[hostdir];
|
|
1121
1192
|
if (tasks && typeof tasks === "object") {
|
|
@@ -1140,7 +1211,7 @@ function attachWssHelpers(wss, $asai) {
|
|
|
1140
1211
|
const data = resWsMsg(msg, $asai);
|
|
1141
1212
|
if (type) {
|
|
1142
1213
|
wss.clients.forEach((client) => {
|
|
1143
|
-
if ((type === 2 || client !== curws) && client.readyState ===
|
|
1214
|
+
if ((type === 2 || client !== curws) && client.readyState === WebSocket3.OPEN) {
|
|
1144
1215
|
client.send(data);
|
|
1145
1216
|
}
|
|
1146
1217
|
});
|
|
@@ -1151,7 +1222,7 @@ function attachWssHelpers(wss, $asai) {
|
|
|
1151
1222
|
wss.broadws = (msg) => {
|
|
1152
1223
|
const data = resWsMsg(msg, $asai);
|
|
1153
1224
|
wss.clients.forEach((client) => {
|
|
1154
|
-
if (client?.readyState ===
|
|
1225
|
+
if (client?.readyState === WebSocket3.OPEN) client.send(data);
|
|
1155
1226
|
});
|
|
1156
1227
|
};
|
|
1157
1228
|
}
|
|
@@ -1331,12 +1402,14 @@ function createWSHost($asai, hostdir) {
|
|
|
1331
1402
|
ws2.send(wsmsg, () => ws2.close(1013, "Server busy"));
|
|
1332
1403
|
return;
|
|
1333
1404
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1405
|
+
void (async () => {
|
|
1406
|
+
const isOpen = !hostcfg.ckws || await isOkWs($asai, hostdir, ws2, req, hostcfg);
|
|
1407
|
+
if (isOpen) {
|
|
1408
|
+
loginWs($asai, hostdir, ws2, req, hostcfg, wsWorkHandler, logWsMessage);
|
|
1409
|
+
} else {
|
|
1410
|
+
ws2.close();
|
|
1411
|
+
}
|
|
1412
|
+
})();
|
|
1340
1413
|
});
|
|
1341
1414
|
$asai.serversws[hostdir] = wss;
|
|
1342
1415
|
} catch (err) {
|
|
@@ -1460,11 +1533,11 @@ function createSkipChecker($asai) {
|
|
|
1460
1533
|
}
|
|
1461
1534
|
if (exact.size === 0 && prefixes.length === 0) return () => false;
|
|
1462
1535
|
return (url) => {
|
|
1463
|
-
const
|
|
1464
|
-
if (!
|
|
1465
|
-
if (exact.has(
|
|
1536
|
+
const path8 = normalizeRequestPath(url);
|
|
1537
|
+
if (!path8) return false;
|
|
1538
|
+
if (exact.has(path8)) return true;
|
|
1466
1539
|
for (let i = 0; i < prefixes.length; i++) {
|
|
1467
|
-
if (
|
|
1540
|
+
if (path8.startsWith(prefixes[i])) return true;
|
|
1468
1541
|
}
|
|
1469
1542
|
return false;
|
|
1470
1543
|
};
|
|
@@ -2382,11 +2455,11 @@ function getSecurityConfig($asai) {
|
|
|
2382
2455
|
return $asai?.hostconfig?.security || {};
|
|
2383
2456
|
}
|
|
2384
2457
|
__name(getSecurityConfig, "getSecurityConfig");
|
|
2385
|
-
function pathMatchesPattern(
|
|
2458
|
+
function pathMatchesPattern(path8, pattern) {
|
|
2386
2459
|
if (pattern.endsWith("*")) {
|
|
2387
|
-
return
|
|
2460
|
+
return path8.startsWith(pattern.slice(0, -1));
|
|
2388
2461
|
}
|
|
2389
|
-
return
|
|
2462
|
+
return path8 === pattern;
|
|
2390
2463
|
}
|
|
2391
2464
|
__name(pathMatchesPattern, "pathMatchesPattern");
|
|
2392
2465
|
function isAuthSkipped($asai, pathname) {
|
|
@@ -2535,7 +2608,7 @@ __name(isApiCorsAllowed, "isApiCorsAllowed");
|
|
|
2535
2608
|
|
|
2536
2609
|
// src/common/server/Api.ts
|
|
2537
2610
|
function readRequestBody(req, maxBody) {
|
|
2538
|
-
return new Promise((
|
|
2611
|
+
return new Promise((resolve6, reject) => {
|
|
2539
2612
|
const chunks = [];
|
|
2540
2613
|
let received = 0;
|
|
2541
2614
|
let settled = false;
|
|
@@ -2543,7 +2616,7 @@ function readRequestBody(req, maxBody) {
|
|
|
2543
2616
|
if (settled) return;
|
|
2544
2617
|
settled = true;
|
|
2545
2618
|
if (err) reject(err);
|
|
2546
|
-
else
|
|
2619
|
+
else resolve6(data ?? "");
|
|
2547
2620
|
}, "finish");
|
|
2548
2621
|
req.on("data", (chunk) => {
|
|
2549
2622
|
if (settled) return;
|
|
@@ -2673,83 +2746,95 @@ var Api_default = /* @__PURE__ */ __name(($asai, opt = {}) => {
|
|
|
2673
2746
|
const isTextPost = req.method === "POST" && req.url.indexOf("binary") === -1;
|
|
2674
2747
|
const bodyPromise = isTextPost ? readRequestBody(req, maxBody) : null;
|
|
2675
2748
|
void (async () => {
|
|
2676
|
-
let authResult;
|
|
2677
|
-
let rawBody = "";
|
|
2678
2749
|
try {
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
if (!authResult.ok) {
|
|
2691
|
-
releaseSlot();
|
|
2692
|
-
return sendAuthError(res, authResult);
|
|
2693
|
-
}
|
|
2694
|
-
let apiFn = $asai.hostserverapi[apiHandlerKey]?.($asai, query);
|
|
2695
|
-
if (!apiFn) {
|
|
2696
|
-
return sendError(res, 501, "Not Implemented");
|
|
2697
|
-
}
|
|
2698
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
2699
|
-
$asai.$log("API", req.method, urlParse.pathname, query);
|
|
2700
|
-
let qrdata;
|
|
2701
|
-
let postdata;
|
|
2702
|
-
if (req.url.indexOf("binary") === -1) {
|
|
2703
|
-
qrdata = query;
|
|
2704
|
-
if (req.method === "POST") {
|
|
2705
|
-
try {
|
|
2706
|
-
const processed = processPostPayload($asai, req, rawBody, pm);
|
|
2707
|
-
postdata = processed.postdata;
|
|
2708
|
-
pm = processed.pm;
|
|
2709
|
-
isAes = processed.isAes;
|
|
2710
|
-
} catch {
|
|
2711
|
-
return sendError(res, 400, "AES decrypt failed");
|
|
2712
|
-
}
|
|
2713
|
-
if (apiFn?.post && typeof apiFn?.post === "function") {
|
|
2714
|
-
const optTmp = { qrdata, data: postdata, pm };
|
|
2715
|
-
if (isAes || $asai.$lib.aesfns?.allaes) {
|
|
2716
|
-
optTmp.resAES = $asai.$lib.aesfns?.resAES;
|
|
2717
|
-
}
|
|
2718
|
-
apiFn.post(req, res, hostdir, optTmp);
|
|
2719
|
-
} else {
|
|
2720
|
-
res.end(typeof postdata === "string" ? postdata : JSON.stringify(postdata ?? ""));
|
|
2721
|
-
}
|
|
2722
|
-
} else if (req.method === "GET") {
|
|
2723
|
-
if (apiFn?.get && typeof apiFn?.get === "function") {
|
|
2724
|
-
const optTmp = { qrdata, data: qrdata, pm };
|
|
2725
|
-
if (isAes || $asai.$lib.aesfns?.allaes) {
|
|
2726
|
-
optTmp.resAES = $asai.$lib.aesfns?.resAES;
|
|
2727
|
-
}
|
|
2728
|
-
apiFn.get(req, res, hostdir, optTmp);
|
|
2729
|
-
} else {
|
|
2730
|
-
res.end(JSON.stringify(qrdata));
|
|
2750
|
+
let authResult;
|
|
2751
|
+
let rawBody = "";
|
|
2752
|
+
try {
|
|
2753
|
+
[authResult, rawBody] = await Promise.all([
|
|
2754
|
+
validateHttpAuthAsync(req, $asai, pathname),
|
|
2755
|
+
bodyPromise ?? Promise.resolve("")
|
|
2756
|
+
]);
|
|
2757
|
+
} catch (err) {
|
|
2758
|
+
releaseSlot();
|
|
2759
|
+
if (err?.message === "PAYLOAD_TOO_LARGE") {
|
|
2760
|
+
return sendError(res, 413, "Payload Too Large");
|
|
2731
2761
|
}
|
|
2762
|
+
return sendError(res, 400, err?.message || "Bad Request");
|
|
2732
2763
|
}
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2764
|
+
if (!authResult.ok) {
|
|
2765
|
+
releaseSlot();
|
|
2766
|
+
return sendAuthError(res, authResult);
|
|
2736
2767
|
}
|
|
2737
|
-
|
|
2738
|
-
|
|
2768
|
+
let apiFn = $asai.hostserverapi[apiHandlerKey]?.($asai, query);
|
|
2769
|
+
if (!apiFn) {
|
|
2770
|
+
return sendError(res, 501, "Not Implemented");
|
|
2771
|
+
}
|
|
2772
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
2773
|
+
$asai.$log("API", req.method, urlParse.pathname, query);
|
|
2774
|
+
let qrdata;
|
|
2775
|
+
let postdata;
|
|
2776
|
+
if (req.url.indexOf("binary") === -1) {
|
|
2777
|
+
qrdata = query;
|
|
2778
|
+
if (req.method === "POST") {
|
|
2779
|
+
try {
|
|
2780
|
+
const processed = processPostPayload($asai, req, rawBody, pm);
|
|
2781
|
+
postdata = processed.postdata;
|
|
2782
|
+
pm = processed.pm;
|
|
2783
|
+
isAes = processed.isAes;
|
|
2784
|
+
} catch {
|
|
2785
|
+
return sendError(res, 400, "AES decrypt failed");
|
|
2786
|
+
}
|
|
2739
2787
|
if (apiFn?.post && typeof apiFn?.post === "function") {
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
}
|
|
2788
|
+
const optTmp = { qrdata, data: postdata, pm };
|
|
2789
|
+
if (isAes || $asai.$lib.aesfns?.allaes) {
|
|
2790
|
+
optTmp.resAES = $asai.$lib.aesfns?.resAES;
|
|
2791
|
+
}
|
|
2792
|
+
apiFn.post(req, res, hostdir, optTmp);
|
|
2744
2793
|
} else {
|
|
2745
|
-
res.end(
|
|
2794
|
+
res.end(typeof postdata === "string" ? postdata : JSON.stringify(postdata ?? ""));
|
|
2746
2795
|
}
|
|
2747
|
-
}
|
|
2748
|
-
|
|
2749
|
-
|
|
2796
|
+
} else if (req.method === "GET") {
|
|
2797
|
+
if (apiFn?.get && typeof apiFn?.get === "function") {
|
|
2798
|
+
const optTmp = { qrdata, data: qrdata, pm };
|
|
2799
|
+
if (isAes || $asai.$lib.aesfns?.allaes) {
|
|
2800
|
+
optTmp.resAES = $asai.$lib.aesfns?.resAES;
|
|
2801
|
+
}
|
|
2802
|
+
apiFn.get(req, res, hostdir, optTmp);
|
|
2803
|
+
} else {
|
|
2804
|
+
res.end(JSON.stringify(qrdata));
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
} else {
|
|
2808
|
+
if (Object.keys(query)?.length) {
|
|
2809
|
+
qrdata = query;
|
|
2810
|
+
}
|
|
2811
|
+
if (req.method === "POST") {
|
|
2812
|
+
$asai.$lib.AsNodeTool.upBinary(req).then((postdata2) => {
|
|
2813
|
+
if (apiFn?.post && typeof apiFn?.post === "function") {
|
|
2814
|
+
apiFn.post(req, res, hostdir, {
|
|
2815
|
+
qrdata,
|
|
2816
|
+
data: postdata2
|
|
2817
|
+
});
|
|
2818
|
+
} else {
|
|
2819
|
+
res.end(postdata2);
|
|
2820
|
+
}
|
|
2821
|
+
}).catch((err) => {
|
|
2822
|
+
return sendError(res, 400, "Invalid content type");
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
} catch (err) {
|
|
2827
|
+
releaseSlot();
|
|
2828
|
+
if (!res.headersSent) {
|
|
2829
|
+
return sendError(res, 500, err?.message || "Internal Server Error");
|
|
2750
2830
|
}
|
|
2751
2831
|
}
|
|
2752
|
-
})()
|
|
2832
|
+
})().catch((err) => {
|
|
2833
|
+
releaseSlot();
|
|
2834
|
+
if (!res.headersSent) {
|
|
2835
|
+
sendError(res, 500, err?.message || "Internal Server Error");
|
|
2836
|
+
}
|
|
2837
|
+
});
|
|
2753
2838
|
} else {
|
|
2754
2839
|
$asai.$log("API", req.method, req.url);
|
|
2755
2840
|
}
|
|
@@ -2883,27 +2968,28 @@ var Sys_default = /* @__PURE__ */ __name(($asai, opt = {}) => {
|
|
|
2883
2968
|
}
|
|
2884
2969
|
const urlPath = (req.url || "").split("?")[0];
|
|
2885
2970
|
void (async () => {
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
handler
|
|
2896
|
-
|
|
2897
|
-
|
|
2971
|
+
try {
|
|
2972
|
+
const authResult = await validateHttpAuthAsync(req, $asai, urlPath);
|
|
2973
|
+
if (!authResult.ok) {
|
|
2974
|
+
return sendAuthError(res, authResult);
|
|
2975
|
+
}
|
|
2976
|
+
const handler = $asai.hostserversys[handlerKey]?.($asai);
|
|
2977
|
+
if (!handler) {
|
|
2978
|
+
return sendError(res, 500, "Handler Initialization Failed");
|
|
2979
|
+
}
|
|
2980
|
+
if (handler?.show && typeof handler?.show === "function") {
|
|
2981
|
+
handler.show(req, res, hostdir);
|
|
2982
|
+
} else {
|
|
2983
|
+
res.end("postdata");
|
|
2984
|
+
}
|
|
2985
|
+
} catch (err) {
|
|
2986
|
+
return sendError(res, 500, err?.message || "Internal Server Error");
|
|
2898
2987
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
});
|
|
2903
|
-
res.end(req.url);
|
|
2904
|
-
} else {
|
|
2988
|
+
})().catch((err) => {
|
|
2989
|
+
if (!res.headersSent) {
|
|
2990
|
+
sendError(res, 500, err?.message || "Internal Server Error");
|
|
2905
2991
|
}
|
|
2906
|
-
})
|
|
2992
|
+
});
|
|
2907
2993
|
}
|
|
2908
2994
|
__name(sysWork, "sysWork");
|
|
2909
2995
|
return { sysWork };
|
|
@@ -2922,7 +3008,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
|
|
|
2922
3008
|
}
|
|
2923
3009
|
__name(getKeyByData, "getKeyByData");
|
|
2924
3010
|
function clientwsInit() {
|
|
2925
|
-
return new Promise((
|
|
3011
|
+
return new Promise((resolve6, reject) => {
|
|
2926
3012
|
$asai.clientws[wsname].socket = new $asai.asaiWs(
|
|
2927
3013
|
$asai.command.commandconfig.clientws[wsname]
|
|
2928
3014
|
);
|
|
@@ -2952,7 +3038,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
|
|
|
2952
3038
|
`${wsname}=${$asai.command.commandconfig.clientws[wsname]} is open.`
|
|
2953
3039
|
);
|
|
2954
3040
|
$asai.clientws[wsname].open = 1;
|
|
2955
|
-
|
|
3041
|
+
resolve6();
|
|
2956
3042
|
};
|
|
2957
3043
|
});
|
|
2958
3044
|
}
|
|
@@ -2982,7 +3068,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
|
|
|
2982
3068
|
}
|
|
2983
3069
|
__name(clientwsOnmessage, "clientwsOnmessage");
|
|
2984
3070
|
function clientwsApi(messageData) {
|
|
2985
|
-
return new Promise((
|
|
3071
|
+
return new Promise((resolve6, reject) => {
|
|
2986
3072
|
if ($asai.clientws[wsname].open) {
|
|
2987
3073
|
try {
|
|
2988
3074
|
const taskOpt = {};
|
|
@@ -2994,7 +3080,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
|
|
|
2994
3080
|
getKeyByData(messageData),
|
|
2995
3081
|
{
|
|
2996
3082
|
callback: /* @__PURE__ */ __name((res) => {
|
|
2997
|
-
|
|
3083
|
+
resolve6(res);
|
|
2998
3084
|
}, "callback"),
|
|
2999
3085
|
...messageData,
|
|
3000
3086
|
...taskOpt
|
|
@@ -4140,8 +4226,14 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
|
|
|
4140
4226
|
const policy = getPasswordPolicy($asai);
|
|
4141
4227
|
const mustChange = !!user.mustChangePassword || isPasswordExpired(user.passwordChangedAt, policy.maxAgeDays);
|
|
4142
4228
|
const hostcfg = $asai.getHost?.(hostdir) || {};
|
|
4143
|
-
if (hostcfg.ckws
|
|
4144
|
-
|
|
4229
|
+
if (hostcfg.ckws) {
|
|
4230
|
+
const existingWs = $asai.connectionsws?.[hostdir]?.[us];
|
|
4231
|
+
if (existingWs) {
|
|
4232
|
+
const cleared = await clearStaleWsIfDead($asai, hostdir, us, existingWs);
|
|
4233
|
+
if (!cleared) {
|
|
4234
|
+
kickUserWs($asai, us, hostdir);
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4145
4237
|
}
|
|
4146
4238
|
const quotaCheck = await canLogin($asai, us, hostdir);
|
|
4147
4239
|
if (!quotaCheck.ok) {
|
|
@@ -4543,10 +4635,10 @@ var As_default = {
|
|
|
4543
4635
|
return absPath;
|
|
4544
4636
|
},
|
|
4545
4637
|
makeDir(fs11, filePaths) {
|
|
4546
|
-
return new Promise((
|
|
4638
|
+
return new Promise((resolve6, reject) => {
|
|
4547
4639
|
try {
|
|
4548
4640
|
const newPath = this.ensureDir(fs11, filePaths);
|
|
4549
|
-
|
|
4641
|
+
resolve6(newPath);
|
|
4550
4642
|
} catch (err) {
|
|
4551
4643
|
reject(err);
|
|
4552
4644
|
}
|
|
@@ -5142,6 +5234,7 @@ var AsDb_default = /* @__PURE__ */ __name(($asai, cfg) => {
|
|
|
5142
5234
|
}, "default");
|
|
5143
5235
|
|
|
5144
5236
|
// src/sysserver/lib/common/reqWork.ts
|
|
5237
|
+
import * as path4 from "path";
|
|
5145
5238
|
var reqWork_default = /* @__PURE__ */ __name(($asai) => {
|
|
5146
5239
|
function hostDefault2(mod) {
|
|
5147
5240
|
if (mod && typeof mod === "object" && "default" in mod) {
|
|
@@ -5157,6 +5250,19 @@ var reqWork_default = /* @__PURE__ */ __name(($asai) => {
|
|
|
5157
5250
|
throw new Error("Missing path");
|
|
5158
5251
|
}
|
|
5159
5252
|
const decoded = decodeURIComponent(String(rawPath));
|
|
5253
|
+
if (path4.isAbsolute(decoded)) {
|
|
5254
|
+
return path4.normalize(decoded);
|
|
5255
|
+
}
|
|
5256
|
+
const rel = decoded.replace(/^\.(\/)?/, "");
|
|
5257
|
+
const serverRoot = $asai?.serverRoot;
|
|
5258
|
+
if (serverRoot && rel) {
|
|
5259
|
+
const absRoot = path4.resolve(serverRoot);
|
|
5260
|
+
const abs = path4.resolve(absRoot, rel);
|
|
5261
|
+
const relCheck = path4.relative(absRoot, abs);
|
|
5262
|
+
if (relCheck === "" || !relCheck.startsWith("..") && !path4.isAbsolute(relCheck)) {
|
|
5263
|
+
return abs;
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5160
5266
|
const roots = $asai?.asaihost?.getHostAllowedRoots?.($asai?.hostconfig) || [];
|
|
5161
5267
|
if (!roots.length) {
|
|
5162
5268
|
const fallback = $asai?.serverRoot || process.cwd();
|
|
@@ -5214,17 +5320,17 @@ __export(AsFs_exports, {
|
|
|
5214
5320
|
writeJson: () => writeJson
|
|
5215
5321
|
});
|
|
5216
5322
|
import fs9 from "fs/promises";
|
|
5217
|
-
import
|
|
5323
|
+
import path5 from "path";
|
|
5218
5324
|
async function ensureFile(filePath) {
|
|
5219
|
-
const normalized =
|
|
5220
|
-
await fs9.mkdir(
|
|
5325
|
+
const normalized = path5.normalize(filePath);
|
|
5326
|
+
await fs9.mkdir(path5.dirname(normalized), { recursive: true });
|
|
5221
5327
|
const fh = await fs9.open(normalized, "a");
|
|
5222
5328
|
await fh.close();
|
|
5223
5329
|
}
|
|
5224
5330
|
__name(ensureFile, "ensureFile");
|
|
5225
5331
|
async function pathExists(filePath) {
|
|
5226
5332
|
try {
|
|
5227
|
-
await fs9.access(
|
|
5333
|
+
await fs9.access(path5.normalize(filePath));
|
|
5228
5334
|
return true;
|
|
5229
5335
|
} catch {
|
|
5230
5336
|
return false;
|
|
@@ -5232,7 +5338,7 @@ async function pathExists(filePath) {
|
|
|
5232
5338
|
}
|
|
5233
5339
|
__name(pathExists, "pathExists");
|
|
5234
5340
|
async function readJson(filePath) {
|
|
5235
|
-
const raw = await fs9.readFile(
|
|
5341
|
+
const raw = await fs9.readFile(path5.normalize(filePath), "utf8");
|
|
5236
5342
|
return JSON.parse(raw);
|
|
5237
5343
|
}
|
|
5238
5344
|
__name(readJson, "readJson");
|
|
@@ -5243,26 +5349,26 @@ function resolvePathUnderBase(baseDir, relPath) {
|
|
|
5243
5349
|
if (relPath.includes("\0")) {
|
|
5244
5350
|
throw new Error("Invalid path");
|
|
5245
5351
|
}
|
|
5246
|
-
const base =
|
|
5247
|
-
const target =
|
|
5248
|
-
const rel =
|
|
5249
|
-
if (rel.startsWith("..") ||
|
|
5352
|
+
const base = path5.resolve(baseDir);
|
|
5353
|
+
const target = path5.resolve(base, relPath.replace(/\\/g, "/"));
|
|
5354
|
+
const rel = path5.relative(base, target);
|
|
5355
|
+
if (rel.startsWith("..") || path5.isAbsolute(rel)) {
|
|
5250
5356
|
throw new Error("Path not allowed");
|
|
5251
5357
|
}
|
|
5252
5358
|
return target;
|
|
5253
5359
|
}
|
|
5254
5360
|
__name(resolvePathUnderBase, "resolvePathUnderBase");
|
|
5255
5361
|
async function readLogDir(dir) {
|
|
5256
|
-
const resolved =
|
|
5362
|
+
const resolved = path5.resolve(dir);
|
|
5257
5363
|
const stats = await fs9.stat(resolved);
|
|
5258
5364
|
if (!stats.isDirectory()) {
|
|
5259
5365
|
throw new Error("Not a directory");
|
|
5260
5366
|
}
|
|
5261
|
-
const dirName =
|
|
5367
|
+
const dirName = path5.basename(resolved);
|
|
5262
5368
|
const entries = await fs9.readdir(resolved, { withFileTypes: true });
|
|
5263
5369
|
const children = await Promise.all(
|
|
5264
5370
|
entries.map(async (entry) => {
|
|
5265
|
-
const fullPath =
|
|
5371
|
+
const fullPath = path5.join(resolved, entry.name);
|
|
5266
5372
|
const st = await fs9.stat(fullPath);
|
|
5267
5373
|
const dot = entry.name.lastIndexOf(".");
|
|
5268
5374
|
const type = entry.isDirectory() ? "dir" : dot > -1 ? entry.name.substring(dot) : "file";
|
|
@@ -5270,7 +5376,7 @@ async function readLogDir(dir) {
|
|
|
5270
5376
|
name: entry.name,
|
|
5271
5377
|
size: st.size,
|
|
5272
5378
|
time: st.mtime.toISOString(),
|
|
5273
|
-
path:
|
|
5379
|
+
path: path5.normalize(fullPath),
|
|
5274
5380
|
type,
|
|
5275
5381
|
created: st.birthtime.toISOString(),
|
|
5276
5382
|
permissions: st.mode.toString(8).slice(-3)
|
|
@@ -5281,7 +5387,7 @@ async function readLogDir(dir) {
|
|
|
5281
5387
|
name: dirName,
|
|
5282
5388
|
size: stats.size,
|
|
5283
5389
|
time: stats.mtime.toISOString(),
|
|
5284
|
-
path:
|
|
5390
|
+
path: path5.normalize(resolved),
|
|
5285
5391
|
type: "dir",
|
|
5286
5392
|
created: stats.birthtime.toISOString(),
|
|
5287
5393
|
permissions: stats.mode.toString(8).slice(-3),
|
|
@@ -5291,7 +5397,7 @@ async function readLogDir(dir) {
|
|
|
5291
5397
|
__name(readLogDir, "readLogDir");
|
|
5292
5398
|
async function removeFile(filePath) {
|
|
5293
5399
|
try {
|
|
5294
|
-
await fs9.unlink(
|
|
5400
|
+
await fs9.unlink(path5.normalize(filePath));
|
|
5295
5401
|
} catch (err) {
|
|
5296
5402
|
if (err?.code !== "ENOENT") throw err;
|
|
5297
5403
|
}
|
|
@@ -5299,13 +5405,13 @@ async function removeFile(filePath) {
|
|
|
5299
5405
|
__name(removeFile, "removeFile");
|
|
5300
5406
|
var remove = removeFile;
|
|
5301
5407
|
async function write(filePath, content) {
|
|
5302
|
-
const normalized =
|
|
5303
|
-
await fs9.mkdir(
|
|
5408
|
+
const normalized = path5.normalize(filePath);
|
|
5409
|
+
await fs9.mkdir(path5.dirname(normalized), { recursive: true });
|
|
5304
5410
|
await fs9.writeFile(normalized, content, "utf8");
|
|
5305
5411
|
}
|
|
5306
5412
|
__name(write, "write");
|
|
5307
5413
|
async function read(filePath) {
|
|
5308
|
-
return fs9.readFile(
|
|
5414
|
+
return fs9.readFile(path5.normalize(filePath), "utf8");
|
|
5309
5415
|
}
|
|
5310
5416
|
__name(read, "read");
|
|
5311
5417
|
async function writeJson(filePath, data) {
|
|
@@ -5341,19 +5447,19 @@ __export(common_exports, {
|
|
|
5341
5447
|
toSetObject: () => toSetObject,
|
|
5342
5448
|
toWherePairs: () => toWherePairs
|
|
5343
5449
|
});
|
|
5344
|
-
import * as
|
|
5450
|
+
import * as path6 from "path";
|
|
5345
5451
|
function promisifySqlDb(query, sql) {
|
|
5346
|
-
return new Promise((
|
|
5452
|
+
return new Promise((resolve6, reject) => {
|
|
5347
5453
|
query(sql, (err, result) => {
|
|
5348
5454
|
if (err) {
|
|
5349
5455
|
reject(err);
|
|
5350
5456
|
return;
|
|
5351
5457
|
}
|
|
5352
5458
|
if (!result || Array.isArray(result) && result.length === 0) {
|
|
5353
|
-
|
|
5459
|
+
resolve6("");
|
|
5354
5460
|
return;
|
|
5355
5461
|
}
|
|
5356
|
-
|
|
5462
|
+
resolve6(result);
|
|
5357
5463
|
});
|
|
5358
5464
|
});
|
|
5359
5465
|
}
|
|
@@ -5406,11 +5512,11 @@ function toInsertRows(sql) {
|
|
|
5406
5512
|
}
|
|
5407
5513
|
__name(toInsertRows, "toInsertRows");
|
|
5408
5514
|
function isPathInside(baseDir, targetPath) {
|
|
5409
|
-
const base =
|
|
5410
|
-
const target =
|
|
5411
|
-
const
|
|
5412
|
-
if (!
|
|
5413
|
-
return !
|
|
5515
|
+
const base = path6.resolve(baseDir);
|
|
5516
|
+
const target = path6.resolve(targetPath);
|
|
5517
|
+
const relative5 = path6.relative(base, target);
|
|
5518
|
+
if (!relative5) return true;
|
|
5519
|
+
return !relative5.startsWith("..") && !path6.isAbsolute(relative5);
|
|
5414
5520
|
}
|
|
5415
5521
|
__name(isPathInside, "isPathInside");
|
|
5416
5522
|
function joinTablePath(table, ...segments) {
|
|
@@ -5592,7 +5698,7 @@ var Sql_default = {
|
|
|
5592
5698
|
|
|
5593
5699
|
// src/sysserver/db/src/file/Index.ts
|
|
5594
5700
|
import * as fs10 from "fs";
|
|
5595
|
-
import * as
|
|
5701
|
+
import * as path7 from "path";
|
|
5596
5702
|
function dbDriver(opt = {}) {
|
|
5597
5703
|
const { Sql, DbCommon } = opt;
|
|
5598
5704
|
const { isPathInside: isPathInside2, joinTablePath: joinTablePath2 } = DbCommon;
|
|
@@ -5606,7 +5712,7 @@ function dbDriver(opt = {}) {
|
|
|
5606
5712
|
this.fileDel = (config.del || 0) !== 0;
|
|
5607
5713
|
this.createDir = config.create || false;
|
|
5608
5714
|
const root = config.$asai?.serverRoot || getPrimaryServerRoot();
|
|
5609
|
-
this.baseDirAbs =
|
|
5715
|
+
this.baseDirAbs = path7.resolve(root, config.dir);
|
|
5610
5716
|
}
|
|
5611
5717
|
dbLog(...args) {
|
|
5612
5718
|
(this.config?.$asai?.$log || console.log)("FILE", ...args);
|
|
@@ -5619,9 +5725,9 @@ function dbDriver(opt = {}) {
|
|
|
5619
5725
|
if (!relPath) {
|
|
5620
5726
|
return this.baseDirAbs;
|
|
5621
5727
|
}
|
|
5622
|
-
const abs =
|
|
5728
|
+
const abs = path7.isAbsolute(relPath) ? path7.normalize(relPath) : path7.resolve(this.baseDirAbs, relPath);
|
|
5623
5729
|
if (!isPathInside2(this.baseDirAbs, abs)) {
|
|
5624
|
-
|
|
5730
|
+
throw new Error("Path not allowed");
|
|
5625
5731
|
}
|
|
5626
5732
|
return abs;
|
|
5627
5733
|
}
|
|
@@ -5633,11 +5739,11 @@ function dbDriver(opt = {}) {
|
|
|
5633
5739
|
if (!relPath) {
|
|
5634
5740
|
return "";
|
|
5635
5741
|
}
|
|
5636
|
-
return
|
|
5742
|
+
return path7.isAbsolute(relPath) ? path7.relative(this.baseDirAbs, relPath) : relPath;
|
|
5637
5743
|
}
|
|
5638
5744
|
ensureDir(relPath) {
|
|
5639
|
-
const
|
|
5640
|
-
const dirPath =
|
|
5745
|
+
const relative5 = this.normalizeRelPath(relPath);
|
|
5746
|
+
const dirPath = path7.dirname(relative5);
|
|
5641
5747
|
const absDir = this.resolvePath(dirPath === "." ? "" : dirPath);
|
|
5642
5748
|
if (this.createDir && !fs10.existsSync(absDir)) {
|
|
5643
5749
|
this.dbLog("mkdir", "[MKDIR]", absDir);
|
|
@@ -5663,9 +5769,9 @@ function dbDriver(opt = {}) {
|
|
|
5663
5769
|
this.dbLog("delete", "[RMDIR]", absPath);
|
|
5664
5770
|
const entries = fs10.readdirSync(absPath, { withFileTypes: true });
|
|
5665
5771
|
for (const entry of entries) {
|
|
5666
|
-
const current =
|
|
5772
|
+
const current = path7.join(absPath, entry.name);
|
|
5667
5773
|
if (entry.isDirectory()) {
|
|
5668
|
-
this.deldir(
|
|
5774
|
+
this.deldir(path7.join(relativePath, entry.name));
|
|
5669
5775
|
} else {
|
|
5670
5776
|
this.dbLog("delete", "[UNLINK]", current);
|
|
5671
5777
|
fs10.unlinkSync(current);
|
|
@@ -5676,8 +5782,8 @@ function dbDriver(opt = {}) {
|
|
|
5676
5782
|
getReadPath(file, sql) {
|
|
5677
5783
|
const candidates = [];
|
|
5678
5784
|
if (sql?.filename) {
|
|
5679
|
-
candidates.push({ dir:
|
|
5680
|
-
candidates.push({ dir:
|
|
5785
|
+
candidates.push({ dir: path7.join(file, sql.filename) });
|
|
5786
|
+
candidates.push({ dir: path7.join(file + ".delete" + this.fileExt, sql.filename) });
|
|
5681
5787
|
} else {
|
|
5682
5788
|
candidates.push({ dir: file });
|
|
5683
5789
|
candidates.push({ dir: file + this.fileExt + ".delete" });
|
|
@@ -5696,13 +5802,13 @@ function dbDriver(opt = {}) {
|
|
|
5696
5802
|
return { path: "", dir: read2.dir };
|
|
5697
5803
|
}
|
|
5698
5804
|
if (sql?.filename) {
|
|
5699
|
-
return { path:
|
|
5805
|
+
return { path: path7.dirname(read2.path), dir: path7.dirname(read2.dir) };
|
|
5700
5806
|
}
|
|
5701
5807
|
return { path: read2.path, dir: read2.dir };
|
|
5702
5808
|
}
|
|
5703
5809
|
getNewPath(file, sql) {
|
|
5704
5810
|
if (sql?.filename) {
|
|
5705
|
-
return this.getAbsPath(
|
|
5811
|
+
return this.getAbsPath(path7.join(file, sql.filename), true);
|
|
5706
5812
|
}
|
|
5707
5813
|
return this.getAbsPath(file, true);
|
|
5708
5814
|
}
|
|
@@ -5795,7 +5901,7 @@ function dbDriver(opt = {}) {
|
|
|
5795
5901
|
const isDelete = fileName.endsWith(deleteSuffix);
|
|
5796
5902
|
const baseName = isDelete ? fileName.slice(0, -deleteSuffix.length) : fileName;
|
|
5797
5903
|
if (this.fileExt && !baseName.endsWith(this.fileExt)) continue;
|
|
5798
|
-
const fullPath =
|
|
5904
|
+
const fullPath = path7.join(absDir, fileName);
|
|
5799
5905
|
try {
|
|
5800
5906
|
const data = fs10.readFileSync(fullPath, "utf8");
|
|
5801
5907
|
const entryData = { data, file: baseName };
|
|
@@ -5824,7 +5930,7 @@ function dbDriver(opt = {}) {
|
|
|
5824
5930
|
return String(raw ?? "");
|
|
5825
5931
|
}
|
|
5826
5932
|
sqlDb(sql) {
|
|
5827
|
-
return new Promise((
|
|
5933
|
+
return new Promise((resolve6, reject) => {
|
|
5828
5934
|
try {
|
|
5829
5935
|
let result;
|
|
5830
5936
|
const tableDir = this.tableFilePath(sql.table);
|
|
@@ -5953,7 +6059,7 @@ function dbDriver(opt = {}) {
|
|
|
5953
6059
|
}
|
|
5954
6060
|
}
|
|
5955
6061
|
if (result !== void 0) {
|
|
5956
|
-
|
|
6062
|
+
resolve6(result);
|
|
5957
6063
|
} else {
|
|
5958
6064
|
reject("");
|
|
5959
6065
|
}
|
|
@@ -6563,7 +6669,7 @@ var initAsaiHostNodejs2 = {
|
|
|
6563
6669
|
createTransportDataHandler,
|
|
6564
6670
|
wireTransportConnectionLogs
|
|
6565
6671
|
};
|
|
6566
|
-
var PLUGIN_VERSION = true ? "0.0.
|
|
6672
|
+
var PLUGIN_VERSION = true ? "0.0.9" : "0.0.1";
|
|
6567
6673
|
var index_default = initAsaiHostNodejs2;
|
|
6568
6674
|
export {
|
|
6569
6675
|
Index_default as AsaiCommon,
|