@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.13 → 0.1.6-BETA.14
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/core.cjs +1638 -1316
- package/package.json +1 -1
- package/ui-react/assets/{InstancesPage-DM0dMQHh.js → InstancesPage-DhR8E6q2.js} +1 -1
- package/ui-react/assets/{LanPage-B5oThF8O.js → LanPage-BymkZ5Lp.js} +1 -1
- package/ui-react/assets/OverviewPage-BwAeZq3_.js +2 -0
- package/ui-react/assets/{PluginsPage-C1llxTDk.js → PluginsPage-D9nLksEp.js} +1 -1
- package/ui-react/assets/{RouterPage-CUKMV2Q9.js → RouterPage-B_dPmJbu.js} +1 -1
- package/ui-react/assets/{SettingsPage-BZG-EvR3.js → SettingsPage-C-iKRaHC.js} +1 -1
- package/ui-react/assets/{TasksPage-haZMZbBh.js → TasksPage-CceWxOiG.js} +1 -1
- package/ui-react/assets/openExternal-RPwenHBw.js +1 -0
- package/ui-react/assets/{refresh-cw-B-VAKpDt.js → refresh-cw-qHR0pOo6.js} +1 -1
- package/ui-react/assets/{rocket-CLAmwatt.js → rocket-qAs1Npqn.js} +1 -1
- package/ui-react/assets/{shield-check-CMRwmPpk.js → shield-check-DdnUZAa0.js} +1 -1
- package/ui-react/assets/{supervisor-BCZW2z-5.js → supervisor-Af5v0BTw.js} +3 -3
- package/ui-react/assets/supervisor-C1zJELaq.css +2 -0
- package/ui-react/assets/{supervisor-BbSavtNN.js → supervisor-CWSt_-Ws.js} +1 -1
- package/ui-react/assets/{useSupervisorAction-q0YJmhui.js → useSupervisorAction-CeZGHqFZ.js} +1 -1
- package/ui-react/assets/{widgets-BbRkZm-Z.js → widgets-BhlrHuez.js} +1 -1
- package/ui-react/supervisor.html +3 -3
- package/ui-react/assets/OverviewPage-DH8PtnPI.js +0 -2
- package/ui-react/assets/openExternal-CzqErnSy.js +0 -1
- package/ui-react/assets/supervisor-YWIsBeZU.css +0 -2
package/core.cjs
CHANGED
|
@@ -833,7 +833,11 @@ var require_config = __commonJS({
|
|
|
833
833
|
// 不配置 = LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken。
|
|
834
834
|
apiAccessKey: null,
|
|
835
835
|
// 关闭窗口行为(系统级):'hide' = 隐藏至托盘、服务常驻(默认);'exit' = 退出管家并停全部服务链。
|
|
836
|
-
closeAction: "hide"
|
|
836
|
+
closeAction: "hide",
|
|
837
|
+
// 外部打开的浏览器偏好(系统级,本机配置):存环境表单候选清单里的 id,null = 未选。
|
|
838
|
+
// 与「系统默认浏览器」分两个字段是刻意的:前者是用户在本产品里的选择,后者是操作系统的事实;
|
|
839
|
+
// 系统说不出默认时按候选次序分发并如实标注,用户可在这里定一次覆盖它(见 platform/os/environment.js)。
|
|
840
|
+
externalBrowser: null
|
|
837
841
|
};
|
|
838
842
|
function buildDefaults2(ext) {
|
|
839
843
|
const pending = normalizeExtension(ext).defaults.slice();
|
|
@@ -947,7 +951,7 @@ var require_version = __commonJS({
|
|
|
947
951
|
var fs2 = require("node:fs");
|
|
948
952
|
var path2 = require("node:path");
|
|
949
953
|
function guardVersion() {
|
|
950
|
-
if (true) return String("0.1.6-BETA.
|
|
954
|
+
if (true) return String("0.1.6-BETA.14");
|
|
951
955
|
try {
|
|
952
956
|
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
953
957
|
} catch {
|
|
@@ -1080,6 +1084,7 @@ var require_fs = __commonJS({
|
|
|
1080
1084
|
"src/platform/util/fs.js"(exports2, module2) {
|
|
1081
1085
|
"use strict";
|
|
1082
1086
|
var fs2 = require("node:fs");
|
|
1087
|
+
var os2 = require("node:os");
|
|
1083
1088
|
var path2 = require("node:path");
|
|
1084
1089
|
function dirSizeBytes(root) {
|
|
1085
1090
|
let total = 0;
|
|
@@ -1140,7 +1145,26 @@ var require_fs = __commonJS({
|
|
|
1140
1145
|
throw e;
|
|
1141
1146
|
}
|
|
1142
1147
|
}
|
|
1143
|
-
|
|
1148
|
+
function removeTreeDeferred(dir, ms) {
|
|
1149
|
+
if (!dir) return null;
|
|
1150
|
+
const t = setTimeout(() => {
|
|
1151
|
+
try {
|
|
1152
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
1153
|
+
} catch {
|
|
1154
|
+
}
|
|
1155
|
+
}, ms === void 0 ? 6e4 : ms);
|
|
1156
|
+
if (t.unref) t.unref();
|
|
1157
|
+
return t;
|
|
1158
|
+
}
|
|
1159
|
+
function allocTempDir(prefix) {
|
|
1160
|
+
const dir = fs2.mkdtempSync(path2.join(os2.tmpdir(), prefix || "dsh-"));
|
|
1161
|
+
try {
|
|
1162
|
+
fs2.chmodSync(dir, 448);
|
|
1163
|
+
} catch {
|
|
1164
|
+
}
|
|
1165
|
+
return dir;
|
|
1166
|
+
}
|
|
1167
|
+
module2.exports = { dirSizeBytes, writeAtomic, removeTreeDeferred, allocTempDir };
|
|
1144
1168
|
}
|
|
1145
1169
|
});
|
|
1146
1170
|
|
|
@@ -4831,1218 +4855,1446 @@ var require_capability_profile = __commonJS({
|
|
|
4831
4855
|
}
|
|
4832
4856
|
});
|
|
4833
4857
|
|
|
4834
|
-
// src/platform/os/
|
|
4835
|
-
var
|
|
4836
|
-
"src/platform/os/
|
|
4837
|
-
"use strict";
|
|
4838
|
-
var ex2 = require_exec();
|
|
4839
|
-
var isWindows = process.platform === "win32";
|
|
4840
|
-
function signalProcess(pid, sig) {
|
|
4841
|
-
if (!Number.isInteger(pid) || pid <= 0) return;
|
|
4842
|
-
if (isWindows) {
|
|
4843
|
-
try {
|
|
4844
|
-
process.kill(pid, sig);
|
|
4845
|
-
} catch {
|
|
4846
|
-
}
|
|
4847
|
-
return;
|
|
4848
|
-
}
|
|
4849
|
-
try {
|
|
4850
|
-
process.kill(-pid, sig);
|
|
4851
|
-
} catch {
|
|
4852
|
-
try {
|
|
4853
|
-
process.kill(pid, sig);
|
|
4854
|
-
} catch {
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
}
|
|
4858
|
-
function killTree(pid, sig, cb, opts) {
|
|
4859
|
-
if (!Number.isInteger(pid) || pid <= 0) {
|
|
4860
|
-
if (cb) cb(new Error("invalid pid"));
|
|
4861
|
-
return;
|
|
4862
|
-
}
|
|
4863
|
-
if (isWindows) {
|
|
4864
|
-
ex2.runAsync("taskkill", ["/PID", String(pid), "/T", "/F"], { timeoutMs: 1e4 }).then((r) => {
|
|
4865
|
-
if (cb) cb(r.ok ? null : new Error(r.error || "taskkill failed"));
|
|
4866
|
-
});
|
|
4867
|
-
return;
|
|
4868
|
-
}
|
|
4869
|
-
if (opts && opts.ownGroup === true) {
|
|
4870
|
-
signalProcess(pid, sig || "SIGTERM");
|
|
4871
|
-
} else {
|
|
4872
|
-
try {
|
|
4873
|
-
process.kill(pid, sig || "SIGTERM");
|
|
4874
|
-
} catch {
|
|
4875
|
-
}
|
|
4876
|
-
}
|
|
4877
|
-
if (cb) process.nextTick(cb, null);
|
|
4878
|
-
}
|
|
4879
|
-
module2.exports = { signalProcess, killTree };
|
|
4880
|
-
}
|
|
4881
|
-
});
|
|
4882
|
-
|
|
4883
|
-
// src/platform/os/file-protect.js
|
|
4884
|
-
var require_file_protect = __commonJS({
|
|
4885
|
-
"src/platform/os/file-protect.js"(exports2, module2) {
|
|
4858
|
+
// src/platform/os/browser-inventory.js
|
|
4859
|
+
var require_browser_inventory = __commonJS({
|
|
4860
|
+
"src/platform/os/browser-inventory.js"(exports2, module2) {
|
|
4886
4861
|
"use strict";
|
|
4887
4862
|
var fs2 = require("node:fs");
|
|
4888
|
-
var os2 = require("node:os");
|
|
4889
4863
|
var path2 = require("node:path");
|
|
4890
|
-
var
|
|
4891
|
-
var
|
|
4892
|
-
var
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
return
|
|
4864
|
+
var os2 = require("node:os");
|
|
4865
|
+
var exec = require_exec();
|
|
4866
|
+
var { isExecutableFile } = require_exec_path();
|
|
4867
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
4868
|
+
function engineOf(bin) {
|
|
4869
|
+
const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
|
|
4870
|
+
if (/(chrome|chromium|msedge|edge|brave|vivaldi|opera|thorium)/.test(base)) return "chromium";
|
|
4871
|
+
if (/(firefox|librewolf|waterfox)/.test(base)) return "firefox";
|
|
4872
|
+
return "other";
|
|
4898
4873
|
}
|
|
4899
|
-
function
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4874
|
+
function tokenizeExec(line) {
|
|
4875
|
+
const toks = [];
|
|
4876
|
+
let cur = "";
|
|
4877
|
+
let q = null;
|
|
4878
|
+
let esc = false;
|
|
4879
|
+
let has = false;
|
|
4880
|
+
for (const ch of String(line)) {
|
|
4881
|
+
if (esc) {
|
|
4882
|
+
cur += ch;
|
|
4883
|
+
esc = false;
|
|
4884
|
+
continue;
|
|
4905
4885
|
}
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
try {
|
|
4911
|
-
fs2.chmodSync(file, 384);
|
|
4912
|
-
return { ok: true, mode: "posix-0600" };
|
|
4913
|
-
} catch (e) {
|
|
4914
|
-
return { ok: false, mode: "posix-0600", reason: e.message };
|
|
4886
|
+
if (ch === "\\") {
|
|
4887
|
+
esc = true;
|
|
4888
|
+
has = true;
|
|
4889
|
+
continue;
|
|
4915
4890
|
}
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
const r = ex2.runDetail("icacls", [file, "/inheritance:r", "/grant:r", user + ":F"], { stdio: "ignore", timeoutMs: 5e3 });
|
|
4921
|
-
return r.ok ? { ok: true, mode: "icacls-file" } : { ok: false, mode: "icacls-file", reason: r.error || "\u9000\u51FA\u7801 " + r.code };
|
|
4922
|
-
}
|
|
4923
|
-
function protectDir(dir) {
|
|
4924
|
-
if (!IS_WINDOWS2) {
|
|
4925
|
-
try {
|
|
4926
|
-
fs2.chmodSync(dir, 448);
|
|
4927
|
-
return { ok: true, mode: "posix-0700" };
|
|
4928
|
-
} catch (e) {
|
|
4929
|
-
return { ok: false, mode: "posix-0700", reason: e.message };
|
|
4891
|
+
if (q) {
|
|
4892
|
+
if (ch === q) q = null;
|
|
4893
|
+
else cur += ch;
|
|
4894
|
+
continue;
|
|
4930
4895
|
}
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
const r = ex2.runDetail("icacls", [dir, "/inheritance:r", "/grant:r", user + ":(OI)(CI)F"], { stdio: "ignore", timeoutMs: 1e4 });
|
|
4936
|
-
return r.ok ? { ok: true, mode: "icacls-dir" } : { ok: false, mode: "icacls-dir", reason: r.error || "\u9000\u51FA\u7801 " + r.code };
|
|
4937
|
-
}
|
|
4938
|
-
function ensurePrivateDir(dir) {
|
|
4939
|
-
try {
|
|
4940
|
-
fs2.mkdirSync(dir, { recursive: true });
|
|
4941
|
-
} catch (e) {
|
|
4942
|
-
return { ok: false, mode: "mkdir", reason: e.message };
|
|
4943
|
-
}
|
|
4944
|
-
return protectDir(dir);
|
|
4945
|
-
}
|
|
4946
|
-
function writePrivate(file, data) {
|
|
4947
|
-
try {
|
|
4948
|
-
const dir = path2.dirname(file);
|
|
4949
|
-
try {
|
|
4950
|
-
fs2.mkdirSync(dir, { recursive: true });
|
|
4951
|
-
} catch {
|
|
4896
|
+
if (ch === "'" || ch === '"') {
|
|
4897
|
+
q = ch;
|
|
4898
|
+
has = true;
|
|
4899
|
+
continue;
|
|
4952
4900
|
}
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
fs2.rmSync(tmp, { force: true });
|
|
4959
|
-
} catch {
|
|
4901
|
+
if (/\s/.test(ch)) {
|
|
4902
|
+
if (has) {
|
|
4903
|
+
toks.push(cur);
|
|
4904
|
+
cur = "";
|
|
4905
|
+
has = false;
|
|
4960
4906
|
}
|
|
4961
|
-
|
|
4907
|
+
continue;
|
|
4962
4908
|
}
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
if (p2 && p2.ok === false) return { ok: false, reason: "protect(file): " + (p2.reason || p2.mode), mode: p2.mode };
|
|
4966
|
-
return { ok: true };
|
|
4967
|
-
} catch (e) {
|
|
4968
|
-
return { ok: false, reason: e.message };
|
|
4909
|
+
cur += ch;
|
|
4910
|
+
has = true;
|
|
4969
4911
|
}
|
|
4912
|
+
if (has) toks.push(cur);
|
|
4913
|
+
return toks;
|
|
4970
4914
|
}
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
var ARGV_UNSAFE_RE = /[\s;|&<>`'"$(){}\\*?~#]/;
|
|
4981
|
-
var WIN_ABS_PATH_RE = /^[A-Za-z]:\\[^;|&<>`'"$*?~#\s]*$/;
|
|
4982
|
-
var UNIT_NAME_RE = /^[A-Za-z0-9:@._-]{1,128}$/;
|
|
4983
|
-
var UNSAFE_LEDGER_KEYS = ["__proto__", "prototype", "constructor"];
|
|
4984
|
-
var LEDGER_UNSAFE_RE = /[\s\u0000-\u001f\u007f]/;
|
|
4985
|
-
function argvViolation(arg) {
|
|
4986
|
-
const s = String(arg == null ? "" : arg);
|
|
4987
|
-
if (!s) return "\u7A7A\u7684 argv \u9879";
|
|
4988
|
-
if (ARGV_UNSAFE_RE.test(s) && !WIN_ABS_PATH_RE.test(s)) return "argv \u9879\u542B\u7981\u7528\u5B57\u7B26\uFF08\u7A7A\u767D/shell \u5143\u5B57\u7B26\uFF09: " + s.slice(0, 80);
|
|
4989
|
-
return null;
|
|
4990
|
-
}
|
|
4991
|
-
var CONTROL_RE = /[\u0000-\u001f\u007f]/;
|
|
4992
|
-
function isAbsoluteForm(p) {
|
|
4993
|
-
const s = String(p == null ? "" : p);
|
|
4994
|
-
return s.charCodeAt(0) === 47 || /^[A-Za-z]:[\\/]/.test(s) || s.charCodeAt(0) === 92 && s.charCodeAt(1) === 92;
|
|
4915
|
+
function parseExecLine(line) {
|
|
4916
|
+
let toks = tokenizeExec(line).filter((t) => t !== "%%" && !/^%[a-zA-Z]$/.test(t));
|
|
4917
|
+
if (toks[0] === "env") {
|
|
4918
|
+
let i = 1;
|
|
4919
|
+
while (i < toks.length && /=/.test(toks[i])) i++;
|
|
4920
|
+
toks = toks.slice(i);
|
|
4921
|
+
}
|
|
4922
|
+
if (!toks.length) return null;
|
|
4923
|
+
return { bin: toks[0], baseArgs: toks.slice(1) };
|
|
4995
4924
|
}
|
|
4996
|
-
function
|
|
4997
|
-
const
|
|
4998
|
-
if (!
|
|
4999
|
-
|
|
5000
|
-
if (s.length > 4096) return "\u5B89\u88C5\u524D\u7F00\u8D85\u957F: " + s.slice(0, 60) + "...";
|
|
5001
|
-
if (s[0] === "-") return "\u5B89\u88C5\u524D\u7F00\u4EE5 - \u5F00\u5934\uFF08\u4F1A\u88AB\u5F53\u4F5C npm \u9009\u9879\uFF09: " + s.slice(0, 80);
|
|
5002
|
-
if (!isAbsoluteForm(s)) return "\u5B89\u88C5\u524D\u7F00\u987B\u4E3A\u7EDD\u5BF9\u8DEF\u5F84\uFF08/ \u5F00\u5934\u3001win \u76D8\u7B26\u6216 UNC\uFF09: " + s.slice(0, 80);
|
|
5003
|
-
return null;
|
|
4925
|
+
function regValueOf(out) {
|
|
4926
|
+
const m = String(out || "").match(/REG_(?:EXPAND_SZ|SZ)\s+(.*)/);
|
|
4927
|
+
if (!m) return null;
|
|
4928
|
+
return m[1].trim() || null;
|
|
5004
4929
|
}
|
|
5005
|
-
function
|
|
5006
|
-
const
|
|
5007
|
-
return
|
|
4930
|
+
function expandEnvVars(value, env) {
|
|
4931
|
+
const e = env || process.env;
|
|
4932
|
+
return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
|
|
5008
4933
|
}
|
|
5009
|
-
function
|
|
5010
|
-
const s = String(
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
return null;
|
|
4934
|
+
function exeFromCmdLine(cmdLine) {
|
|
4935
|
+
const s = String(cmdLine || "");
|
|
4936
|
+
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
4937
|
+
if (m) return m[1];
|
|
4938
|
+
m = s.match(/^\s*(.*?\.exe)/i);
|
|
4939
|
+
return m ? m[1] : null;
|
|
5015
4940
|
}
|
|
5016
|
-
function
|
|
5017
|
-
|
|
5018
|
-
const max = typeof o.max === "number" ? o.max : 128;
|
|
5019
|
-
const empty = o.empty == null ? "unknown" : o.empty;
|
|
5020
|
-
const unsafe = o.unsafe == null ? "(other)" : o.unsafe;
|
|
5021
|
-
if (typeof raw !== "string" || !raw) return empty;
|
|
5022
|
-
const s = raw.length > max ? raw.slice(0, max) : raw;
|
|
5023
|
-
if (UNSAFE_LEDGER_KEYS.indexOf(s) >= 0 || LEDGER_UNSAFE_RE.test(s)) return unsafe;
|
|
5024
|
-
return s;
|
|
4941
|
+
function safeRegKeyPart(s) {
|
|
4942
|
+
return typeof s === "string" && s.length > 0 && s.length <= 200 && /^[\x20-\x7e]+$/.test(s) && !/[;|&`$()<>^"'\r\n]/.test(s);
|
|
5025
4943
|
}
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
LEDGER_UNSAFE_KEYS_RE: LEDGER_UNSAFE_RE,
|
|
5033
|
-
argvViolation,
|
|
5034
|
-
pkgNameViolation,
|
|
5035
|
-
unitNameViolation,
|
|
5036
|
-
ledgerKey,
|
|
5037
|
-
CONTROL_RE,
|
|
5038
|
-
isAbsoluteForm,
|
|
5039
|
-
prefixViolation
|
|
5040
|
-
};
|
|
5041
|
-
}
|
|
5042
|
-
});
|
|
5043
|
-
|
|
5044
|
-
// src/platform/os/spawn.js
|
|
5045
|
-
var require_spawn = __commonJS({
|
|
5046
|
-
"src/platform/os/spawn.js"(exports2, module2) {
|
|
5047
|
-
"use strict";
|
|
5048
|
-
var { spawn } = require("node:child_process");
|
|
5049
|
-
function detached(cmd2, args, opts) {
|
|
5050
|
-
const o = opts || {};
|
|
5051
|
-
return spawn(cmd2, args, Object.assign({}, o, {
|
|
5052
|
-
detached: true,
|
|
5053
|
-
windowsHide: true,
|
|
5054
|
-
// 默认 ignore;显式 undefined 也回落 ignore,避免 stdio:undefined 的歧义。
|
|
5055
|
-
stdio: o.stdio === void 0 ? "ignore" : o.stdio
|
|
5056
|
-
}));
|
|
5057
|
-
}
|
|
5058
|
-
function piped(cmd2, args, opts) {
|
|
5059
|
-
const o = opts || {};
|
|
5060
|
-
return spawn(cmd2, args, Object.assign({}, o, {
|
|
5061
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
5062
|
-
windowsHide: true,
|
|
5063
|
-
detached: o.detached === true
|
|
5064
|
-
}));
|
|
4944
|
+
function regValue(runner, note, key, name) {
|
|
4945
|
+
const args = name ? ["query", key, "/v", name] : ["query", key, "/ve"];
|
|
4946
|
+
const out = runner("reg.exe", args);
|
|
4947
|
+
const v = regValueOf(out);
|
|
4948
|
+
note(name ? key + " /v " + name : key, v ? "ok" : "empty");
|
|
4949
|
+
return v;
|
|
5065
4950
|
}
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
}));
|
|
4951
|
+
var REG_HIVE_ALIAS = { HKLM: "HKEY_LOCAL_MACHINE", HKCU: "HKEY_CURRENT_USER", HKCR: "HKEY_CLASSES_ROOT", HKU: "HKEY_USERS", HKCC: "HKEY_CURRENT_CONFIG" };
|
|
4952
|
+
function regKeyFull(key) {
|
|
4953
|
+
const s = String(key || "");
|
|
4954
|
+
const i = s.indexOf("\\");
|
|
4955
|
+
const root = i < 0 ? s : s.slice(0, i);
|
|
4956
|
+
return (REG_HIVE_ALIAS[root.toUpperCase()] || root) + (i < 0 ? "" : s.slice(i));
|
|
5073
4957
|
}
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
var require_portable = __commonJS({
|
|
5080
|
-
"src/platform/os/portable.js"(exports2, module2) {
|
|
5081
|
-
"use strict";
|
|
5082
|
-
var fs2 = require("node:fs");
|
|
5083
|
-
var pidlookup = require_pidlookup();
|
|
5084
|
-
var spawner = require_spawn();
|
|
5085
|
-
var procOS = require_process();
|
|
5086
|
-
var STOP_WAIT_CAP_MS = 3e3;
|
|
5087
|
-
var NAP_MS = 150;
|
|
5088
|
-
function nap(ms) {
|
|
5089
|
-
try {
|
|
5090
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
5091
|
-
} catch {
|
|
4958
|
+
function regSubkeys(runner, note, key) {
|
|
4959
|
+
const out = runner("reg.exe", ["query", key]);
|
|
4960
|
+
if (!out) {
|
|
4961
|
+
note(key, "unreadable");
|
|
4962
|
+
return [];
|
|
5092
4963
|
}
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
4964
|
+
const prefix = regKeyFull(key) + "\\";
|
|
4965
|
+
const names = [];
|
|
4966
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
4967
|
+
const l = line.trim();
|
|
4968
|
+
if (!/^HKEY_/i.test(l) || l.length <= prefix.length) continue;
|
|
4969
|
+
if (l.slice(0, prefix.length).toUpperCase() !== prefix.toUpperCase()) continue;
|
|
4970
|
+
const rest = l.slice(prefix.length);
|
|
4971
|
+
if (rest && !rest.includes("\\") && safeRegKeyPart(rest)) names.push(rest);
|
|
5101
4972
|
}
|
|
4973
|
+
note(key, names.length ? names.length + " \u9879" : "\u65E0\u5B50\u952E");
|
|
4974
|
+
return names;
|
|
5102
4975
|
}
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
const p = Number(o && o.port);
|
|
5111
|
-
return Number.isInteger(p) && p > 0 ? p : 0;
|
|
5112
|
-
};
|
|
5113
|
-
var pidFileOf = (o) => o && o.pidFile || null;
|
|
5114
|
-
var anchorsOf = (o) => Array.isArray(o && o.anchors) ? o.anchors : [];
|
|
5115
|
-
function findOurs(o) {
|
|
5116
|
-
const anchors = anchorsOf(o);
|
|
5117
|
-
const fp = readPidFile(pidFileOf(o));
|
|
5118
|
-
if (fp !== null && pidlookup.isAlive(fp) && matchesAnchors(fp, anchors)) return { pid: fp, ownGroup: true };
|
|
5119
|
-
const port = portOf(o);
|
|
5120
|
-
if (port) {
|
|
5121
|
-
const q = pidlookup.findListeningPid(port);
|
|
5122
|
-
if (q !== null && q !== fp && matchesAnchors(q, anchors)) return { pid: q, ownGroup: false };
|
|
4976
|
+
var WIN_APP_PATHS = ["msedge.exe", "chrome.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe", "chromium.exe", "thorium.exe", "librewolf.exe"];
|
|
4977
|
+
function winExeOfProgId(runner, note, progId, env) {
|
|
4978
|
+
if (!safeRegKeyPart(progId)) return null;
|
|
4979
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
4980
|
+
const cmd2 = regValue(runner, note, root + "\\" + progId + "\\shell\\open\\command");
|
|
4981
|
+
const exe = cmd2 ? exeFromCmdLine(expandEnvVars(cmd2, env)) : null;
|
|
4982
|
+
if (exe) return exe;
|
|
5123
4983
|
}
|
|
5124
4984
|
return null;
|
|
5125
4985
|
}
|
|
5126
|
-
function
|
|
5127
|
-
const
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
4986
|
+
function probeWin(d) {
|
|
4987
|
+
const { runOut, env, canExec } = d;
|
|
4988
|
+
const notes = [];
|
|
4989
|
+
const note = (source, detail) => {
|
|
4990
|
+
notes.push({ source, detail });
|
|
4991
|
+
};
|
|
4992
|
+
const found = /* @__PURE__ */ new Map();
|
|
4993
|
+
const keyOf = (exe) => String(exe || "").toLowerCase().replace(/[\\/]/g, "\\");
|
|
4994
|
+
const push = (exe, how) => {
|
|
4995
|
+
const full = expandEnvVars(exe, env).trim();
|
|
4996
|
+
if (!/\.exe$/i.test(full)) {
|
|
4997
|
+
note(how, "\u6765\u6E90\u7ED9\u51FA\u7684\u4E0D\u662F exe \u8DEF\u5F84: " + full);
|
|
4998
|
+
return null;
|
|
5132
4999
|
}
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
supportsTransient: true,
|
|
5139
|
-
// 无操作 = 成功(与 systemd 的动词返回形态一致,调用方无需按 provider 分支)。
|
|
5140
|
-
daemonReload() {
|
|
5141
|
-
return true;
|
|
5142
|
-
},
|
|
5143
|
-
resetFailed() {
|
|
5144
|
-
return true;
|
|
5145
|
-
},
|
|
5146
|
-
/** 拉起:spawn(detached)——POSIX 自成进程组(kill(-pid) 语义的前提)、win32 windowsHide +
|
|
5147
|
-
* CREATE_NEW_PROCESS_GROUP(NO-CONSOLE-WINDOW 纪律收口在 platform/os/spawn.js)。
|
|
5148
|
-
* 调用方传来的 props(cgroup 语义)在此如实忽略:本档无内核强制可施加。
|
|
5149
|
-
* @param {{cmd:string[], env?:object, workingDir?:string, pidFile?:string, port?:number, anchors?:string[]}} o */
|
|
5150
|
-
startTransient(o) {
|
|
5151
|
-
const opts = o || {};
|
|
5152
|
-
const cmd2 = opts.cmd || [];
|
|
5153
|
-
if (!cmd2.length) throw new Error("portable \u62C9\u8D77\u62D2\u7EDD\uFF1A\u7A7A\u547D\u4EE4");
|
|
5154
|
-
const child = spawner.detached(cmd2[0], cmd2.slice(1), {
|
|
5155
|
-
cwd: opts.workingDir || void 0,
|
|
5156
|
-
env: Object.assign({}, process.env, opts.env || {})
|
|
5157
|
-
});
|
|
5158
|
-
child.on("error", () => {
|
|
5159
|
-
});
|
|
5160
|
-
if (!child.pid) {
|
|
5161
|
-
try {
|
|
5162
|
-
child.kill();
|
|
5163
|
-
} catch {
|
|
5164
|
-
}
|
|
5165
|
-
throw new Error("portable \u62C9\u8D77\u5931\u8D25\uFF1Aspawn \u672A\u4EA7\u751F\u8FDB\u7A0B");
|
|
5000
|
+
const k = keyOf(full);
|
|
5001
|
+
const hit = found.get(k);
|
|
5002
|
+
if (hit) {
|
|
5003
|
+
if (!hit.sources.includes(how)) hit.sources.push(how);
|
|
5004
|
+
return hit;
|
|
5166
5005
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5006
|
+
if (!canExec(full)) {
|
|
5007
|
+
note(how, "\u6307\u5411\u7684\u6587\u4EF6\u4E0D\u53EF\u6267\u884C: " + full);
|
|
5008
|
+
return null;
|
|
5170
5009
|
}
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5010
|
+
const item = { id: k, name: path2.basename(full).replace(/\.exe$/i, ""), engine: engineOf(full), bin: full, source: how, sources: [how] };
|
|
5011
|
+
found.set(k, item);
|
|
5012
|
+
note(how, item.name);
|
|
5013
|
+
return item;
|
|
5014
|
+
};
|
|
5015
|
+
const progIds = /* @__PURE__ */ new Map();
|
|
5016
|
+
const addProgId = (pid, how) => {
|
|
5017
|
+
const s = String(pid || "").trim();
|
|
5018
|
+
if (!safeRegKeyPart(s)) return;
|
|
5019
|
+
if (progIds.get(s) === "userchoice") return;
|
|
5020
|
+
progIds.set(s, how);
|
|
5021
|
+
};
|
|
5022
|
+
let defaultId = null;
|
|
5023
|
+
let defaultSource = null;
|
|
5024
|
+
const DEF_RANK = { userchoice: 1, "scheme-association": 2, "only-installed": 9 };
|
|
5025
|
+
let defRank = 99;
|
|
5026
|
+
const setDefault = (item, how) => {
|
|
5027
|
+
const r = DEF_RANK[how] === void 0 ? 99 : DEF_RANK[how];
|
|
5028
|
+
if (item && r < defRank) {
|
|
5029
|
+
defRank = r;
|
|
5030
|
+
defaultId = item.id;
|
|
5031
|
+
defaultSource = how;
|
|
5176
5032
|
}
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
const
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5033
|
+
};
|
|
5034
|
+
const cmdToExe = (raw) => raw ? exeFromCmdLine(expandEnvVars(raw, env)) : null;
|
|
5035
|
+
const uc = regValue(runOut, note, "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice", "ProgId");
|
|
5036
|
+
if (uc) addProgId(uc, "userchoice");
|
|
5037
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
5038
|
+
const pid = regValue(runOut, note, root + "\\https");
|
|
5039
|
+
if (pid) addProgId(pid, "scheme-association");
|
|
5040
|
+
const exe = cmdToExe(regValue(runOut, note, root + "\\https\\shell\\open\\command"));
|
|
5041
|
+
if (exe) setDefault(push(exe, "scheme-association"), "scheme-association");
|
|
5042
|
+
}
|
|
5043
|
+
for (const name of regSubkeys(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet")) {
|
|
5044
|
+
addProgId(name, "startmenu-catalog");
|
|
5045
|
+
const exe = cmdToExe(regValue(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" + name + "\\shell\\open\\command")) || winExeOfProgId(runOut, note, name, env);
|
|
5046
|
+
if (exe) push(exe, "startmenu-catalog");
|
|
5047
|
+
}
|
|
5048
|
+
for (const root of ["HKLM\\SOFTWARE", "HKCU\\SOFTWARE"]) {
|
|
5049
|
+
for (const capPath of regValueTargets(runOut, note, root + "\\RegisteredApplications")) {
|
|
5050
|
+
const https = regValue(runOut, note, capPath + "\\UrlAssociations\\https");
|
|
5051
|
+
const sid = regValue(runOut, note, capPath, "StartMenuInternet");
|
|
5052
|
+
const pid = https || sid;
|
|
5053
|
+
if (pid) addProgId(pid, "registered-apps");
|
|
5187
5054
|
}
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5055
|
+
}
|
|
5056
|
+
for (const exe of WIN_APP_PATHS) {
|
|
5057
|
+
for (const root of ["HKCU", "HKLM"]) {
|
|
5058
|
+
const v = regValue(runOut, note, root + "\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + exe);
|
|
5059
|
+
if (v && push(v, "app-paths")) break;
|
|
5191
5060
|
}
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5061
|
+
}
|
|
5062
|
+
for (const [pid, how] of progIds) {
|
|
5063
|
+
const exe = winExeOfProgId(runOut, note, pid, env);
|
|
5064
|
+
if (!exe) continue;
|
|
5065
|
+
const item = push(exe, how);
|
|
5066
|
+
if (how === "userchoice") setDefault(item, "userchoice");
|
|
5067
|
+
}
|
|
5068
|
+
if (found.size === 1) setDefault([...found.values()][0], "only-installed");
|
|
5069
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5070
|
+
}
|
|
5071
|
+
function regValueTargets(runOut, note, key) {
|
|
5072
|
+
const out = runOut("reg.exe", ["query", key]);
|
|
5073
|
+
if (!out) {
|
|
5074
|
+
note(key, "unreadable");
|
|
5075
|
+
return [];
|
|
5076
|
+
}
|
|
5077
|
+
const paths = [];
|
|
5078
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
5079
|
+
const m = line.trim().match(/REG_SZ\s+(.*)/);
|
|
5080
|
+
if (!m) continue;
|
|
5081
|
+
const rel = m[1].trim();
|
|
5082
|
+
if (!safeRegKeyPart(rel)) continue;
|
|
5083
|
+
const root = key.slice(0, key.indexOf("\\"));
|
|
5084
|
+
paths.push(root + "\\" + rel);
|
|
5085
|
+
}
|
|
5086
|
+
note(key, paths.length ? paths.length + " \u4E2A\u80FD\u529B\u8DEF\u5F84" : "\u65E0\u503C");
|
|
5087
|
+
return paths;
|
|
5088
|
+
}
|
|
5089
|
+
var MAC_JXA_LIST = [
|
|
5090
|
+
"ObjC.import('Foundation');",
|
|
5091
|
+
"var ws=$.NSWorkspace.sharedWorkspace;",
|
|
5092
|
+
"var u=$.NSURL.URLWithString('https://dsh.local/probe');",
|
|
5093
|
+
"var out=[];var def='';",
|
|
5094
|
+
"try{var d=ws.URLForApplicationToOpenURL(u); if(!d.isNil()) def=ObjC.unwrap(d.path)||'';}catch(e){}",
|
|
5095
|
+
"var list=null;",
|
|
5096
|
+
"try{list=ws.urlsForApplicationsToOpenURL(u);}catch(e){}",
|
|
5097
|
+
"if(list===null||typeof list.count!=='number'){if(def){out.push(def+'\\t\\t1');}}else{",
|
|
5098
|
+
"var n=Number(list.count);",
|
|
5099
|
+
"for(var i=0;i<n;i++){",
|
|
5100
|
+
"var p=ObjC.unwrap(list.objectAtIndex(i).path)||''; if(!p) continue;",
|
|
5101
|
+
"var exe='';var bid='';",
|
|
5102
|
+
"var b=$.NSBundle.bundleWithPath(p);",
|
|
5103
|
+
"if(!b.isNil()){exe=ObjC.unwrap(b.executablePath)||'';bid=ObjC.unwrap(b.bundleIdentifier)||'';}",
|
|
5104
|
+
"out.push((exe||p)+'\\t'+bid+'\\t'+(p&&def&&p===def?1:0));}",
|
|
5105
|
+
"}",
|
|
5106
|
+
// 末句必须是裸表达式:osascript 取的是最后一条**语句**的值,if/else 语句不产结果,
|
|
5107
|
+
// 写在分支里会让整段查询输出空字符串(表现为「系统未报任何可用应用」)。
|
|
5108
|
+
"out.join('\\n');"
|
|
5109
|
+
].join("");
|
|
5110
|
+
function probeMac(d) {
|
|
5111
|
+
const { runOut, canExec } = d;
|
|
5112
|
+
const notes = [];
|
|
5113
|
+
const note = (source, detail) => {
|
|
5114
|
+
notes.push({ source, detail });
|
|
5115
|
+
};
|
|
5116
|
+
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA_LIST]);
|
|
5117
|
+
if (!out || !out.trim()) {
|
|
5118
|
+
note("launchservices", "\u67E5\u8BE2\u65E0\u8F93\u51FA\uFF08\u65E7\u7CFB\u7EDF\u6216\u88AB\u6743\u9650\u62E6\u622A\uFF09");
|
|
5119
|
+
return { browsers: [], defaultId: null, defaultSource: null, probed: notes };
|
|
5120
|
+
}
|
|
5121
|
+
const keyOf = (exe) => String(exe || "").toLowerCase();
|
|
5122
|
+
const found = /* @__PURE__ */ new Map();
|
|
5123
|
+
let defaultId = null;
|
|
5124
|
+
let defaultSource = null;
|
|
5125
|
+
for (const line of out.trim().split("\n")) {
|
|
5126
|
+
const parts = line.split(" ");
|
|
5127
|
+
const bin = (parts[0] || "").trim();
|
|
5128
|
+
if (!bin) continue;
|
|
5129
|
+
if (!canExec(bin)) {
|
|
5130
|
+
note("launchservices", "\u4E0D\u53EF\u6267\u884C: " + bin);
|
|
5131
|
+
continue;
|
|
5210
5132
|
}
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
const opts = o || {};
|
|
5219
|
-
if (findOurs(opts)) return true;
|
|
5220
|
-
const port = portOf(opts);
|
|
5221
|
-
const pidFile = pidFileOf(opts);
|
|
5222
|
-
const anchors = anchorsOf(opts);
|
|
5223
|
-
if (!port && !pidFile) return null;
|
|
5224
|
-
if (!anchors.length) {
|
|
5225
|
-
const fp2 = readPidFile(pidFile);
|
|
5226
|
-
if (fp2 !== null && pidlookup.isAlive(fp2)) return true;
|
|
5227
|
-
if (port) {
|
|
5228
|
-
const q = pidlookup.findListeningPid(port);
|
|
5229
|
-
if (q !== null) return true;
|
|
5230
|
-
if (fp2 !== null) return false;
|
|
5231
|
-
return null;
|
|
5133
|
+
const k = keyOf(bin);
|
|
5134
|
+
if (!found.has(k)) found.set(k, { id: k, name: path2.basename(bin), engine: engineOf(bin), bin, source: "launchservices", sources: ["launchservices"], isDefault: false });
|
|
5135
|
+
if (parts[2] === "1") {
|
|
5136
|
+
found.get(k).isDefault = true;
|
|
5137
|
+
if (!defaultId) {
|
|
5138
|
+
defaultId = k;
|
|
5139
|
+
defaultSource = "launchservices";
|
|
5232
5140
|
}
|
|
5233
|
-
return fp2 !== null ? false : null;
|
|
5234
5141
|
}
|
|
5235
|
-
const fp = readPidFile(pidFile);
|
|
5236
|
-
if (fp !== null && pidlookup.isAlive(fp) && !pidlookup.readCmdline(fp)) return null;
|
|
5237
|
-
return false;
|
|
5238
|
-
},
|
|
5239
|
-
// portable 无 systemd transient 单元文件;run.pid 的清理归 cleanTransient。
|
|
5240
|
-
transientUnitFile() {
|
|
5241
|
-
return null;
|
|
5242
|
-
},
|
|
5243
|
-
/** 清理同名残留:先停掉仍活着的旧进程(重启自愈路径:旧进程未监听端口时端口探测拦不住),再清 run.pid。 */
|
|
5244
|
-
cleanTransient(unit, o) {
|
|
5245
|
-
const opts = o || {};
|
|
5246
|
-
const errors = [];
|
|
5247
|
-
if (this.stopUnit(unit, Object.assign({}, opts, { timeoutMs: 1500 })) === false) errors.push("stop-unconfirmed");
|
|
5248
|
-
removePidFile(opts);
|
|
5249
|
-
return { ok: errors.length === 0, errors };
|
|
5250
|
-
},
|
|
5251
|
-
/** 返回值只表示「是否改动了内核强制」;governor 不因 false 走降级分支 —— 违规处置链本就平台无关。 */
|
|
5252
|
-
setLimits() {
|
|
5253
|
-
return false;
|
|
5254
5142
|
}
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
// src/platform/os/service.js
|
|
5261
|
-
var require_service = __commonJS({
|
|
5262
|
-
"src/platform/os/service.js"(exports2, module2) {
|
|
5263
|
-
"use strict";
|
|
5264
|
-
var fs2 = require("node:fs");
|
|
5265
|
-
var os2 = require("node:os");
|
|
5266
|
-
var path2 = require("node:path");
|
|
5267
|
-
var exec = require_exec();
|
|
5268
|
-
var input = require_input();
|
|
5269
|
-
var execPath = require_exec_path();
|
|
5270
|
-
var { portable } = require_portable();
|
|
5271
|
-
var CapabilityError = class extends Error {
|
|
5272
|
-
constructor(msg) {
|
|
5273
|
-
super(msg);
|
|
5274
|
-
this.name = "CapabilityError";
|
|
5275
|
-
this.code = "CAPABILITY_UNSUPPORTED";
|
|
5143
|
+
note("launchservices", found.size ? found.size + " \u4E2A\u53EF\u6253\u5F00 https \u7684\u5E94\u7528" : "\u7CFB\u7EDF\u672A\u62A5\u4EFB\u4F55\u53EF\u7528\u5E94\u7528");
|
|
5144
|
+
if (!defaultId && found.size === 1) {
|
|
5145
|
+
defaultId = [...found.keys()][0];
|
|
5146
|
+
defaultSource = "only-installed";
|
|
5276
5147
|
}
|
|
5277
|
-
|
|
5278
|
-
var PLATFORM = process.platform;
|
|
5279
|
-
function run(cmd2, args, opts) {
|
|
5280
|
-
return exec.run(cmd2, args, opts || {});
|
|
5148
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5281
5149
|
}
|
|
5282
|
-
var
|
|
5283
|
-
function
|
|
5284
|
-
|
|
5150
|
+
var PJ = path2.posix.join;
|
|
5151
|
+
function desktopDirs(env, home) {
|
|
5152
|
+
const dataHome = env.XDG_DATA_HOME || PJ(home, ".local", "share");
|
|
5153
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5154
|
+
const dirs = [[dataHome, "xdg"], ...dataDirs.map((p) => [p, "xdg"])];
|
|
5155
|
+
dirs.push([PJ(home, ".local", "share"), "xdg"]);
|
|
5156
|
+
dirs.push(["/var/lib/flatpak/exports/share", "flatpak"]);
|
|
5157
|
+
dirs.push([PJ(home, ".local", "share", "flatpak", "exports", "share"), "flatpak"]);
|
|
5158
|
+
dirs.push(["/var/lib/snapd/desktop", "snap"]);
|
|
5159
|
+
const seen = [];
|
|
5160
|
+
return dirs.map(([root, kind]) => ({ dir: PJ(root, "applications"), kind })).filter((x) => {
|
|
5161
|
+
if (seen.includes(x.dir)) return false;
|
|
5162
|
+
seen.push(x.dir);
|
|
5163
|
+
return true;
|
|
5164
|
+
});
|
|
5285
5165
|
}
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
} catch {
|
|
5294
|
-
return false;
|
|
5295
|
-
}
|
|
5296
|
-
},
|
|
5297
|
-
stopUnit(unit, opts) {
|
|
5298
|
-
if (unitNameViolation(unit)) return false;
|
|
5299
|
-
const o = opts || {};
|
|
5300
|
-
try {
|
|
5301
|
-
return run("systemctl", ["--user", "stop", unit], { timeoutMs: o.timeoutMs || 15e3 }) !== null;
|
|
5302
|
-
} catch {
|
|
5303
|
-
return false;
|
|
5166
|
+
function browserFromDesktop(text, kind, file) {
|
|
5167
|
+
let inMain = false;
|
|
5168
|
+
const got = {};
|
|
5169
|
+
for (const line of String(text).split(/\r?\n/)) {
|
|
5170
|
+
if (/^\[Desktop Entry\]\s*$/.test(line)) {
|
|
5171
|
+
inMain = true;
|
|
5172
|
+
continue;
|
|
5304
5173
|
}
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
if (
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5174
|
+
if (/^\[/.test(line)) break;
|
|
5175
|
+
if (!inMain) continue;
|
|
5176
|
+
const m = line.match(/^(Exec|Name|TryExec|Categories)=(.*)$/);
|
|
5177
|
+
if (!m) continue;
|
|
5178
|
+
if (m[1] === "Name" && got.Name) continue;
|
|
5179
|
+
got[m[1]] = m[2].trim();
|
|
5180
|
+
}
|
|
5181
|
+
if (!got.Exec) return null;
|
|
5182
|
+
const categories = String(got.Categories || "");
|
|
5183
|
+
const parsed = parseExecLine(got.Exec);
|
|
5184
|
+
if (!parsed) return null;
|
|
5185
|
+
const engine = engineOf(parsed.bin);
|
|
5186
|
+
const claimsBrowser = /(^|;)WebBrowser(;|$)/.test(categories);
|
|
5187
|
+
if (!claimsBrowser && engine === "other") return null;
|
|
5188
|
+
if (engine === "other") return null;
|
|
5189
|
+
return {
|
|
5190
|
+
// id 恒为归一后的可执行文件路径:defaultId 靠它在清单里定位条目,三平台同一契约
|
|
5191
|
+
id: parsed.bin.toLowerCase(),
|
|
5192
|
+
name: got.Name || path2.basename(file, ".desktop"),
|
|
5193
|
+
engine,
|
|
5194
|
+
bin: parsed.bin,
|
|
5195
|
+
baseArgs: parsed.baseArgs,
|
|
5196
|
+
source: kind,
|
|
5197
|
+
desktopFile: file
|
|
5198
|
+
};
|
|
5199
|
+
}
|
|
5200
|
+
function resolveLinuxBin(bin, canExec, env) {
|
|
5201
|
+
const b = String(bin || "").trim();
|
|
5202
|
+
if (!b) return null;
|
|
5203
|
+
if (b.startsWith("/")) return canExec(b) ? b : null;
|
|
5204
|
+
if (b.includes("/")) return null;
|
|
5205
|
+
for (const dir of String(env.PATH || "").split(":")) {
|
|
5206
|
+
if (!dir) continue;
|
|
5207
|
+
const p = PJ(dir.replace(/\/+$/, ""), b);
|
|
5208
|
+
if (canExec(p)) return p;
|
|
5209
|
+
}
|
|
5210
|
+
return null;
|
|
5211
|
+
}
|
|
5212
|
+
function probeLinux(d) {
|
|
5213
|
+
const { runOut, readFile, exists, listDir, canExec, env, home } = d;
|
|
5214
|
+
const notes = [];
|
|
5215
|
+
const note = (source, detail) => {
|
|
5216
|
+
notes.push({ source, detail });
|
|
5217
|
+
};
|
|
5218
|
+
const found = /* @__PURE__ */ new Map();
|
|
5219
|
+
const usable = (item) => {
|
|
5220
|
+
const resolved = resolveLinuxBin(item.bin, canExec, env);
|
|
5221
|
+
if (!resolved) {
|
|
5222
|
+
note(item.source, "\u4E0D\u53EF\u6267\u884C: " + item.bin);
|
|
5325
5223
|
return null;
|
|
5326
5224
|
}
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
if (
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
uid = os2.userInfo().uid;
|
|
5333
|
-
} catch {
|
|
5225
|
+
const k = resolved.toLowerCase();
|
|
5226
|
+
const hit = found.get(k);
|
|
5227
|
+
if (hit) {
|
|
5228
|
+
if (!hit.sources.includes(item.source)) hit.sources.push(item.source);
|
|
5229
|
+
return hit;
|
|
5334
5230
|
}
|
|
5335
|
-
const
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
* 硬失败只有删单元文件与 daemon-reload(run() 失败返回 null 不抛,成败须如实回传)。 */
|
|
5342
|
-
cleanTransient(unit) {
|
|
5343
|
-
const errors = [];
|
|
5344
|
-
const bad = unitNameViolation(unit);
|
|
5345
|
-
if (bad) return { ok: false, errors: [bad] };
|
|
5346
|
-
exec.runDetail("systemctl", ["--user", "stop", unit + ".service"], { timeoutMs: 1e4 });
|
|
5347
|
-
exec.runDetail("systemctl", ["--user", "reset-failed", unit + ".service"], { timeoutMs: 1e4 });
|
|
5348
|
-
let unlinkOk = true;
|
|
5231
|
+
const v = Object.assign({}, item, { id: k, bin: resolved, sources: [item.source] });
|
|
5232
|
+
found.set(k, v);
|
|
5233
|
+
return v;
|
|
5234
|
+
};
|
|
5235
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5236
|
+
let names = [];
|
|
5349
5237
|
try {
|
|
5350
|
-
|
|
5351
|
-
if (f) fs2.unlinkSync(f);
|
|
5238
|
+
names = listDir(dir).filter((f) => f.endsWith(".desktop"));
|
|
5352
5239
|
} catch {
|
|
5353
|
-
|
|
5354
|
-
|
|
5240
|
+
continue;
|
|
5241
|
+
}
|
|
5242
|
+
for (const f of names) {
|
|
5243
|
+
let text = null;
|
|
5244
|
+
try {
|
|
5245
|
+
text = readFile(PJ(dir, f));
|
|
5246
|
+
} catch {
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
const item = browserFromDesktop(text, kind, f);
|
|
5250
|
+
if (item) usable(item);
|
|
5355
5251
|
}
|
|
5356
|
-
if (!exec.runDetail("systemctl", ["--user", "daemon-reload"], { timeoutMs: 15e3 }).ok) errors.push("daemon-reload");
|
|
5357
|
-
return { ok: unlinkOk && errors.length === 0, errors };
|
|
5358
|
-
},
|
|
5359
|
-
/** 以 transient 单元启动(独立 cgroup;每实例隔离)。
|
|
5360
|
-
* @param {{unit:string, cmd:string[], env?:object, props?:string[], workingDir?:string, description?:string, timeoutMs?:number}} o
|
|
5361
|
-
* props 为 systemd 属性(如 KillMode=process、MemoryMax=8G),平台层只拼装成 --property,不解释语义。 */
|
|
5362
|
-
startTransient(o) {
|
|
5363
|
-
const opts = o || {};
|
|
5364
|
-
const bad = unitNameViolation(opts.unit);
|
|
5365
|
-
if (bad) throw new Error("systemd-run \u62D2\u7EDD: " + bad);
|
|
5366
|
-
const args = ["--user", "--unit=" + opts.unit];
|
|
5367
|
-
if (opts.description) args.push("--description=" + opts.description);
|
|
5368
|
-
for (const p of opts.props || []) args.push("--property=" + p);
|
|
5369
|
-
for (const [k, v] of Object.entries(opts.env || {})) args.push("--setenv=" + k + "=" + v);
|
|
5370
|
-
if (opts.workingDir) args.push("--working-directory=" + opts.workingDir);
|
|
5371
|
-
args.push("--", ...opts.cmd || []);
|
|
5372
|
-
const r = exec.runDetail("systemd-run", args, { timeoutMs: opts.timeoutMs || 2e4 });
|
|
5373
|
-
if (!r.ok) throw new Error("systemd-run \u5931\u8D25: " + (r.error || "unknown") + (r.stderr ? " | " + String(r.stderr).trim() : ""));
|
|
5374
|
-
return true;
|
|
5375
|
-
},
|
|
5376
|
-
/** 运行期改限额(W3 动态化):systemctl --user set-property 立即生效,无需重启单元。
|
|
5377
|
-
* 必带 --runtime:transient 单元本不落盘,不带它会把 drop-in 写进用户配置目录,陈旧下限永久黏住。
|
|
5378
|
-
* 值只来自 sandbox.unitProps 同源的 alloc(平台层翻译语义、不决定数额)。 */
|
|
5379
|
-
setLimits(unit, alloc) {
|
|
5380
|
-
if (unitNameViolation(unit)) return false;
|
|
5381
|
-
const a = alloc || {};
|
|
5382
|
-
const props = [];
|
|
5383
|
-
if (a.memoryMax) props.push("MemoryMax=" + a.memoryMax);
|
|
5384
|
-
if (a.memoryHigh) props.push("MemoryHigh=" + a.memoryHigh);
|
|
5385
|
-
if (a.cpuQuota) props.push("CPUQuota=" + a.cpuQuota);
|
|
5386
|
-
if (!props.length) return false;
|
|
5387
|
-
return exec.runDetail(
|
|
5388
|
-
"systemctl",
|
|
5389
|
-
["--user", "set-property", "--runtime", unit].concat(props),
|
|
5390
|
-
{ timeoutMs: 1e4 }
|
|
5391
|
-
).ok;
|
|
5392
5252
|
}
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
}
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5253
|
+
let defaultId = null;
|
|
5254
|
+
let defaultSource = null;
|
|
5255
|
+
const fromMime = linuxDefaultFromMimeApps(readFile, exists, env, home, note);
|
|
5256
|
+
if (fromMime) {
|
|
5257
|
+
const item = usable(fromMime);
|
|
5258
|
+
if (item) {
|
|
5259
|
+
defaultId = item.id;
|
|
5260
|
+
defaultSource = "mimeapps";
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5264
|
+
const desktopId = id && String(id).trim();
|
|
5265
|
+
if (!defaultId && desktopId && /^[A-Za-z0-9._-]+\.desktop$/.test(desktopId)) {
|
|
5266
|
+
for (const { dir } of desktopDirs(env, home)) {
|
|
5267
|
+
const p = PJ(dir, desktopId);
|
|
5268
|
+
let text = null;
|
|
5269
|
+
try {
|
|
5270
|
+
if (exists(p)) text = readFile(p);
|
|
5271
|
+
} catch {
|
|
5272
|
+
continue;
|
|
5273
|
+
}
|
|
5274
|
+
if (text === null) continue;
|
|
5275
|
+
const item = browserFromDesktop(text, "xdg-settings", desktopId);
|
|
5276
|
+
const used = item && usable(item);
|
|
5277
|
+
if (used) {
|
|
5278
|
+
defaultId = used.id;
|
|
5279
|
+
defaultSource = "xdg-settings";
|
|
5280
|
+
break;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
if (!desktopId) note("xdg-settings", "\u65E0\u8F93\u51FA");
|
|
5285
|
+
else if (defaultSource === "xdg-settings") note("xdg-settings", "\u9ED8\u8BA4=" + defaultId);
|
|
5286
|
+
else note("xdg-settings", "\u62A5\u51FA " + desktopId + (defaultId ? "\uFF08\u9ED8\u8BA4\u5DF2\u7531 " + defaultSource + " \u5B9A\u51FA\uFF09" : " \u4F46\u4E0D\u53EF\u7528"));
|
|
5287
|
+
if (!defaultId && found.size === 1) {
|
|
5288
|
+
defaultId = [...found.keys()][0];
|
|
5289
|
+
defaultSource = "only-installed";
|
|
5290
|
+
}
|
|
5291
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5292
|
+
}
|
|
5293
|
+
function linuxDefaultFromMimeApps(readFile, exists, env, home, note) {
|
|
5294
|
+
const cfgHome = env.XDG_CONFIG_HOME || PJ(home, ".config");
|
|
5295
|
+
const cfgDirs = String(env.XDG_CONFIG_DIRS || "/etc/xdg").split(":").filter(Boolean);
|
|
5296
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5297
|
+
const files = [
|
|
5298
|
+
PJ(cfgHome, "mimeapps.list"),
|
|
5299
|
+
...cfgDirs.map((d) => PJ(d, "mimeapps.list")),
|
|
5300
|
+
...dataDirs.map((d) => PJ(d, "applications", "mimeapps.list"))
|
|
5301
|
+
];
|
|
5302
|
+
for (const f of files) {
|
|
5303
|
+
if (!exists(f)) continue;
|
|
5304
|
+
let text = null;
|
|
5305
|
+
try {
|
|
5306
|
+
text = readFile(f);
|
|
5307
|
+
} catch {
|
|
5308
|
+
continue;
|
|
5423
5309
|
}
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5310
|
+
const id = mimeAppsDefault(text);
|
|
5311
|
+
if (!id) continue;
|
|
5312
|
+
note("mimeapps", path2.basename(f) + " -> " + id);
|
|
5313
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5314
|
+
const p = PJ(dir, id);
|
|
5315
|
+
if (!exists(p)) continue;
|
|
5316
|
+
let dt = null;
|
|
5317
|
+
try {
|
|
5318
|
+
dt = readFile(p);
|
|
5319
|
+
} catch {
|
|
5320
|
+
continue;
|
|
5321
|
+
}
|
|
5322
|
+
const item = browserFromDesktop(dt, kind, id);
|
|
5323
|
+
if (item) return item;
|
|
5324
|
+
}
|
|
5325
|
+
return null;
|
|
5431
5326
|
}
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
function current() {
|
|
5435
|
-
if (PLATFORM === "linux") return hasSystemdRun() ? systemd : portable;
|
|
5436
|
-
if (PLATFORM === "darwin" || PLATFORM === "win32") return portable;
|
|
5437
|
-
return NONE;
|
|
5438
|
-
}
|
|
5439
|
-
module2.exports = { current, CapabilityError, kind: () => current().kind, PLATFORM, UNIT_NAME_RE, unitNameViolation, _testProviders: { systemd, portable, NONE } };
|
|
5440
|
-
}
|
|
5441
|
-
});
|
|
5442
|
-
|
|
5443
|
-
// src/platform/os/notify.js
|
|
5444
|
-
var require_notify = __commonJS({
|
|
5445
|
-
"src/platform/os/notify.js"(exports2, module2) {
|
|
5446
|
-
"use strict";
|
|
5447
|
-
var spawnOS = require_spawn();
|
|
5448
|
-
function appleScriptString(s) {
|
|
5449
|
-
return JSON.stringify(String(s));
|
|
5450
|
-
}
|
|
5451
|
-
function powerShellString(s) {
|
|
5452
|
-
return "'" + String(s).replace(/'/g, "''") + "'";
|
|
5327
|
+
note("mimeapps", "\u65E0\u9ED8\u8BA4\u9879");
|
|
5328
|
+
return null;
|
|
5453
5329
|
}
|
|
5454
|
-
function
|
|
5455
|
-
|
|
5456
|
-
const
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
const
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
const ps = [
|
|
5467
|
-
'[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null',
|
|
5468
|
-
'[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null',
|
|
5469
|
-
"$n = New-Object System.Windows.Forms.NotifyIcon",
|
|
5470
|
-
"$n.Icon = [System.Drawing.SystemIcons]::Information",
|
|
5471
|
-
"$n.Visible = $true",
|
|
5472
|
-
"$n.ShowBalloonTip(4000, " + powerShellString(t) + ", " + powerShellString(b) + ", [System.Windows.Forms.ToolTipIcon]::None)",
|
|
5473
|
-
"Start-Sleep -Milliseconds 4200",
|
|
5474
|
-
"$n.Dispose(); $n.Visible = $false"
|
|
5475
|
-
].join("; ");
|
|
5476
|
-
return { cmd: "powershell", args: ["-NoProfile", "-NonInteractive", "-Command", ps] };
|
|
5330
|
+
function mimeAppsDefault(text) {
|
|
5331
|
+
let inDefault = false;
|
|
5332
|
+
for (const line of String(text || "").split(/\r?\n/)) {
|
|
5333
|
+
if (/^\s*\[/.test(line)) {
|
|
5334
|
+
inDefault = /^\s*\[Default Applications\]\s*$/.test(line);
|
|
5335
|
+
continue;
|
|
5336
|
+
}
|
|
5337
|
+
if (!inDefault) continue;
|
|
5338
|
+
const m = line.match(/^\s*x-scheme-handler\/https?\s*=\s*(.*)$/i);
|
|
5339
|
+
if (!m) continue;
|
|
5340
|
+
const ids = m[1].split(";").map((s) => s.trim()).filter((s) => /^[A-Za-z0-9._-]+\.desktop$/.test(s));
|
|
5341
|
+
if (ids.length) return ids[0];
|
|
5477
5342
|
}
|
|
5478
5343
|
return null;
|
|
5479
5344
|
}
|
|
5480
|
-
function
|
|
5345
|
+
function probe(platform, d) {
|
|
5346
|
+
const pl = platform || process.platform;
|
|
5347
|
+
const dd = Object.assign({}, d, { canExec: d.canExec || ((p) => isExecutableFile(p, pl)) });
|
|
5348
|
+
if (pl === "win32") return probeWin(dd);
|
|
5349
|
+
if (pl === "darwin") return probeMac(dd);
|
|
5350
|
+
return probeLinux(dd);
|
|
5351
|
+
}
|
|
5352
|
+
var CACHE = /* @__PURE__ */ Object.create(null);
|
|
5353
|
+
function inventory(platform, o) {
|
|
5354
|
+
const ov = o || {};
|
|
5355
|
+
const pl = platform || process.platform;
|
|
5356
|
+
const now = ov.now || (() => Date.now());
|
|
5357
|
+
const ttl = ov.ttlMs === void 0 ? 6e4 : ov.ttlMs;
|
|
5358
|
+
const cached = CACHE[pl];
|
|
5359
|
+
if (!ov.force && cached && now() - cached.at < ttl) return Object.assign({ cached: true }, cached.value);
|
|
5360
|
+
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: PROBE_TIMEOUT_MS }));
|
|
5361
|
+
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
5362
|
+
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
5363
|
+
const listDir = ov.listDir || ((p) => fs2.readdirSync(p));
|
|
5364
|
+
let value;
|
|
5481
5365
|
try {
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
c.on("error", () => {
|
|
5486
|
-
if (onError) onError();
|
|
5487
|
-
});
|
|
5488
|
-
c.unref();
|
|
5489
|
-
return true;
|
|
5490
|
-
} catch {
|
|
5491
|
-
if (onError) onError();
|
|
5492
|
-
return false;
|
|
5366
|
+
value = probe(pl, { runOut, readFile, exists, listDir, canExec: ov.canExec, env: ov.env || process.env, home: ov.home || os2.homedir() });
|
|
5367
|
+
} catch (e) {
|
|
5368
|
+
value = { browsers: [], defaultId: null, defaultSource: null, probed: [{ source: "probe-error", detail: String(e && e.message || e) }] };
|
|
5493
5369
|
}
|
|
5370
|
+
value.at = now();
|
|
5371
|
+
value.platform = pl;
|
|
5372
|
+
value.browsers.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
5373
|
+
CACHE[pl] = { at: now(), value };
|
|
5374
|
+
return Object.assign({ cached: false }, value);
|
|
5494
5375
|
}
|
|
5495
|
-
|
|
5376
|
+
function invalidate(platform) {
|
|
5377
|
+
if (platform) delete CACHE[platform];
|
|
5378
|
+
else for (const k of Object.keys(CACHE)) delete CACHE[k];
|
|
5379
|
+
}
|
|
5380
|
+
module2.exports = {
|
|
5381
|
+
inventory,
|
|
5382
|
+
invalidate,
|
|
5383
|
+
probe,
|
|
5384
|
+
probeWin,
|
|
5385
|
+
probeMac,
|
|
5386
|
+
probeLinux,
|
|
5387
|
+
engineOf,
|
|
5388
|
+
tokenizeExec,
|
|
5389
|
+
parseExecLine,
|
|
5390
|
+
regValueOf,
|
|
5391
|
+
expandEnvVars,
|
|
5392
|
+
exeFromCmdLine,
|
|
5393
|
+
regSubkeys,
|
|
5394
|
+
regKeyFull,
|
|
5395
|
+
regValueTargets,
|
|
5396
|
+
safeRegKeyPart,
|
|
5397
|
+
browserFromDesktop,
|
|
5398
|
+
desktopDirs,
|
|
5399
|
+
resolveLinuxBin,
|
|
5400
|
+
mimeAppsDefault,
|
|
5401
|
+
linuxDefaultFromMimeApps,
|
|
5402
|
+
WIN_APP_PATHS,
|
|
5403
|
+
PROBE_TIMEOUT_MS
|
|
5404
|
+
};
|
|
5496
5405
|
}
|
|
5497
5406
|
});
|
|
5498
5407
|
|
|
5499
|
-
// src/platform/os/
|
|
5500
|
-
var
|
|
5501
|
-
"src/platform/os/
|
|
5408
|
+
// src/platform/os/environment.js
|
|
5409
|
+
var require_environment = __commonJS({
|
|
5410
|
+
"src/platform/os/environment.js"(exports2, module2) {
|
|
5502
5411
|
"use strict";
|
|
5503
5412
|
var fs2 = require("node:fs");
|
|
5504
|
-
var path2 = require("node:path");
|
|
5505
5413
|
var os2 = require("node:os");
|
|
5506
|
-
var
|
|
5507
|
-
var
|
|
5508
|
-
var
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5414
|
+
var path2 = require("node:path");
|
|
5415
|
+
var stateRoot2 = require_state_root();
|
|
5416
|
+
var { writeAtomic } = require_fs();
|
|
5417
|
+
var desktop = require_desktop();
|
|
5418
|
+
var detector = require_browser_inventory();
|
|
5419
|
+
var { engineOf } = detector;
|
|
5420
|
+
var SCHEMA = 1;
|
|
5421
|
+
var FILE_NAME = "environment.json";
|
|
5422
|
+
var FORM_TTL_MS = 6e4;
|
|
5423
|
+
var _sources = {};
|
|
5424
|
+
function bind(sources) {
|
|
5425
|
+
_sources = Object.assign({}, _sources, sources || {});
|
|
5426
|
+
return _sources;
|
|
5427
|
+
}
|
|
5428
|
+
function preferenceId() {
|
|
5429
|
+
const f = _sources.preference;
|
|
5430
|
+
if (typeof f !== "function") return null;
|
|
5431
|
+
const v = f();
|
|
5432
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
5514
5433
|
}
|
|
5515
|
-
function
|
|
5516
|
-
const
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
let esc = false;
|
|
5520
|
-
let has = false;
|
|
5521
|
-
for (const ch of String(line)) {
|
|
5522
|
-
if (esc) {
|
|
5523
|
-
cur += ch;
|
|
5524
|
-
esc = false;
|
|
5525
|
-
continue;
|
|
5526
|
-
}
|
|
5527
|
-
if (ch === "\\") {
|
|
5528
|
-
esc = true;
|
|
5529
|
-
has = true;
|
|
5530
|
-
continue;
|
|
5531
|
-
}
|
|
5532
|
-
if (q) {
|
|
5533
|
-
if (ch === q) q = null;
|
|
5534
|
-
else cur += ch;
|
|
5535
|
-
continue;
|
|
5536
|
-
}
|
|
5537
|
-
if (ch === "'" || ch === '"') {
|
|
5538
|
-
q = ch;
|
|
5539
|
-
has = true;
|
|
5540
|
-
continue;
|
|
5541
|
-
}
|
|
5542
|
-
if (/\s/.test(ch)) {
|
|
5543
|
-
if (has) {
|
|
5544
|
-
toks.push(cur);
|
|
5545
|
-
cur = "";
|
|
5546
|
-
has = false;
|
|
5547
|
-
}
|
|
5548
|
-
continue;
|
|
5549
|
-
}
|
|
5550
|
-
cur += ch;
|
|
5551
|
-
has = true;
|
|
5552
|
-
}
|
|
5553
|
-
if (has) toks.push(cur);
|
|
5554
|
-
return toks;
|
|
5434
|
+
function capabilities() {
|
|
5435
|
+
const f = _sources.capabilities;
|
|
5436
|
+
if (typeof f !== "function") return null;
|
|
5437
|
+
return f() || null;
|
|
5555
5438
|
}
|
|
5556
|
-
function
|
|
5557
|
-
let
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5439
|
+
function identity() {
|
|
5440
|
+
let user = null;
|
|
5441
|
+
try {
|
|
5442
|
+
user = os2.userInfo().username;
|
|
5443
|
+
} catch {
|
|
5444
|
+
user = process.env.USER || process.env.USERNAME || null;
|
|
5562
5445
|
}
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
function expandEnvVars(value, env) {
|
|
5572
|
-
const e = env || process.env;
|
|
5573
|
-
return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
|
|
5574
|
-
}
|
|
5575
|
-
function exeFromCmdLine(cmdLine) {
|
|
5576
|
-
const s = String(cmdLine || "");
|
|
5577
|
-
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
5578
|
-
if (m) return m[1];
|
|
5579
|
-
m = s.match(/^\s*(.*?\.exe)/i);
|
|
5580
|
-
return m ? m[1] : null;
|
|
5446
|
+
return {
|
|
5447
|
+
platform: process.platform,
|
|
5448
|
+
arch: process.arch,
|
|
5449
|
+
hostname: os2.hostname(),
|
|
5450
|
+
user: user || null,
|
|
5451
|
+
home: os2.homedir(),
|
|
5452
|
+
node: process.version
|
|
5453
|
+
};
|
|
5581
5454
|
}
|
|
5582
|
-
function
|
|
5583
|
-
return
|
|
5455
|
+
function paths() {
|
|
5456
|
+
return { root: stateRoot2.root(), supervisor: stateRoot2.supervisorDir(), shell: stateRoot2.shellDir() };
|
|
5584
5457
|
}
|
|
5585
|
-
function
|
|
5586
|
-
const
|
|
5587
|
-
const
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5458
|
+
function normalizeInventory(inv, platform) {
|
|
5459
|
+
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
5460
|
+
const defaultId = inv && inv.defaultId ? inv.defaultId : null;
|
|
5461
|
+
return {
|
|
5462
|
+
platform: inv && inv.platform || platform || process.platform,
|
|
5463
|
+
cached: !!(inv && inv.cached),
|
|
5464
|
+
at: inv && inv.at !== void 0 ? inv.at : null,
|
|
5465
|
+
defaultId,
|
|
5466
|
+
defaultSource: inv && inv.defaultSource || null,
|
|
5467
|
+
browsers: list.map((b) => ({
|
|
5468
|
+
id: b.id,
|
|
5469
|
+
name: b.name,
|
|
5470
|
+
bin: b.bin,
|
|
5471
|
+
engine: b.engine || engineOf(b.bin),
|
|
5472
|
+
baseArgs: b.baseArgs || [],
|
|
5473
|
+
sources: b.sources && b.sources.length ? b.sources : [b.source || "unknown"],
|
|
5474
|
+
isDefault: !!defaultId && b.id === defaultId
|
|
5475
|
+
})),
|
|
5476
|
+
probed: inv && inv.probed || []
|
|
5477
|
+
};
|
|
5591
5478
|
}
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
const
|
|
5595
|
-
|
|
5596
|
-
const
|
|
5597
|
-
return (
|
|
5479
|
+
function browsers(o) {
|
|
5480
|
+
const ov = o || {};
|
|
5481
|
+
const pl = ov.platform || process.platform;
|
|
5482
|
+
if (ov.inventory) return normalizeInventory(ov.inventory, pl);
|
|
5483
|
+
const resolve = typeof ov.resolveInventory === "function" ? ov.resolveInventory : ((platform, deps) => detector.inventory(platform, deps));
|
|
5484
|
+
return normalizeInventory(resolve(pl, ov.resolveDeps || {}), pl);
|
|
5485
|
+
}
|
|
5486
|
+
var ENGINE_RANK = { chromium: 0, firefox: 1, other: 2 };
|
|
5487
|
+
function rankCandidates(list) {
|
|
5488
|
+
const rankOf = (b) => {
|
|
5489
|
+
const r = ENGINE_RANK[b && b.engine];
|
|
5490
|
+
return r === void 0 ? ENGINE_RANK.other : r;
|
|
5491
|
+
};
|
|
5492
|
+
return (Array.isArray(list) ? list : []).slice().sort((a, b) => {
|
|
5493
|
+
if (rankOf(a) !== rankOf(b)) return rankOf(a) - rankOf(b);
|
|
5494
|
+
const ia = String(a && a.id || "");
|
|
5495
|
+
const ib = String(b && b.id || "");
|
|
5496
|
+
return ia < ib ? -1 : ia > ib ? 1 : 0;
|
|
5497
|
+
});
|
|
5598
5498
|
}
|
|
5599
|
-
function
|
|
5600
|
-
const
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5499
|
+
function pickLauncher(platform, inv, preference) {
|
|
5500
|
+
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
5501
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5502
|
+
for (const b of list) byId.set(b.id, b);
|
|
5503
|
+
const wanted = preference === void 0 ? preferenceId() : typeof preference === "string" && preference ? preference : null;
|
|
5504
|
+
const stale = wanted !== null && !byId.has(wanted);
|
|
5505
|
+
const out = (browser, how) => ({ browser, how, wanted, stale });
|
|
5506
|
+
if (wanted !== null && byId.has(wanted)) return out(byId.get(wanted), "user-preference");
|
|
5507
|
+
const sys = inv && inv.defaultId ? byId.get(inv.defaultId) : null;
|
|
5508
|
+
if (sys) return out(sys, inv.defaultSource || "default");
|
|
5509
|
+
if (list.length === 1) return out(list[0], "only-installed");
|
|
5510
|
+
if (list.length > 1) return out(rankCandidates(list)[0], "candidate-rank");
|
|
5511
|
+
return out(null, "none-found");
|
|
5512
|
+
}
|
|
5513
|
+
function snapshotPath() {
|
|
5514
|
+
return path2.join(stateRoot2.supervisorDir(), FILE_NAME);
|
|
5515
|
+
}
|
|
5516
|
+
function readSnapshot() {
|
|
5517
|
+
try {
|
|
5518
|
+
const doc = JSON.parse(fs2.readFileSync(snapshotPath(), "utf8"));
|
|
5519
|
+
return doc && doc.schema === SCHEMA ? doc : null;
|
|
5520
|
+
} catch {
|
|
5521
|
+
return null;
|
|
5604
5522
|
}
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5523
|
+
}
|
|
5524
|
+
var _formCache = null;
|
|
5525
|
+
function form(o) {
|
|
5526
|
+
const ov = o || {};
|
|
5527
|
+
const now = typeof ov.now === "function" ? ov.now : (() => Date.now());
|
|
5528
|
+
const stamp = now();
|
|
5529
|
+
const ttl = ov.ttlMs === void 0 ? FORM_TTL_MS : ov.ttlMs;
|
|
5530
|
+
if (!ov.force && _formCache && stamp - _formCache.at < ttl) {
|
|
5531
|
+
return Object.assign({}, _formCache.value, { cached: true });
|
|
5532
|
+
}
|
|
5533
|
+
const inv = browsers(ov);
|
|
5534
|
+
const caps = capabilities();
|
|
5535
|
+
const session = desktop.describe();
|
|
5536
|
+
const prefId = preferenceId();
|
|
5537
|
+
const prefEntry = prefId ? inv.browsers.find((b) => b.id === prefId) || null : null;
|
|
5538
|
+
const preference = {
|
|
5539
|
+
id: prefId,
|
|
5540
|
+
configured: !!prefId,
|
|
5541
|
+
matched: !!prefEntry,
|
|
5542
|
+
browser: prefEntry ? { id: prefEntry.id, name: prefEntry.name, engine: prefEntry.engine } : null,
|
|
5543
|
+
reason: !prefId ? "not-set" : prefEntry ? "matched" : "stale"
|
|
5544
|
+
};
|
|
5545
|
+
const pick = pickLauncher(inv.platform, inv, prefId);
|
|
5546
|
+
const probed = inv.probed.map((p) => ({ section: "browsers", source: p.source, detail: p.detail }));
|
|
5547
|
+
probed.push({ section: "session", source: "desktop", detail: session.reason + (session.available ? "\uFF08\u53EF\u7528\uFF09" : "\uFF08\u4E0D\u53EF\u7528\uFF09") });
|
|
5548
|
+
probed.push({
|
|
5549
|
+
section: "capabilities",
|
|
5550
|
+
source: "profile",
|
|
5551
|
+
detail: caps ? "openBrowser=" + (caps.openBrowser === true) : "\u672A\u7ED1\u5B9A\u80FD\u529B\u77E9\u9635\uFF08\u7531 platform/os/index.js \u88C5\u914D\u671F\u6CE8\u5165\uFF09"
|
|
5552
|
+
});
|
|
5553
|
+
probed.push({
|
|
5554
|
+
section: "preference",
|
|
5555
|
+
source: "config",
|
|
5556
|
+
detail: preference.reason === "not-set" ? "\u672A\u8BBE\u7F6E\uFF0C\u6309\u7CFB\u7EDF\u9ED8\u8BA4\u6216\u5019\u9009\u6B21\u5E8F\u5206\u53D1" : preference.reason === "matched" ? "\u5DF2\u9009 " + preference.browser.name : "\u504F\u597D\u6240\u6307\u5DF2\u4E0D\u5728\u5019\u9009\u6E05\u5355: " + prefId
|
|
5557
|
+
});
|
|
5558
|
+
probed.push({
|
|
5559
|
+
section: "pick",
|
|
5560
|
+
source: "form",
|
|
5561
|
+
detail: pick.how + (pick.browser ? "\uFF08" + pick.browser.name + "\uFF09" : "\uFF08\u65E0\u5019\u9009\uFF09") + (pick.stale ? "\uFF0C\u504F\u597D\u5DF2\u5931\u6548\u9700\u91CD\u9009" : "")
|
|
5562
|
+
});
|
|
5563
|
+
const value = {
|
|
5564
|
+
schema: SCHEMA,
|
|
5565
|
+
at: stamp,
|
|
5566
|
+
platform: inv.platform,
|
|
5567
|
+
identity: identity(),
|
|
5568
|
+
paths: paths(),
|
|
5569
|
+
session,
|
|
5570
|
+
capabilities: caps,
|
|
5571
|
+
preference,
|
|
5572
|
+
default: inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource } : null,
|
|
5573
|
+
browsers: inv.browsers,
|
|
5574
|
+
pick: { how: pick.how, id: pick.browser ? pick.browser.id : null, name: pick.browser ? pick.browser.name : null, wanted: pick.wanted, stale: pick.stale },
|
|
5575
|
+
probed
|
|
5576
|
+
};
|
|
5577
|
+
const snapshot = { path: snapshotPath(), written: false, error: null };
|
|
5578
|
+
if (ov.persist === true) {
|
|
5579
|
+
try {
|
|
5580
|
+
writeAtomic(snapshot.path, JSON.stringify(value, null, 2) + "\n", { mode: 384 });
|
|
5581
|
+
snapshot.written = true;
|
|
5582
|
+
} catch (e) {
|
|
5583
|
+
snapshot.error = String(e && e.message || e);
|
|
5584
|
+
}
|
|
5585
|
+
probed.push({
|
|
5586
|
+
section: "snapshot",
|
|
5587
|
+
source: FILE_NAME,
|
|
5588
|
+
detail: snapshot.written ? "\u5DF2\u843D\u76D8 " + snapshot.path : "\u843D\u76D8\u5931\u8D25: " + snapshot.error
|
|
5589
|
+
});
|
|
5613
5590
|
}
|
|
5614
|
-
|
|
5615
|
-
|
|
5591
|
+
value.snapshot = snapshot;
|
|
5592
|
+
_formCache = { at: stamp, value };
|
|
5593
|
+
return Object.assign({ cached: false }, value);
|
|
5616
5594
|
}
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5595
|
+
function invalidate(platform) {
|
|
5596
|
+
_formCache = null;
|
|
5597
|
+
return detector.invalidate(platform);
|
|
5598
|
+
}
|
|
5599
|
+
function checkPreference(value, form2) {
|
|
5600
|
+
const candidates = (form2 && form2.browsers || []).map((b) => ({
|
|
5601
|
+
id: b.id,
|
|
5602
|
+
name: b.name,
|
|
5603
|
+
engine: b.engine,
|
|
5604
|
+
isDefault: b.isDefault === true
|
|
5605
|
+
}));
|
|
5606
|
+
const id = typeof value === "string" ? value.trim() : "";
|
|
5607
|
+
if (!id) return { ok: true, id: null, browser: null, candidates };
|
|
5608
|
+
const hit = candidates.find((c) => c.id === id);
|
|
5609
|
+
if (!hit) {
|
|
5610
|
+
return { ok: false, id: null, browser: null, candidates, error: "\u8BE5\u6D4F\u89C8\u5668\u4E0D\u5728\u672C\u673A\u5019\u9009\u6E05\u5355\u91CC\uFF08\u53EF\u80FD\u5DF2\u5378\u8F7D\u6216\u8DEF\u5F84\u5931\u6548\uFF09\uFF0C\u8BF7\u5148\u5237\u65B0\u73AF\u5883\u8868\u5355" };
|
|
5624
5611
|
}
|
|
5625
|
-
return
|
|
5612
|
+
return { ok: true, id: hit.id, browser: hit, candidates };
|
|
5626
5613
|
}
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5614
|
+
module2.exports = {
|
|
5615
|
+
SCHEMA,
|
|
5616
|
+
FILE_NAME,
|
|
5617
|
+
FORM_TTL_MS,
|
|
5618
|
+
bind,
|
|
5619
|
+
preferenceId,
|
|
5620
|
+
capabilities,
|
|
5621
|
+
identity,
|
|
5622
|
+
paths,
|
|
5623
|
+
browsers,
|
|
5624
|
+
normalizeInventory,
|
|
5625
|
+
rankCandidates,
|
|
5626
|
+
pickLauncher,
|
|
5627
|
+
checkPreference,
|
|
5628
|
+
form,
|
|
5629
|
+
snapshotPath,
|
|
5630
|
+
readSnapshot,
|
|
5631
|
+
invalidate
|
|
5632
|
+
};
|
|
5633
|
+
}
|
|
5634
|
+
});
|
|
5635
|
+
|
|
5636
|
+
// src/platform/os/process.js
|
|
5637
|
+
var require_process = __commonJS({
|
|
5638
|
+
"src/platform/os/process.js"(exports2, module2) {
|
|
5639
|
+
"use strict";
|
|
5640
|
+
var ex2 = require_exec();
|
|
5641
|
+
var isWindows = process.platform === "win32";
|
|
5642
|
+
function signalProcess(pid, sig) {
|
|
5643
|
+
if (!Number.isInteger(pid) || pid <= 0) return;
|
|
5644
|
+
if (isWindows) {
|
|
5645
|
+
try {
|
|
5646
|
+
process.kill(pid, sig);
|
|
5647
|
+
} catch {
|
|
5650
5648
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
}
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
if (!safeRegKeyPart(s)) return;
|
|
5660
|
-
if (progIds.get(s) === "userchoice") return;
|
|
5661
|
-
progIds.set(s, how);
|
|
5662
|
-
};
|
|
5663
|
-
let defaultId = null;
|
|
5664
|
-
let defaultSource = null;
|
|
5665
|
-
const DEF_RANK = { userchoice: 1, "scheme-association": 2, "only-installed": 9 };
|
|
5666
|
-
let defRank = 99;
|
|
5667
|
-
const setDefault = (item, how) => {
|
|
5668
|
-
const r = DEF_RANK[how] === void 0 ? 99 : DEF_RANK[how];
|
|
5669
|
-
if (item && r < defRank) {
|
|
5670
|
-
defRank = r;
|
|
5671
|
-
defaultId = item.id;
|
|
5672
|
-
defaultSource = how;
|
|
5649
|
+
return;
|
|
5650
|
+
}
|
|
5651
|
+
try {
|
|
5652
|
+
process.kill(-pid, sig);
|
|
5653
|
+
} catch {
|
|
5654
|
+
try {
|
|
5655
|
+
process.kill(pid, sig);
|
|
5656
|
+
} catch {
|
|
5673
5657
|
}
|
|
5674
|
-
};
|
|
5675
|
-
const cmdToExe = (raw) => raw ? exeFromCmdLine(expandEnvVars(raw, env)) : null;
|
|
5676
|
-
const uc = regValue(runOut, note, "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice", "ProgId");
|
|
5677
|
-
if (uc) addProgId(uc, "userchoice");
|
|
5678
|
-
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
5679
|
-
const pid = regValue(runOut, note, root + "\\https");
|
|
5680
|
-
if (pid) addProgId(pid, "scheme-association");
|
|
5681
|
-
const exe = cmdToExe(regValue(runOut, note, root + "\\https\\shell\\open\\command"));
|
|
5682
|
-
if (exe) setDefault(push(exe, "scheme-association"), "scheme-association");
|
|
5683
5658
|
}
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
if (
|
|
5659
|
+
}
|
|
5660
|
+
function killTree(pid, sig, cb, opts) {
|
|
5661
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
5662
|
+
if (cb) cb(new Error("invalid pid"));
|
|
5663
|
+
return;
|
|
5688
5664
|
}
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
if (pid) addProgId(pid, "registered-apps");
|
|
5695
|
-
}
|
|
5665
|
+
if (isWindows) {
|
|
5666
|
+
ex2.runAsync("taskkill", ["/PID", String(pid), "/T", "/F"], { timeoutMs: 1e4 }).then((r) => {
|
|
5667
|
+
if (cb) cb(r.ok ? null : new Error(r.error || "taskkill failed"));
|
|
5668
|
+
});
|
|
5669
|
+
return;
|
|
5696
5670
|
}
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5671
|
+
if (opts && opts.ownGroup === true) {
|
|
5672
|
+
signalProcess(pid, sig || "SIGTERM");
|
|
5673
|
+
} else {
|
|
5674
|
+
try {
|
|
5675
|
+
process.kill(pid, sig || "SIGTERM");
|
|
5676
|
+
} catch {
|
|
5701
5677
|
}
|
|
5702
5678
|
}
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5679
|
+
if (cb) process.nextTick(cb, null);
|
|
5680
|
+
}
|
|
5681
|
+
module2.exports = { signalProcess, killTree };
|
|
5682
|
+
}
|
|
5683
|
+
});
|
|
5684
|
+
|
|
5685
|
+
// src/platform/os/file-protect.js
|
|
5686
|
+
var require_file_protect = __commonJS({
|
|
5687
|
+
"src/platform/os/file-protect.js"(exports2, module2) {
|
|
5688
|
+
"use strict";
|
|
5689
|
+
var fs2 = require("node:fs");
|
|
5690
|
+
var os2 = require("node:os");
|
|
5691
|
+
var path2 = require("node:path");
|
|
5692
|
+
var ex2 = require_exec();
|
|
5693
|
+
var IS_WINDOWS2 = process.platform === "win32";
|
|
5694
|
+
var _icacls = null;
|
|
5695
|
+
function hasIcacls(platform) {
|
|
5696
|
+
if ((platform || process.platform) !== "win32") return false;
|
|
5697
|
+
if (_icacls !== null) return _icacls;
|
|
5698
|
+
_icacls = ex2.runOut("icacls", ["/?"], { timeoutMs: 3e3 }) !== null;
|
|
5699
|
+
return _icacls;
|
|
5700
|
+
}
|
|
5701
|
+
function currentUser() {
|
|
5702
|
+
return process.env.USERNAME || process.env.USER || (() => {
|
|
5703
|
+
try {
|
|
5704
|
+
return os2.userInfo().username;
|
|
5705
|
+
} catch {
|
|
5706
|
+
return null;
|
|
5707
|
+
}
|
|
5708
|
+
})();
|
|
5709
|
+
}
|
|
5710
|
+
function protectFile(file) {
|
|
5711
|
+
if (!IS_WINDOWS2) {
|
|
5712
|
+
try {
|
|
5713
|
+
fs2.chmodSync(file, 384);
|
|
5714
|
+
return { ok: true, mode: "posix-0600" };
|
|
5715
|
+
} catch (e) {
|
|
5716
|
+
return { ok: false, mode: "posix-0600", reason: e.message };
|
|
5717
|
+
}
|
|
5708
5718
|
}
|
|
5709
|
-
if (
|
|
5710
|
-
|
|
5719
|
+
if (!hasIcacls()) return { ok: false, mode: "none", reason: "icacls \u4E0D\u53EF\u7528" };
|
|
5720
|
+
const user = currentUser();
|
|
5721
|
+
if (!user) return { ok: false, mode: "icacls", reason: "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u7528\u6237" };
|
|
5722
|
+
const r = ex2.runDetail("icacls", [file, "/inheritance:r", "/grant:r", user + ":F"], { stdio: "ignore", timeoutMs: 5e3 });
|
|
5723
|
+
return r.ok ? { ok: true, mode: "icacls-file" } : { ok: false, mode: "icacls-file", reason: r.error || "\u9000\u51FA\u7801 " + r.code };
|
|
5711
5724
|
}
|
|
5712
|
-
function
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5725
|
+
function protectDir(dir) {
|
|
5726
|
+
if (!IS_WINDOWS2) {
|
|
5727
|
+
try {
|
|
5728
|
+
fs2.chmodSync(dir, 448);
|
|
5729
|
+
return { ok: true, mode: "posix-0700" };
|
|
5730
|
+
} catch (e) {
|
|
5731
|
+
return { ok: false, mode: "posix-0700", reason: e.message };
|
|
5732
|
+
}
|
|
5717
5733
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5734
|
+
if (!hasIcacls()) return { ok: false, mode: "none", reason: "icacls \u4E0D\u53EF\u7528" };
|
|
5735
|
+
const user = currentUser();
|
|
5736
|
+
if (!user) return { ok: false, mode: "icacls", reason: "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u7528\u6237" };
|
|
5737
|
+
const r = ex2.runDetail("icacls", [dir, "/inheritance:r", "/grant:r", user + ":(OI)(CI)F"], { stdio: "ignore", timeoutMs: 1e4 });
|
|
5738
|
+
return r.ok ? { ok: true, mode: "icacls-dir" } : { ok: false, mode: "icacls-dir", reason: r.error || "\u9000\u51FA\u7801 " + r.code };
|
|
5739
|
+
}
|
|
5740
|
+
function ensurePrivateDir(dir) {
|
|
5741
|
+
try {
|
|
5742
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
5743
|
+
} catch (e) {
|
|
5744
|
+
return { ok: false, mode: "mkdir", reason: e.message };
|
|
5726
5745
|
}
|
|
5727
|
-
|
|
5728
|
-
return paths;
|
|
5746
|
+
return protectDir(dir);
|
|
5729
5747
|
}
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
"var list=null;",
|
|
5737
|
-
"try{list=ws.urlsForApplicationsToOpenURL(u);}catch(e){}",
|
|
5738
|
-
"if(list===null||typeof list.count!=='number'){if(def){out.push(def+'\\t\\t1');}}else{",
|
|
5739
|
-
"var n=Number(list.count);",
|
|
5740
|
-
"for(var i=0;i<n;i++){",
|
|
5741
|
-
"var p=ObjC.unwrap(list.objectAtIndex(i).path)||''; if(!p) continue;",
|
|
5742
|
-
"var exe='';var bid='';",
|
|
5743
|
-
"var b=$.NSBundle.bundleWithPath(p);",
|
|
5744
|
-
"if(!b.isNil()){exe=ObjC.unwrap(b.executablePath)||'';bid=ObjC.unwrap(b.bundleIdentifier)||'';}",
|
|
5745
|
-
"out.push((exe||p)+'\\t'+bid+'\\t'+(p&&def&&p===def?1:0));}",
|
|
5746
|
-
"}",
|
|
5747
|
-
// 末句必须是裸表达式:osascript 取的是最后一条**语句**的值,if/else 语句不产结果,
|
|
5748
|
-
// 写在分支里会让整段查询输出空字符串(表现为「系统未报任何可用应用」)。
|
|
5749
|
-
"out.join('\\n');"
|
|
5750
|
-
].join("");
|
|
5751
|
-
function probeMac(d) {
|
|
5752
|
-
const { runOut, canExec } = d;
|
|
5753
|
-
const notes = [];
|
|
5754
|
-
const note = (source, detail) => {
|
|
5755
|
-
notes.push({ source, detail });
|
|
5756
|
-
};
|
|
5757
|
-
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA_LIST]);
|
|
5758
|
-
if (!out || !out.trim()) {
|
|
5759
|
-
note("launchservices", "\u67E5\u8BE2\u65E0\u8F93\u51FA\uFF08\u65E7\u7CFB\u7EDF\u6216\u88AB\u6743\u9650\u62E6\u622A\uFF09");
|
|
5760
|
-
return { browsers: [], defaultId: null, defaultSource: null, probed: notes };
|
|
5761
|
-
}
|
|
5762
|
-
const keyOf = (exe) => String(exe || "").toLowerCase();
|
|
5763
|
-
const found = /* @__PURE__ */ new Map();
|
|
5764
|
-
let defaultId = null;
|
|
5765
|
-
let defaultSource = null;
|
|
5766
|
-
for (const line of out.trim().split("\n")) {
|
|
5767
|
-
const parts = line.split(" ");
|
|
5768
|
-
const bin = (parts[0] || "").trim();
|
|
5769
|
-
if (!bin) continue;
|
|
5770
|
-
if (!canExec(bin)) {
|
|
5771
|
-
note("launchservices", "\u4E0D\u53EF\u6267\u884C: " + bin);
|
|
5772
|
-
continue;
|
|
5748
|
+
function writePrivate(file, data) {
|
|
5749
|
+
try {
|
|
5750
|
+
const dir = path2.dirname(file);
|
|
5751
|
+
try {
|
|
5752
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
5753
|
+
} catch {
|
|
5773
5754
|
}
|
|
5774
|
-
const
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5755
|
+
const tmp = file + ".tmp" + process.pid;
|
|
5756
|
+
fs2.writeFileSync(tmp, data, { mode: 384 });
|
|
5757
|
+
const p1 = protectFile(tmp);
|
|
5758
|
+
if (p1 && p1.ok === false) {
|
|
5759
|
+
try {
|
|
5760
|
+
fs2.rmSync(tmp, { force: true });
|
|
5761
|
+
} catch {
|
|
5781
5762
|
}
|
|
5763
|
+
return { ok: false, reason: "protect(tmp): " + (p1.reason || p1.mode), mode: p1.mode };
|
|
5782
5764
|
}
|
|
5765
|
+
fs2.renameSync(tmp, file);
|
|
5766
|
+
const p2 = protectFile(file);
|
|
5767
|
+
if (p2 && p2.ok === false) return { ok: false, reason: "protect(file): " + (p2.reason || p2.mode), mode: p2.mode };
|
|
5768
|
+
return { ok: true };
|
|
5769
|
+
} catch (e) {
|
|
5770
|
+
return { ok: false, reason: e.message };
|
|
5783
5771
|
}
|
|
5784
|
-
note("launchservices", found.size ? found.size + " \u4E2A\u53EF\u6253\u5F00 https \u7684\u5E94\u7528" : "\u7CFB\u7EDF\u672A\u62A5\u4EFB\u4F55\u53EF\u7528\u5E94\u7528");
|
|
5785
|
-
if (!defaultId && found.size === 1) {
|
|
5786
|
-
defaultId = [...found.keys()][0];
|
|
5787
|
-
defaultSource = "only-installed";
|
|
5788
|
-
}
|
|
5789
|
-
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5790
5772
|
}
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5773
|
+
module2.exports = { protectFile, protectDir, ensurePrivateDir, writePrivate, hasIcacls, currentUser, IS_WINDOWS: IS_WINDOWS2 };
|
|
5774
|
+
}
|
|
5775
|
+
});
|
|
5776
|
+
|
|
5777
|
+
// src/platform/util/input.js
|
|
5778
|
+
var require_input = __commonJS({
|
|
5779
|
+
"src/platform/util/input.js"(exports2, module2) {
|
|
5780
|
+
"use strict";
|
|
5781
|
+
var PKG_NAME_RE = /^(@[a-zA-Z0-9._-]+\/)?[a-zA-Z0-9._-]+$/;
|
|
5782
|
+
var ARGV_UNSAFE_RE = /[\s;|&<>`'"$(){}\\*?~#]/;
|
|
5783
|
+
var WIN_ABS_PATH_RE = /^[A-Za-z]:\\[^;|&<>`'"$*?~#\s]*$/;
|
|
5784
|
+
var UNIT_NAME_RE = /^[A-Za-z0-9:@._-]{1,128}$/;
|
|
5785
|
+
var UNSAFE_LEDGER_KEYS = ["__proto__", "prototype", "constructor"];
|
|
5786
|
+
var LEDGER_UNSAFE_RE = /[\s\u0000-\u001f\u007f]/;
|
|
5787
|
+
function argvViolation(arg) {
|
|
5788
|
+
const s = String(arg == null ? "" : arg);
|
|
5789
|
+
if (!s) return "\u7A7A\u7684 argv \u9879";
|
|
5790
|
+
if (ARGV_UNSAFE_RE.test(s) && !WIN_ABS_PATH_RE.test(s)) return "argv \u9879\u542B\u7981\u7528\u5B57\u7B26\uFF08\u7A7A\u767D/shell \u5143\u5B57\u7B26\uFF09: " + s.slice(0, 80);
|
|
5791
|
+
return null;
|
|
5806
5792
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
const
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5793
|
+
var CONTROL_RE = /[\u0000-\u001f\u007f]/;
|
|
5794
|
+
function isAbsoluteForm(p) {
|
|
5795
|
+
const s = String(p == null ? "" : p);
|
|
5796
|
+
return s.charCodeAt(0) === 47 || /^[A-Za-z]:[\\/]/.test(s) || s.charCodeAt(0) === 92 && s.charCodeAt(1) === 92;
|
|
5797
|
+
}
|
|
5798
|
+
function prefixViolation(prefix) {
|
|
5799
|
+
const s = String(prefix == null ? "" : prefix);
|
|
5800
|
+
if (!s.trim()) return "\u7A7A\u7684\u5B89\u88C5\u524D\u7F00";
|
|
5801
|
+
if (CONTROL_RE.test(s)) return "\u5B89\u88C5\u524D\u7F00\u542B\u63A7\u5236\u7B26: " + s.slice(0, 80);
|
|
5802
|
+
if (s.length > 4096) return "\u5B89\u88C5\u524D\u7F00\u8D85\u957F: " + s.slice(0, 60) + "...";
|
|
5803
|
+
if (s[0] === "-") return "\u5B89\u88C5\u524D\u7F00\u4EE5 - \u5F00\u5934\uFF08\u4F1A\u88AB\u5F53\u4F5C npm \u9009\u9879\uFF09: " + s.slice(0, 80);
|
|
5804
|
+
if (!isAbsoluteForm(s)) return "\u5B89\u88C5\u524D\u7F00\u987B\u4E3A\u7EDD\u5BF9\u8DEF\u5F84\uFF08/ \u5F00\u5934\u3001win \u76D8\u7B26\u6216 UNC\uFF09: " + s.slice(0, 80);
|
|
5805
|
+
return null;
|
|
5806
|
+
}
|
|
5807
|
+
function pkgNameViolation(pkg) {
|
|
5808
|
+
const s = String(pkg == null ? "" : pkg);
|
|
5809
|
+
return PKG_NAME_RE.test(s) ? null : "\u975E\u6CD5\u5305\u540D\uFF08\u5B57\u7B26\u96C6\u767D\u540D\u5355\u4E0D\u901A\u8FC7\uFF09: " + s.slice(0, 80);
|
|
5810
|
+
}
|
|
5811
|
+
function unitNameViolation(unit) {
|
|
5812
|
+
const s = String(unit == null ? "" : unit);
|
|
5813
|
+
if (!UNIT_NAME_RE.test(s)) return "\u975E\u6CD5\u5355\u5143\u540D\uFF08\u5B57\u7B26\u96C6/\u957F\u5EA6\u767D\u540D\u5355\u4E0D\u901A\u8FC7\uFF09: " + s.slice(0, 80);
|
|
5814
|
+
const dot = s.indexOf(".");
|
|
5815
|
+
if (dot >= 0 && !/\.service$/.test(s)) return "\u5355\u5143\u540D\u540E\u7F00\u4E0D\u53D7\u652F\u6301\uFF08\u4EC5\u5141\u8BB8 .service \u6216\u65E0\u540E\u7F00\uFF09: " + s.slice(0, 80);
|
|
5816
|
+
return null;
|
|
5817
|
+
}
|
|
5818
|
+
function ledgerKey(raw, opts) {
|
|
5819
|
+
const o = opts || {};
|
|
5820
|
+
const max = typeof o.max === "number" ? o.max : 128;
|
|
5821
|
+
const empty = o.empty == null ? "unknown" : o.empty;
|
|
5822
|
+
const unsafe = o.unsafe == null ? "(other)" : o.unsafe;
|
|
5823
|
+
if (typeof raw !== "string" || !raw) return empty;
|
|
5824
|
+
const s = raw.length > max ? raw.slice(0, max) : raw;
|
|
5825
|
+
if (UNSAFE_LEDGER_KEYS.indexOf(s) >= 0 || LEDGER_UNSAFE_RE.test(s)) return unsafe;
|
|
5826
|
+
return s;
|
|
5827
|
+
}
|
|
5828
|
+
module2.exports = {
|
|
5829
|
+
PKG_NAME_RE,
|
|
5830
|
+
ARGV_UNSAFE_RE,
|
|
5831
|
+
WIN_ABS_PATH_RE,
|
|
5832
|
+
UNIT_NAME_RE,
|
|
5833
|
+
UNSAFE_LEDGER_KEYS,
|
|
5834
|
+
LEDGER_UNSAFE_KEYS_RE: LEDGER_UNSAFE_RE,
|
|
5835
|
+
argvViolation,
|
|
5836
|
+
pkgNameViolation,
|
|
5837
|
+
unitNameViolation,
|
|
5838
|
+
ledgerKey,
|
|
5839
|
+
CONTROL_RE,
|
|
5840
|
+
isAbsoluteForm,
|
|
5841
|
+
prefixViolation
|
|
5842
|
+
};
|
|
5843
|
+
}
|
|
5844
|
+
});
|
|
5845
|
+
|
|
5846
|
+
// src/platform/os/spawn.js
|
|
5847
|
+
var require_spawn = __commonJS({
|
|
5848
|
+
"src/platform/os/spawn.js"(exports2, module2) {
|
|
5849
|
+
"use strict";
|
|
5850
|
+
var { spawn } = require("node:child_process");
|
|
5851
|
+
function detached(cmd2, args, opts) {
|
|
5852
|
+
const o = opts || {};
|
|
5853
|
+
return spawn(cmd2, args, Object.assign({}, o, {
|
|
5854
|
+
detached: true,
|
|
5855
|
+
windowsHide: true,
|
|
5856
|
+
// 默认 ignore;显式 undefined 也回落 ignore,避免 stdio:undefined 的歧义。
|
|
5857
|
+
stdio: o.stdio === void 0 ? "ignore" : o.stdio
|
|
5858
|
+
}));
|
|
5859
|
+
}
|
|
5860
|
+
function piped(cmd2, args, opts) {
|
|
5861
|
+
const o = opts || {};
|
|
5862
|
+
return spawn(cmd2, args, Object.assign({}, o, {
|
|
5863
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5864
|
+
windowsHide: true,
|
|
5865
|
+
detached: o.detached === true
|
|
5866
|
+
}));
|
|
5867
|
+
}
|
|
5868
|
+
function detachedIgnored(cmd2, args, opts) {
|
|
5869
|
+
const o = opts || {};
|
|
5870
|
+
return spawn(cmd2, args, Object.assign({}, o, {
|
|
5871
|
+
detached: true,
|
|
5872
|
+
windowsHide: true,
|
|
5873
|
+
stdio: "ignore"
|
|
5874
|
+
}));
|
|
5875
|
+
}
|
|
5876
|
+
module2.exports = { detached, piped, detachedIgnored };
|
|
5877
|
+
}
|
|
5878
|
+
});
|
|
5879
|
+
|
|
5880
|
+
// src/platform/os/portable.js
|
|
5881
|
+
var require_portable = __commonJS({
|
|
5882
|
+
"src/platform/os/portable.js"(exports2, module2) {
|
|
5883
|
+
"use strict";
|
|
5884
|
+
var fs2 = require("node:fs");
|
|
5885
|
+
var pidlookup = require_pidlookup();
|
|
5886
|
+
var spawner = require_spawn();
|
|
5887
|
+
var procOS = require_process();
|
|
5888
|
+
var STOP_WAIT_CAP_MS = 3e3;
|
|
5889
|
+
var NAP_MS = 150;
|
|
5890
|
+
function nap(ms) {
|
|
5891
|
+
try {
|
|
5892
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
5893
|
+
} catch {
|
|
5821
5894
|
}
|
|
5822
|
-
if (!got.Exec) return null;
|
|
5823
|
-
const categories = String(got.Categories || "");
|
|
5824
|
-
const parsed = parseExecLine(got.Exec);
|
|
5825
|
-
if (!parsed) return null;
|
|
5826
|
-
const engine = engineOf(parsed.bin);
|
|
5827
|
-
const claimsBrowser = /(^|;)WebBrowser(;|$)/.test(categories);
|
|
5828
|
-
if (!claimsBrowser && engine === "other") return null;
|
|
5829
|
-
if (engine === "other") return null;
|
|
5830
|
-
return {
|
|
5831
|
-
// id 恒为归一后的可执行文件路径:defaultId 靠它在清单里定位条目,三平台同一契约
|
|
5832
|
-
id: parsed.bin.toLowerCase(),
|
|
5833
|
-
name: got.Name || path2.basename(file, ".desktop"),
|
|
5834
|
-
engine,
|
|
5835
|
-
bin: parsed.bin,
|
|
5836
|
-
baseArgs: parsed.baseArgs,
|
|
5837
|
-
source: kind,
|
|
5838
|
-
desktopFile: file
|
|
5839
|
-
};
|
|
5840
5895
|
}
|
|
5841
|
-
function
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5896
|
+
function readPidFile(pidFile) {
|
|
5897
|
+
if (!pidFile) return null;
|
|
5898
|
+
try {
|
|
5899
|
+
const n = parseInt(String(fs2.readFileSync(pidFile, "utf8")).trim(), 10);
|
|
5900
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
5901
|
+
} catch {
|
|
5902
|
+
return null;
|
|
5903
|
+
}
|
|
5904
|
+
}
|
|
5905
|
+
function matchesAnchors(pid, anchors) {
|
|
5906
|
+
if (!pid || !Array.isArray(anchors) || !anchors.length) return false;
|
|
5907
|
+
const cmd2 = pidlookup.readCmdline(pid);
|
|
5908
|
+
if (!cmd2) return false;
|
|
5909
|
+
return anchors.some((a) => a && cmd2.indexOf(String(a)) !== -1);
|
|
5910
|
+
}
|
|
5911
|
+
var portOf = (o) => {
|
|
5912
|
+
const p = Number(o && o.port);
|
|
5913
|
+
return Number.isInteger(p) && p > 0 ? p : 0;
|
|
5914
|
+
};
|
|
5915
|
+
var pidFileOf = (o) => o && o.pidFile || null;
|
|
5916
|
+
var anchorsOf = (o) => Array.isArray(o && o.anchors) ? o.anchors : [];
|
|
5917
|
+
function findOurs(o) {
|
|
5918
|
+
const anchors = anchorsOf(o);
|
|
5919
|
+
const fp = readPidFile(pidFileOf(o));
|
|
5920
|
+
if (fp !== null && pidlookup.isAlive(fp) && matchesAnchors(fp, anchors)) return { pid: fp, ownGroup: true };
|
|
5921
|
+
const port = portOf(o);
|
|
5922
|
+
if (port) {
|
|
5923
|
+
const q = pidlookup.findListeningPid(port);
|
|
5924
|
+
if (q !== null && q !== fp && matchesAnchors(q, anchors)) return { pid: q, ownGroup: false };
|
|
5850
5925
|
}
|
|
5851
5926
|
return null;
|
|
5852
5927
|
}
|
|
5853
|
-
function
|
|
5854
|
-
const
|
|
5855
|
-
|
|
5856
|
-
const note = (source, detail) => {
|
|
5857
|
-
notes.push({ source, detail });
|
|
5858
|
-
};
|
|
5859
|
-
const found = /* @__PURE__ */ new Map();
|
|
5860
|
-
const usable = (item) => {
|
|
5861
|
-
const resolved = resolveLinuxBin(item.bin, canExec, env);
|
|
5862
|
-
if (!resolved) {
|
|
5863
|
-
note(item.source, "\u4E0D\u53EF\u6267\u884C: " + item.bin);
|
|
5864
|
-
return null;
|
|
5865
|
-
}
|
|
5866
|
-
const k = resolved.toLowerCase();
|
|
5867
|
-
const hit = found.get(k);
|
|
5868
|
-
if (hit) {
|
|
5869
|
-
if (!hit.sources.includes(item.source)) hit.sources.push(item.source);
|
|
5870
|
-
return hit;
|
|
5871
|
-
}
|
|
5872
|
-
const v = Object.assign({}, item, { id: k, bin: resolved, sources: [item.source] });
|
|
5873
|
-
found.set(k, v);
|
|
5874
|
-
return v;
|
|
5875
|
-
};
|
|
5876
|
-
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5877
|
-
let names = [];
|
|
5928
|
+
function removePidFile(o) {
|
|
5929
|
+
const f = pidFileOf(o);
|
|
5930
|
+
if (f) {
|
|
5878
5931
|
try {
|
|
5879
|
-
|
|
5932
|
+
fs2.unlinkSync(f);
|
|
5880
5933
|
} catch {
|
|
5881
|
-
continue;
|
|
5882
5934
|
}
|
|
5883
|
-
|
|
5884
|
-
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
var portable = {
|
|
5938
|
+
kind: "portable",
|
|
5939
|
+
supportsUnits: false,
|
|
5940
|
+
supportsTransient: true,
|
|
5941
|
+
// 无操作 = 成功(与 systemd 的动词返回形态一致,调用方无需按 provider 分支)。
|
|
5942
|
+
daemonReload() {
|
|
5943
|
+
return true;
|
|
5944
|
+
},
|
|
5945
|
+
resetFailed() {
|
|
5946
|
+
return true;
|
|
5947
|
+
},
|
|
5948
|
+
/** 拉起:spawn(detached)——POSIX 自成进程组(kill(-pid) 语义的前提)、win32 windowsHide +
|
|
5949
|
+
* CREATE_NEW_PROCESS_GROUP(NO-CONSOLE-WINDOW 纪律收口在 platform/os/spawn.js)。
|
|
5950
|
+
* 调用方传来的 props(cgroup 语义)在此如实忽略:本档无内核强制可施加。
|
|
5951
|
+
* @param {{cmd:string[], env?:object, workingDir?:string, pidFile?:string, port?:number, anchors?:string[]}} o */
|
|
5952
|
+
startTransient(o) {
|
|
5953
|
+
const opts = o || {};
|
|
5954
|
+
const cmd2 = opts.cmd || [];
|
|
5955
|
+
if (!cmd2.length) throw new Error("portable \u62C9\u8D77\u62D2\u7EDD\uFF1A\u7A7A\u547D\u4EE4");
|
|
5956
|
+
const child = spawner.detached(cmd2[0], cmd2.slice(1), {
|
|
5957
|
+
cwd: opts.workingDir || void 0,
|
|
5958
|
+
env: Object.assign({}, process.env, opts.env || {})
|
|
5959
|
+
});
|
|
5960
|
+
child.on("error", () => {
|
|
5961
|
+
});
|
|
5962
|
+
if (!child.pid) {
|
|
5885
5963
|
try {
|
|
5886
|
-
|
|
5964
|
+
child.kill();
|
|
5887
5965
|
} catch {
|
|
5888
|
-
continue;
|
|
5889
5966
|
}
|
|
5890
|
-
|
|
5891
|
-
if (item) usable(item);
|
|
5967
|
+
throw new Error("portable \u62C9\u8D77\u5931\u8D25\uFF1Aspawn \u672A\u4EA7\u751F\u8FDB\u7A0B");
|
|
5892
5968
|
}
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
const fromMime = linuxDefaultFromMimeApps(readFile, exists, env, home, note);
|
|
5897
|
-
if (fromMime) {
|
|
5898
|
-
const item = usable(fromMime);
|
|
5899
|
-
if (item) {
|
|
5900
|
-
defaultId = item.id;
|
|
5901
|
-
defaultSource = "mimeapps";
|
|
5969
|
+
try {
|
|
5970
|
+
child.unref();
|
|
5971
|
+
} catch {
|
|
5902
5972
|
}
|
|
5903
|
-
|
|
5904
|
-
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5905
|
-
const desktopId = id && String(id).trim();
|
|
5906
|
-
if (!defaultId && desktopId && /^[A-Za-z0-9._-]+\.desktop$/.test(desktopId)) {
|
|
5907
|
-
for (const { dir } of desktopDirs(env, home)) {
|
|
5908
|
-
const p = PJ(dir, desktopId);
|
|
5909
|
-
let text = null;
|
|
5973
|
+
if (opts.pidFile) {
|
|
5910
5974
|
try {
|
|
5911
|
-
|
|
5975
|
+
fs2.writeFileSync(opts.pidFile, String(child.pid));
|
|
5912
5976
|
} catch {
|
|
5913
|
-
continue;
|
|
5914
5977
|
}
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5978
|
+
}
|
|
5979
|
+
return true;
|
|
5980
|
+
},
|
|
5981
|
+
/** 停止(有界同步复核):终止我们的进程树,确认「端口锚点与 run.pid 锚点双双消失」才 true。
|
|
5982
|
+
* 无可杀对象(含 run.pid 为陈旧/被 PID 复用)-> 清文件后如实 true(幂等)。 */
|
|
5983
|
+
stopUnit(unit, o) {
|
|
5984
|
+
const opts = o || {};
|
|
5985
|
+
const ours = findOurs(opts);
|
|
5986
|
+
if (!ours) {
|
|
5987
|
+
removePidFile(opts);
|
|
5988
|
+
return true;
|
|
5989
|
+
}
|
|
5990
|
+
try {
|
|
5991
|
+
procOS.killTree(ours.pid, "SIGTERM", void 0, { ownGroup: ours.ownGroup });
|
|
5992
|
+
} catch {
|
|
5993
|
+
}
|
|
5994
|
+
const budget = Math.max(0, Math.min(typeof opts.timeoutMs === "number" ? opts.timeoutMs : STOP_WAIT_CAP_MS, STOP_WAIT_CAP_MS));
|
|
5995
|
+
const t0 = Date.now();
|
|
5996
|
+
for (; ; ) {
|
|
5997
|
+
if (!findOurs(opts)) {
|
|
5998
|
+
removePidFile(opts);
|
|
5999
|
+
return true;
|
|
6000
|
+
}
|
|
6001
|
+
if (Date.now() - t0 >= budget) break;
|
|
6002
|
+
nap(NAP_MS);
|
|
6003
|
+
}
|
|
6004
|
+
try {
|
|
6005
|
+
procOS.killTree(ours.pid, "SIGKILL", void 0, { ownGroup: ours.ownGroup });
|
|
6006
|
+
} catch {
|
|
6007
|
+
}
|
|
6008
|
+
nap(NAP_MS);
|
|
6009
|
+
if (!findOurs(opts)) {
|
|
6010
|
+
removePidFile(opts);
|
|
6011
|
+
return true;
|
|
6012
|
+
}
|
|
6013
|
+
return false;
|
|
6014
|
+
},
|
|
6015
|
+
/** 活跃判定(三态):port 与 pidFile 都缺 = 无从查询 -> null,删除保护路径不得把它当「已停止」。
|
|
6016
|
+
* anchors 为空时降级为「端口有监听即活跃」(monitor.probeInstance 同口径,该调用方本就以此判在线);
|
|
6017
|
+
* 杀进程(stopUnit)仍要求锚点命中 —— 判定可宽,动手必严。
|
|
6018
|
+
* 存活 pid 的 cmdline 读不到 = 分不清「他人复用」与「查询失败」-> null。 */
|
|
6019
|
+
isUnitActive(unit, o) {
|
|
6020
|
+
const opts = o || {};
|
|
6021
|
+
if (findOurs(opts)) return true;
|
|
6022
|
+
const port = portOf(opts);
|
|
6023
|
+
const pidFile = pidFileOf(opts);
|
|
6024
|
+
const anchors = anchorsOf(opts);
|
|
6025
|
+
if (!port && !pidFile) return null;
|
|
6026
|
+
if (!anchors.length) {
|
|
6027
|
+
const fp2 = readPidFile(pidFile);
|
|
6028
|
+
if (fp2 !== null && pidlookup.isAlive(fp2)) return true;
|
|
6029
|
+
if (port) {
|
|
6030
|
+
const q = pidlookup.findListeningPid(port);
|
|
6031
|
+
if (q !== null) return true;
|
|
6032
|
+
if (fp2 !== null) return false;
|
|
6033
|
+
return null;
|
|
5922
6034
|
}
|
|
6035
|
+
return fp2 !== null ? false : null;
|
|
6036
|
+
}
|
|
6037
|
+
const fp = readPidFile(pidFile);
|
|
6038
|
+
if (fp !== null && pidlookup.isAlive(fp) && !pidlookup.readCmdline(fp)) return null;
|
|
6039
|
+
return false;
|
|
6040
|
+
},
|
|
6041
|
+
// portable 无 systemd transient 单元文件;run.pid 的清理归 cleanTransient。
|
|
6042
|
+
transientUnitFile() {
|
|
6043
|
+
return null;
|
|
6044
|
+
},
|
|
6045
|
+
/** 清理同名残留:先停掉仍活着的旧进程(重启自愈路径:旧进程未监听端口时端口探测拦不住),再清 run.pid。 */
|
|
6046
|
+
cleanTransient(unit, o) {
|
|
6047
|
+
const opts = o || {};
|
|
6048
|
+
const errors = [];
|
|
6049
|
+
if (this.stopUnit(unit, Object.assign({}, opts, { timeoutMs: 1500 })) === false) errors.push("stop-unconfirmed");
|
|
6050
|
+
removePidFile(opts);
|
|
6051
|
+
return { ok: errors.length === 0, errors };
|
|
6052
|
+
},
|
|
6053
|
+
/** 返回值只表示「是否改动了内核强制」;governor 不因 false 走降级分支 —— 违规处置链本就平台无关。 */
|
|
6054
|
+
setLimits() {
|
|
6055
|
+
return false;
|
|
6056
|
+
}
|
|
6057
|
+
};
|
|
6058
|
+
module2.exports = { portable, findOurs, matchesAnchors, _test: { readPidFile, matchesAnchors, findOurs } };
|
|
6059
|
+
}
|
|
6060
|
+
});
|
|
6061
|
+
|
|
6062
|
+
// src/platform/os/service.js
|
|
6063
|
+
var require_service = __commonJS({
|
|
6064
|
+
"src/platform/os/service.js"(exports2, module2) {
|
|
6065
|
+
"use strict";
|
|
6066
|
+
var fs2 = require("node:fs");
|
|
6067
|
+
var os2 = require("node:os");
|
|
6068
|
+
var path2 = require("node:path");
|
|
6069
|
+
var exec = require_exec();
|
|
6070
|
+
var input = require_input();
|
|
6071
|
+
var execPath = require_exec_path();
|
|
6072
|
+
var { portable } = require_portable();
|
|
6073
|
+
var CapabilityError = class extends Error {
|
|
6074
|
+
constructor(msg) {
|
|
6075
|
+
super(msg);
|
|
6076
|
+
this.name = "CapabilityError";
|
|
6077
|
+
this.code = "CAPABILITY_UNSUPPORTED";
|
|
6078
|
+
}
|
|
6079
|
+
};
|
|
6080
|
+
var PLATFORM = process.platform;
|
|
6081
|
+
function run(cmd2, args, opts) {
|
|
6082
|
+
return exec.run(cmd2, args, opts || {});
|
|
6083
|
+
}
|
|
6084
|
+
var UNIT_NAME_RE = input.UNIT_NAME_RE;
|
|
6085
|
+
function unitNameViolation(unit) {
|
|
6086
|
+
return input.unitNameViolation(unit);
|
|
6087
|
+
}
|
|
6088
|
+
var systemd = {
|
|
6089
|
+
kind: "systemd",
|
|
6090
|
+
supportsUnits: true,
|
|
6091
|
+
supportsTransient: true,
|
|
6092
|
+
daemonReload() {
|
|
6093
|
+
try {
|
|
6094
|
+
return run("systemctl", ["--user", "daemon-reload"], { timeoutMs: 15e3 }) !== null;
|
|
6095
|
+
} catch {
|
|
6096
|
+
return false;
|
|
6097
|
+
}
|
|
6098
|
+
},
|
|
6099
|
+
stopUnit(unit, opts) {
|
|
6100
|
+
if (unitNameViolation(unit)) return false;
|
|
6101
|
+
const o = opts || {};
|
|
6102
|
+
try {
|
|
6103
|
+
return run("systemctl", ["--user", "stop", unit], { timeoutMs: o.timeoutMs || 15e3 }) !== null;
|
|
6104
|
+
} catch {
|
|
6105
|
+
return false;
|
|
6106
|
+
}
|
|
6107
|
+
},
|
|
6108
|
+
// run() 失败返回 null 而不抛,try/catch 包裹会恒返回 true;如实回传成败。
|
|
6109
|
+
resetFailed(unit) {
|
|
6110
|
+
if (unitNameViolation(unit)) return false;
|
|
6111
|
+
return run("systemctl", ["--user", "reset-failed", unit], { timeoutMs: 1e4 }) !== null;
|
|
6112
|
+
},
|
|
6113
|
+
/** 单元活跃判定(三态):确认 active -> true;确认不活跃 -> false;查询未完成 -> null(未知)。
|
|
6114
|
+
* run() 失败只返回 null,「查询未完成」不可折成 false:instance/ops.js 删除数据目录前
|
|
6115
|
+
* 按「!== false 才放行删除」消费本函数,折假即超时窗口内误删沙箱数据。 */
|
|
6116
|
+
isUnitActive(unit) {
|
|
6117
|
+
if (!unit) return true;
|
|
6118
|
+
if (unitNameViolation(unit)) return false;
|
|
6119
|
+
try {
|
|
6120
|
+
const r = exec.runDetail("systemctl", ["--user", "is-active", unit], { timeoutMs: 8e3 });
|
|
6121
|
+
if (r.timedOut) return null;
|
|
6122
|
+
const state = String(r.stdout || "").trim();
|
|
6123
|
+
if (state === "active") return true;
|
|
6124
|
+
if (state || r.code !== null) return false;
|
|
6125
|
+
return null;
|
|
6126
|
+
} catch {
|
|
6127
|
+
return null;
|
|
5923
6128
|
}
|
|
5924
|
-
}
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
if (!defaultId && found.size === 1) {
|
|
5929
|
-
defaultId = [...found.keys()][0];
|
|
5930
|
-
defaultSource = "only-installed";
|
|
5931
|
-
}
|
|
5932
|
-
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5933
|
-
}
|
|
5934
|
-
function linuxDefaultFromMimeApps(readFile, exists, env, home, note) {
|
|
5935
|
-
const cfgHome = env.XDG_CONFIG_HOME || PJ(home, ".config");
|
|
5936
|
-
const cfgDirs = String(env.XDG_CONFIG_DIRS || "/etc/xdg").split(":").filter(Boolean);
|
|
5937
|
-
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5938
|
-
const files = [
|
|
5939
|
-
PJ(cfgHome, "mimeapps.list"),
|
|
5940
|
-
...cfgDirs.map((d) => PJ(d, "mimeapps.list")),
|
|
5941
|
-
...dataDirs.map((d) => PJ(d, "applications", "mimeapps.list"))
|
|
5942
|
-
];
|
|
5943
|
-
for (const f of files) {
|
|
5944
|
-
if (!exists(f)) continue;
|
|
5945
|
-
let text = null;
|
|
6129
|
+
},
|
|
6130
|
+
transientUnitFile(unit) {
|
|
6131
|
+
if (unitNameViolation(unit)) return null;
|
|
6132
|
+
let uid = 0;
|
|
5946
6133
|
try {
|
|
5947
|
-
|
|
6134
|
+
uid = os2.userInfo().uid;
|
|
5948
6135
|
} catch {
|
|
5949
|
-
continue;
|
|
5950
6136
|
}
|
|
5951
|
-
const
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
6137
|
+
const rt = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
6138
|
+
return path2.join(rt, "systemd", "transient", unit + ".service");
|
|
6139
|
+
},
|
|
6140
|
+
/** 清理 stale transient 单元:stop/reset-failed/删单元文件/daemon-reload。
|
|
6141
|
+
* 必须 reload:删除文件后 systemd 仍缓存该单元为 loaded,否则 systemd-run 拒绝重建同名单元。
|
|
6142
|
+
* 返回 {ok, errors}:stop/reset-failed 对「从未加载的单元」非零退出属正常,不计入 ok;
|
|
6143
|
+
* 硬失败只有删单元文件与 daemon-reload(run() 失败返回 null 不抛,成败须如实回传)。 */
|
|
6144
|
+
cleanTransient(unit) {
|
|
6145
|
+
const errors = [];
|
|
6146
|
+
const bad = unitNameViolation(unit);
|
|
6147
|
+
if (bad) return { ok: false, errors: [bad] };
|
|
6148
|
+
exec.runDetail("systemctl", ["--user", "stop", unit + ".service"], { timeoutMs: 1e4 });
|
|
6149
|
+
exec.runDetail("systemctl", ["--user", "reset-failed", unit + ".service"], { timeoutMs: 1e4 });
|
|
6150
|
+
let unlinkOk = true;
|
|
6151
|
+
try {
|
|
6152
|
+
const f = this.transientUnitFile(unit);
|
|
6153
|
+
if (f) fs2.unlinkSync(f);
|
|
6154
|
+
} catch {
|
|
6155
|
+
unlinkOk = false;
|
|
6156
|
+
errors.push("unlink " + unit + ".service");
|
|
5965
6157
|
}
|
|
5966
|
-
|
|
6158
|
+
if (!exec.runDetail("systemctl", ["--user", "daemon-reload"], { timeoutMs: 15e3 }).ok) errors.push("daemon-reload");
|
|
6159
|
+
return { ok: unlinkOk && errors.length === 0, errors };
|
|
6160
|
+
},
|
|
6161
|
+
/** 以 transient 单元启动(独立 cgroup;每实例隔离)。
|
|
6162
|
+
* @param {{unit:string, cmd:string[], env?:object, props?:string[], workingDir?:string, description?:string, timeoutMs?:number}} o
|
|
6163
|
+
* props 为 systemd 属性(如 KillMode=process、MemoryMax=8G),平台层只拼装成 --property,不解释语义。 */
|
|
6164
|
+
startTransient(o) {
|
|
6165
|
+
const opts = o || {};
|
|
6166
|
+
const bad = unitNameViolation(opts.unit);
|
|
6167
|
+
if (bad) throw new Error("systemd-run \u62D2\u7EDD: " + bad);
|
|
6168
|
+
const args = ["--user", "--unit=" + opts.unit];
|
|
6169
|
+
if (opts.description) args.push("--description=" + opts.description);
|
|
6170
|
+
for (const p of opts.props || []) args.push("--property=" + p);
|
|
6171
|
+
for (const [k, v] of Object.entries(opts.env || {})) args.push("--setenv=" + k + "=" + v);
|
|
6172
|
+
if (opts.workingDir) args.push("--working-directory=" + opts.workingDir);
|
|
6173
|
+
args.push("--", ...opts.cmd || []);
|
|
6174
|
+
const r = exec.runDetail("systemd-run", args, { timeoutMs: opts.timeoutMs || 2e4 });
|
|
6175
|
+
if (!r.ok) throw new Error("systemd-run \u5931\u8D25: " + (r.error || "unknown") + (r.stderr ? " | " + String(r.stderr).trim() : ""));
|
|
6176
|
+
return true;
|
|
6177
|
+
},
|
|
6178
|
+
/** 运行期改限额(W3 动态化):systemctl --user set-property 立即生效,无需重启单元。
|
|
6179
|
+
* 必带 --runtime:transient 单元本不落盘,不带它会把 drop-in 写进用户配置目录,陈旧下限永久黏住。
|
|
6180
|
+
* 值只来自 sandbox.unitProps 同源的 alloc(平台层翻译语义、不决定数额)。 */
|
|
6181
|
+
setLimits(unit, alloc) {
|
|
6182
|
+
if (unitNameViolation(unit)) return false;
|
|
6183
|
+
const a = alloc || {};
|
|
6184
|
+
const props = [];
|
|
6185
|
+
if (a.memoryMax) props.push("MemoryMax=" + a.memoryMax);
|
|
6186
|
+
if (a.memoryHigh) props.push("MemoryHigh=" + a.memoryHigh);
|
|
6187
|
+
if (a.cpuQuota) props.push("CPUQuota=" + a.cpuQuota);
|
|
6188
|
+
if (!props.length) return false;
|
|
6189
|
+
return exec.runDetail(
|
|
6190
|
+
"systemctl",
|
|
6191
|
+
["--user", "set-property", "--runtime", unit].concat(props),
|
|
6192
|
+
{ timeoutMs: 1e4 }
|
|
6193
|
+
).ok;
|
|
5967
6194
|
}
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
6195
|
+
};
|
|
6196
|
+
function makeUnsupported(kind, label) {
|
|
6197
|
+
return {
|
|
6198
|
+
kind,
|
|
6199
|
+
supportsUnits: false,
|
|
6200
|
+
supportsTransient: false,
|
|
6201
|
+
daemonReload() {
|
|
6202
|
+
return false;
|
|
6203
|
+
},
|
|
6204
|
+
stopUnit() {
|
|
6205
|
+
throw new CapabilityError(label + "\uFF1A\u4E0D\u652F\u6301\u4EE5\u7528\u6237\u5355\u5143\u65B9\u5F0F\u7BA1\u7406\u88AB\u7BA1\u5B9E\u4F8B");
|
|
6206
|
+
},
|
|
6207
|
+
resetFailed() {
|
|
6208
|
+
return false;
|
|
6209
|
+
},
|
|
6210
|
+
isUnitActive(unit) {
|
|
6211
|
+
return unit ? false : true;
|
|
6212
|
+
},
|
|
6213
|
+
transientUnitFile() {
|
|
6214
|
+
return null;
|
|
6215
|
+
},
|
|
6216
|
+
// 无 transient 单元可清 = 成功;返回形态与 systemd 一致,调用方无需分支。
|
|
6217
|
+
cleanTransient() {
|
|
6218
|
+
return { ok: true, errors: [] };
|
|
6219
|
+
},
|
|
6220
|
+
startTransient() {
|
|
6221
|
+
throw new CapabilityError(label + "\uFF1A\u4E0D\u652F\u6301\u62C9\u8D77\u5B9E\u4F8B\u8231\uFF08portable \u6863\u672A\u542F\u7528\uFF09");
|
|
6222
|
+
},
|
|
6223
|
+
setLimits() {
|
|
6224
|
+
return false;
|
|
5977
6225
|
}
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
6226
|
+
};
|
|
6227
|
+
}
|
|
6228
|
+
var NONE = makeUnsupported("none", "\u5F53\u524D\u5E73\u53F0\u65E0\u670D\u52A1\u7BA1\u7406\u5668");
|
|
6229
|
+
var _systemdRun = null;
|
|
6230
|
+
function hasSystemdRun() {
|
|
6231
|
+
if (_systemdRun === null) {
|
|
6232
|
+
_systemdRun = !!execPath.resolveExecutable("systemd-run") || exec.runOut("systemd-run", ["--version"], { timeoutMs: 3e3 }) !== null;
|
|
5983
6233
|
}
|
|
5984
|
-
return
|
|
6234
|
+
return _systemdRun;
|
|
5985
6235
|
}
|
|
5986
|
-
function
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
if (pl === "darwin") return probeMac(dd);
|
|
5991
|
-
return probeLinux(dd);
|
|
6236
|
+
function current() {
|
|
6237
|
+
if (PLATFORM === "linux") return hasSystemdRun() ? systemd : portable;
|
|
6238
|
+
if (PLATFORM === "darwin" || PLATFORM === "win32") return portable;
|
|
6239
|
+
return NONE;
|
|
5992
6240
|
}
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
6241
|
+
module2.exports = { current, CapabilityError, kind: () => current().kind, PLATFORM, UNIT_NAME_RE, unitNameViolation, _testProviders: { systemd, portable, NONE } };
|
|
6242
|
+
}
|
|
6243
|
+
});
|
|
6244
|
+
|
|
6245
|
+
// src/platform/os/notify.js
|
|
6246
|
+
var require_notify = __commonJS({
|
|
6247
|
+
"src/platform/os/notify.js"(exports2, module2) {
|
|
6248
|
+
"use strict";
|
|
6249
|
+
var spawnOS = require_spawn();
|
|
6250
|
+
function appleScriptString(s) {
|
|
6251
|
+
return JSON.stringify(String(s));
|
|
6252
|
+
}
|
|
6253
|
+
function powerShellString(s) {
|
|
6254
|
+
return "'" + String(s).replace(/'/g, "''") + "'";
|
|
6255
|
+
}
|
|
6256
|
+
function notifyCommand(platform, title, body) {
|
|
5996
6257
|
const pl = platform || process.platform;
|
|
5997
|
-
const
|
|
5998
|
-
const
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: PROBE_TIMEOUT_MS }));
|
|
6002
|
-
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
6003
|
-
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
6004
|
-
const listDir = ov.listDir || ((p) => fs2.readdirSync(p));
|
|
6005
|
-
let value;
|
|
6006
|
-
try {
|
|
6007
|
-
value = probe(pl, { runOut, readFile, exists, listDir, canExec: ov.canExec, env: ov.env || process.env, home: ov.home || os2.homedir() });
|
|
6008
|
-
} catch (e) {
|
|
6009
|
-
value = { browsers: [], defaultId: null, defaultSource: null, probed: [{ source: "probe-error", detail: String(e && e.message || e) }] };
|
|
6258
|
+
const t = String(title == null ? "" : title);
|
|
6259
|
+
const b = String(body == null ? "" : body);
|
|
6260
|
+
if (pl === "linux") {
|
|
6261
|
+
return { cmd: "notify-send", args: ["-a", "dsh-supervisor", t, b] };
|
|
6010
6262
|
}
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6263
|
+
if (pl === "darwin") {
|
|
6264
|
+
const script = "display notification " + appleScriptString(b) + " with title " + appleScriptString(t);
|
|
6265
|
+
return { cmd: "osascript", args: ["-e", script] };
|
|
6266
|
+
}
|
|
6267
|
+
if (pl === "win32") {
|
|
6268
|
+
const ps = [
|
|
6269
|
+
'[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null',
|
|
6270
|
+
'[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null',
|
|
6271
|
+
"$n = New-Object System.Windows.Forms.NotifyIcon",
|
|
6272
|
+
"$n.Icon = [System.Drawing.SystemIcons]::Information",
|
|
6273
|
+
"$n.Visible = $true",
|
|
6274
|
+
"$n.ShowBalloonTip(4000, " + powerShellString(t) + ", " + powerShellString(b) + ", [System.Windows.Forms.ToolTipIcon]::None)",
|
|
6275
|
+
"Start-Sleep -Milliseconds 4200",
|
|
6276
|
+
"$n.Dispose(); $n.Visible = $false"
|
|
6277
|
+
].join("; ");
|
|
6278
|
+
return { cmd: "powershell", args: ["-NoProfile", "-NonInteractive", "-Command", ps] };
|
|
6279
|
+
}
|
|
6280
|
+
return null;
|
|
6016
6281
|
}
|
|
6017
|
-
function
|
|
6018
|
-
|
|
6019
|
-
|
|
6282
|
+
function notify(title, body, onError) {
|
|
6283
|
+
try {
|
|
6284
|
+
const plan = notifyCommand(process.platform, title, body);
|
|
6285
|
+
if (!plan) return false;
|
|
6286
|
+
const c = spawnOS.detachedIgnored(plan.cmd, plan.args);
|
|
6287
|
+
c.on("error", () => {
|
|
6288
|
+
if (onError) onError();
|
|
6289
|
+
});
|
|
6290
|
+
c.unref();
|
|
6291
|
+
return true;
|
|
6292
|
+
} catch {
|
|
6293
|
+
if (onError) onError();
|
|
6294
|
+
return false;
|
|
6295
|
+
}
|
|
6020
6296
|
}
|
|
6021
|
-
module2.exports = {
|
|
6022
|
-
inventory,
|
|
6023
|
-
invalidate,
|
|
6024
|
-
probe,
|
|
6025
|
-
probeWin,
|
|
6026
|
-
probeMac,
|
|
6027
|
-
probeLinux,
|
|
6028
|
-
engineOf,
|
|
6029
|
-
tokenizeExec,
|
|
6030
|
-
parseExecLine,
|
|
6031
|
-
regValueOf,
|
|
6032
|
-
expandEnvVars,
|
|
6033
|
-
exeFromCmdLine,
|
|
6034
|
-
regSubkeys,
|
|
6035
|
-
regKeyFull,
|
|
6036
|
-
regValueTargets,
|
|
6037
|
-
safeRegKeyPart,
|
|
6038
|
-
browserFromDesktop,
|
|
6039
|
-
desktopDirs,
|
|
6040
|
-
resolveLinuxBin,
|
|
6041
|
-
mimeAppsDefault,
|
|
6042
|
-
linuxDefaultFromMimeApps,
|
|
6043
|
-
WIN_APP_PATHS,
|
|
6044
|
-
PROBE_TIMEOUT_MS
|
|
6045
|
-
};
|
|
6297
|
+
module2.exports = { notify, notifyCommand, appleScriptString, powerShellString };
|
|
6046
6298
|
}
|
|
6047
6299
|
});
|
|
6048
6300
|
|
|
@@ -6055,8 +6307,10 @@ var require_browser = __commonJS({
|
|
|
6055
6307
|
var desktop = require_desktop();
|
|
6056
6308
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
6057
6309
|
var { resolveExecutable, isExecutableFile } = require_exec_path();
|
|
6310
|
+
var environment = require_environment();
|
|
6058
6311
|
var detector = require_browser_inventory();
|
|
6059
6312
|
var { engineOf } = detector;
|
|
6313
|
+
var { allocTempDir, removeTreeDeferred } = require_fs();
|
|
6060
6314
|
function isSafeHttpUrl(url) {
|
|
6061
6315
|
try {
|
|
6062
6316
|
const u = new URL(String(url));
|
|
@@ -6092,7 +6346,7 @@ var require_browser = __commonJS({
|
|
|
6092
6346
|
var HANDEDOFF_TEXT = "\u5DF2\u628A\u5730\u5740\u4EA4\u7ED9\u7CFB\u7EDF\uFF0C\u4F46\u8FD9\u6B21\u542F\u52A8\u62FF\u4E0D\u5230\u7A97\u53E3\u662F\u5426\u51FA\u73B0\u7684\u8BC1\u636E";
|
|
6093
6347
|
var FAILURE_TEXT = {
|
|
6094
6348
|
"unsafe-url": "\u5730\u5740\u4E0D\u662F http(s) \u7EDD\u5BF9 URL\uFF0C\u5DF2\u62D2\u7EDD\u4EA4\u7ED9\u6D4F\u89C8\u5668",
|
|
6095
|
-
"no-launcher": "\u672A\
|
|
6349
|
+
"no-launcher": "\u672C\u673A\u672A\u63A2\u5230\u53EF\u542F\u52A8\u7684\u6D4F\u89C8\u5668\uFF08\u6216\u6240\u9009\u6D4F\u89C8\u5668\u5DF2\u4E0D\u53EF\u6267\u884C\uFF09\uFF0C\u8BF7\u5728\u9762\u677F\u7684\u73AF\u5883\u8868\u5355\u91CC\u786E\u8BA4\uFF0C\u6216\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740",
|
|
6096
6350
|
"spawn-failed": "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF08\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8BE5\u547D\u4EE4\uFF09",
|
|
6097
6351
|
"exit-nonzero": "\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8FD9\u4E2A\u5730\u5740\uFF08\u542F\u52A8\u547D\u4EE4\u975E 0 \u9000\u51FA\uFF09\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
6098
6352
|
"killed-by-signal": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u88AB\u7CFB\u7EDF\u7EC8\u6B62\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
@@ -6100,17 +6354,10 @@ var require_browser = __commonJS({
|
|
|
6100
6354
|
"unsupported-platform": "\u5F53\u524D\u5E73\u53F0\u4E0D\u5728\u4EA7\u54C1\u652F\u6301\u7684\u684C\u9762\u5E73\u53F0\u5185\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740"
|
|
6101
6355
|
};
|
|
6102
6356
|
function ownsItsWindow(via, platform) {
|
|
6357
|
+
if (via === "isolated") return true;
|
|
6103
6358
|
if (via !== "dispatcher") return false;
|
|
6104
6359
|
return platform !== "win32";
|
|
6105
6360
|
}
|
|
6106
|
-
function pickLauncher(platform, inv) {
|
|
6107
|
-
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
6108
|
-
const id = inv && inv.defaultId;
|
|
6109
|
-
const hit = id ? list.find((b) => b.id === id) : null;
|
|
6110
|
-
if (hit) return { browser: hit, how: inv && inv.defaultSource || "default" };
|
|
6111
|
-
if (list.length === 1) return { browser: list[0], how: "only-installed" };
|
|
6112
|
-
return { browser: null, how: list.length ? "no-default" : "none-found" };
|
|
6113
|
-
}
|
|
6114
6361
|
function formOfBin(pl, b) {
|
|
6115
6362
|
const engine = b && b.bin ? engineOf(b.bin) : "other";
|
|
6116
6363
|
return { engine, direct: !!b && (engine !== "other" || pl === "win32") };
|
|
@@ -6118,30 +6365,118 @@ var require_browser = __commonJS({
|
|
|
6118
6365
|
function openPlan(platform, url, opts) {
|
|
6119
6366
|
const o = opts || {};
|
|
6120
6367
|
const pl = platform || process.platform;
|
|
6121
|
-
const picked = o.pick || pickLauncher(pl, o.inventory);
|
|
6368
|
+
const picked = o.pick || environment.pickLauncher(pl, o.inventory, o.preference);
|
|
6122
6369
|
const b = picked.browser;
|
|
6123
6370
|
const form = formOfBin(pl, b);
|
|
6124
6371
|
if (form.direct) {
|
|
6125
6372
|
return {
|
|
6126
6373
|
bin: b.bin,
|
|
6374
|
+
args: (b.baseArgs || []).concat([url]),
|
|
6127
6375
|
engine: form.engine,
|
|
6128
6376
|
via: "browser",
|
|
6377
|
+
isolated: false,
|
|
6378
|
+
watch: false,
|
|
6379
|
+
envKind: "sys",
|
|
6129
6380
|
pick: picked.how,
|
|
6130
|
-
|
|
6381
|
+
stale: picked.stale === true,
|
|
6131
6382
|
exitIsEvidence: ownsItsWindow("browser", pl)
|
|
6132
6383
|
};
|
|
6133
6384
|
}
|
|
6134
6385
|
const c = openCommand(pl, url);
|
|
6135
|
-
if (!c) return {
|
|
6386
|
+
if (!c) return {
|
|
6387
|
+
bin: null,
|
|
6388
|
+
args: [url],
|
|
6389
|
+
engine: form.engine,
|
|
6390
|
+
via: "none",
|
|
6391
|
+
isolated: false,
|
|
6392
|
+
watch: false,
|
|
6393
|
+
envKind: "sys",
|
|
6394
|
+
pick: picked.how,
|
|
6395
|
+
stale: picked.stale === true,
|
|
6396
|
+
exitIsEvidence: false
|
|
6397
|
+
};
|
|
6136
6398
|
return {
|
|
6137
6399
|
bin: c.cmd,
|
|
6400
|
+
args: c.args,
|
|
6138
6401
|
engine: "other",
|
|
6139
6402
|
via: "dispatcher",
|
|
6403
|
+
isolated: false,
|
|
6404
|
+
watch: false,
|
|
6405
|
+
envKind: "sys",
|
|
6140
6406
|
pick: picked.how,
|
|
6141
|
-
|
|
6407
|
+
stale: picked.stale === true,
|
|
6142
6408
|
exitIsEvidence: ownsItsWindow("dispatcher", pl)
|
|
6143
6409
|
};
|
|
6144
6410
|
}
|
|
6411
|
+
function isolatedPlan(platform, url, opts) {
|
|
6412
|
+
const o = opts || {};
|
|
6413
|
+
const pl = platform || process.platform;
|
|
6414
|
+
const picked = o.pick || environment.pickLauncher(pl, o.inventory, o.preference);
|
|
6415
|
+
const b = picked.browser;
|
|
6416
|
+
const form = formOfBin(pl, b);
|
|
6417
|
+
const baseArgs = b && b.baseArgs || [];
|
|
6418
|
+
const common = { pick: picked.how, stale: picked.stale === true, engine: form.engine };
|
|
6419
|
+
const plain = (bin, label) => Object.assign(common, {
|
|
6420
|
+
bin,
|
|
6421
|
+
args: baseArgs.concat([url]),
|
|
6422
|
+
via: "browser",
|
|
6423
|
+
isolated: false,
|
|
6424
|
+
watch: false,
|
|
6425
|
+
envKind: "sys",
|
|
6426
|
+
label,
|
|
6427
|
+
exitIsEvidence: ownsItsWindow("browser", pl)
|
|
6428
|
+
});
|
|
6429
|
+
if (form.direct && form.engine === "chromium" && o.profileDir) {
|
|
6430
|
+
const args = ["--incognito", "--user-data-dir=" + o.profileDir];
|
|
6431
|
+
if (Array.isArray(o.size) && o.size.length === 2) args.push("--window-size=" + o.size[0] + "," + o.size[1]);
|
|
6432
|
+
if (o.lang) args.push("--lang=" + o.lang);
|
|
6433
|
+
args.push("--no-first-run", "--no-default-browser-check", "--disable-session-crashed-bubble");
|
|
6434
|
+
return Object.assign(common, {
|
|
6435
|
+
bin: b.bin,
|
|
6436
|
+
args: [...baseArgs, ...args, url],
|
|
6437
|
+
via: "isolated",
|
|
6438
|
+
isolated: true,
|
|
6439
|
+
watch: true,
|
|
6440
|
+
envKind: "anti",
|
|
6441
|
+
label: "chromium",
|
|
6442
|
+
exitIsEvidence: ownsItsWindow("isolated", pl)
|
|
6443
|
+
});
|
|
6444
|
+
}
|
|
6445
|
+
if (form.direct && form.engine === "firefox" && o.profileDir) {
|
|
6446
|
+
return Object.assign(common, {
|
|
6447
|
+
bin: b.bin,
|
|
6448
|
+
args: [...baseArgs, "--no-remote", "--profile", o.profileDir, "-private-window", url],
|
|
6449
|
+
via: "isolated",
|
|
6450
|
+
isolated: true,
|
|
6451
|
+
watch: true,
|
|
6452
|
+
envKind: "anti",
|
|
6453
|
+
label: "firefox",
|
|
6454
|
+
exitIsEvidence: ownsItsWindow("isolated", pl)
|
|
6455
|
+
});
|
|
6456
|
+
}
|
|
6457
|
+
if (form.direct) return plain(b.bin, path2.basename(b.bin));
|
|
6458
|
+
const c = openCommand(pl, url);
|
|
6459
|
+
if (!c) return Object.assign(common, {
|
|
6460
|
+
bin: null,
|
|
6461
|
+
args: [url],
|
|
6462
|
+
via: "none",
|
|
6463
|
+
isolated: false,
|
|
6464
|
+
watch: false,
|
|
6465
|
+
envKind: "sys",
|
|
6466
|
+
label: null,
|
|
6467
|
+
exitIsEvidence: false
|
|
6468
|
+
});
|
|
6469
|
+
return Object.assign(common, {
|
|
6470
|
+
bin: c.cmd,
|
|
6471
|
+
args: c.args,
|
|
6472
|
+
via: "dispatcher",
|
|
6473
|
+
isolated: false,
|
|
6474
|
+
watch: false,
|
|
6475
|
+
envKind: "sys",
|
|
6476
|
+
label: c.cmd,
|
|
6477
|
+
exitIsEvidence: ownsItsWindow("dispatcher", pl)
|
|
6478
|
+
});
|
|
6479
|
+
}
|
|
6145
6480
|
function observeSpawn(child, windowMs, setTimeoutFn) {
|
|
6146
6481
|
return new Promise((resolve) => {
|
|
6147
6482
|
let settled = false;
|
|
@@ -6159,24 +6494,72 @@ var require_browser = __commonJS({
|
|
|
6159
6494
|
});
|
|
6160
6495
|
}
|
|
6161
6496
|
var OPEN_OBSERVE_MS = 1500;
|
|
6162
|
-
|
|
6497
|
+
var LOGIN_TZ_POOL = ["Asia/Shanghai", "Asia/Seoul", "Asia/Tokyo", "Asia/Singapore", "Europe/Berlin", "Europe/London", "Europe/Paris", "America/New_York", "America/Los_Angeles", "Australia/Sydney"];
|
|
6498
|
+
var LOGIN_LANG_POOL = ["zh-CN", "en-US", "en-GB", "ja-JP", "ko-KR", "de-DE", "fr-FR", "zh-TW"];
|
|
6499
|
+
var LOGIN_SIZE_POOL = [[1280, 800], [1366, 768], [1440, 900], [1536, 864], [1600, 900], [1680, 1050], [1920, 1080], [1024, 768], [1152, 864], [1280, 720]];
|
|
6500
|
+
function loginEnv(rand) {
|
|
6501
|
+
const pick = (arr) => arr[Math.floor((typeof rand === "function" ? rand() : Math.random()) * arr.length)];
|
|
6502
|
+
const size = pick(LOGIN_SIZE_POOL);
|
|
6503
|
+
const lang = pick(LOGIN_LANG_POOL);
|
|
6504
|
+
const tz = pick(LOGIN_TZ_POOL);
|
|
6505
|
+
const sysEnv = Object.assign({}, process.env, desktop.sessionEnv());
|
|
6506
|
+
return { size, lang, sysEnv, antiEnv: Object.assign({}, sysEnv, { TZ: tz, LANG: lang }) };
|
|
6507
|
+
}
|
|
6508
|
+
function launchDiagnostics(inv, plan, picked) {
|
|
6163
6509
|
const found = (inv && inv.browsers || []).map((b) => ({
|
|
6164
6510
|
name: b.name,
|
|
6165
6511
|
engine: b.engine || engineOf(b.bin),
|
|
6166
6512
|
via: (b.sources && b.sources.length ? b.sources : [b.source || "unknown"]).join("+")
|
|
6167
6513
|
}));
|
|
6514
|
+
const pk = picked || {};
|
|
6168
6515
|
return {
|
|
6169
6516
|
platform: inv && inv.platform || null,
|
|
6170
|
-
pick: how || plan && plan.pick || "none",
|
|
6517
|
+
pick: pk.how || plan && plan.pick || "none",
|
|
6171
6518
|
bin: plan && plan.bin || null,
|
|
6172
6519
|
default: inv && inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
|
|
6520
|
+
preference: pk.wanted ? { id: pk.wanted, matched: pk.stale !== true } : null,
|
|
6173
6521
|
found,
|
|
6174
6522
|
probed: inv && inv.probed || []
|
|
6175
6523
|
};
|
|
6176
6524
|
}
|
|
6525
|
+
function _spawnDetachedIgnored(bin, args) {
|
|
6526
|
+
try {
|
|
6527
|
+
const p = spawnOS.detachedIgnored(bin, args);
|
|
6528
|
+
p.on("error", () => {
|
|
6529
|
+
});
|
|
6530
|
+
p.unref();
|
|
6531
|
+
return p;
|
|
6532
|
+
} catch {
|
|
6533
|
+
return null;
|
|
6534
|
+
}
|
|
6535
|
+
}
|
|
6536
|
+
function _spawnDetached(bin, args, env, onExit) {
|
|
6537
|
+
let child;
|
|
6538
|
+
try {
|
|
6539
|
+
child = spawnOS.detachedIgnored(bin, args, { env: env || process.env });
|
|
6540
|
+
} catch {
|
|
6541
|
+
return null;
|
|
6542
|
+
}
|
|
6543
|
+
child.on("error", () => {
|
|
6544
|
+
});
|
|
6545
|
+
if (typeof onExit === "function") child.on("exit", () => {
|
|
6546
|
+
try {
|
|
6547
|
+
onExit();
|
|
6548
|
+
} catch {
|
|
6549
|
+
}
|
|
6550
|
+
});
|
|
6551
|
+
child.unref();
|
|
6552
|
+
return child;
|
|
6553
|
+
}
|
|
6554
|
+
function binAvailable(bin) {
|
|
6555
|
+
if (!bin) return false;
|
|
6556
|
+
if (bin.includes("/") || bin.includes("\\") || /^[A-Za-z]:[\\/]/.test(bin)) return isExecutableFile(bin);
|
|
6557
|
+
return resolveExecutable(bin) !== null;
|
|
6558
|
+
}
|
|
6177
6559
|
async function openBrowser(url, o) {
|
|
6178
6560
|
const opts = o || {};
|
|
6179
6561
|
const pl = opts.platform || process.platform;
|
|
6562
|
+
const intent = opts.intent === "isolated-login" ? "isolated-login" : "plain";
|
|
6180
6563
|
if (!isSafeHttpUrl(url)) {
|
|
6181
6564
|
return outcome({ ok: false, reason: "unsafe-url", url: String(url || ""), evidence: null });
|
|
6182
6565
|
}
|
|
@@ -6184,41 +6567,64 @@ var require_browser = __commonJS({
|
|
|
6184
6567
|
return outcome({ ok: false, reason: "unsupported-platform", url, evidence: { platform: pl } });
|
|
6185
6568
|
}
|
|
6186
6569
|
const observeMs = opts.observeMs === void 0 ? OPEN_OBSERVE_MS : opts.observeMs;
|
|
6187
|
-
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetachedIgnored;
|
|
6570
|
+
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : intent === "isolated-login" ? _spawnDetached : _spawnDetachedIgnored;
|
|
6188
6571
|
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
6189
6572
|
const observe = typeof opts.observe === "function" ? opts.observe : observeSpawn;
|
|
6190
|
-
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) =>
|
|
6573
|
+
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) => environment.browsers(Object.assign({ platform }, deps)));
|
|
6191
6574
|
const inv = "inventory" in opts ? opts.inventory : resolveInv(pl, opts.resolveDeps || {});
|
|
6192
|
-
const
|
|
6193
|
-
const
|
|
6575
|
+
const pref = "preference" in opts ? opts.preference : void 0;
|
|
6576
|
+
const login = intent === "isolated-login" ? loginEnv(opts.rand) : null;
|
|
6577
|
+
const picked = opts.pick || environment.pickLauncher(pl, inv, pref);
|
|
6578
|
+
const form = formOfBin(pl, picked.browser);
|
|
6579
|
+
const canIsolate = intent === "isolated-login" && form.direct && (form.engine === "chromium" || form.engine === "firefox");
|
|
6580
|
+
let profile = null;
|
|
6581
|
+
if (canIsolate) {
|
|
6582
|
+
const alloc = typeof opts.allocProfile === "function" ? opts.allocProfile : (() => allocTempDir("dsh-login-"));
|
|
6583
|
+
try {
|
|
6584
|
+
profile = opts.profileDir || alloc();
|
|
6585
|
+
} catch {
|
|
6586
|
+
profile = null;
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
const plan = intent === "isolated-login" ? isolatedPlan(pl, url, { inventory: inv, pick: picked, profileDir: profile, size: login.size, lang: login.lang }) : openPlan(pl, url, { inventory: inv, pick: picked });
|
|
6590
|
+
const diagnostics = launchDiagnostics(inv, plan, picked);
|
|
6194
6591
|
const evidence = {
|
|
6195
6592
|
bin: plan.bin,
|
|
6196
6593
|
engine: plan.engine,
|
|
6197
6594
|
via: plan.via,
|
|
6198
6595
|
ownsWindow: plan.exitIsEvidence === true,
|
|
6596
|
+
isolated: plan.isolated === true,
|
|
6597
|
+
profile: plan.isolated ? profile : null,
|
|
6598
|
+
watch: plan.watch === true,
|
|
6199
6599
|
exitCode: null,
|
|
6200
6600
|
exitSignal: null,
|
|
6201
6601
|
error: null,
|
|
6202
6602
|
diagnostics
|
|
6203
6603
|
};
|
|
6604
|
+
const deferredRemove = typeof opts.rmTree === "function" ? opts.rmTree : removeTreeDeferred;
|
|
6605
|
+
const fail = (reason, patch) => {
|
|
6606
|
+
if (profile) deferredRemove(profile, 0);
|
|
6607
|
+
return outcome(Object.assign({ ok: false, reason, url, evidence }, patch));
|
|
6608
|
+
};
|
|
6204
6609
|
const desktopAvailable = typeof opts.desktopAvailable === "function" ? opts.desktopAvailable : desktop.sessionAvailable;
|
|
6205
6610
|
if (pl === "linux" && !desktopAvailable()) {
|
|
6206
|
-
return
|
|
6611
|
+
return fail("no-desktop-session");
|
|
6207
6612
|
}
|
|
6208
|
-
if (!plan.bin)
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
return
|
|
6613
|
+
if (!plan.bin) return fail("no-launcher");
|
|
6614
|
+
if (!avail(plan.bin)) return fail("no-launcher");
|
|
6615
|
+
if (canIsolate && !profile) {
|
|
6616
|
+
evidence.error = "\u4E34\u65F6 profile \u76EE\u5F55\u5206\u914D\u5931\u8D25";
|
|
6617
|
+
return fail("spawn-failed");
|
|
6213
6618
|
}
|
|
6214
6619
|
let child;
|
|
6215
6620
|
try {
|
|
6216
|
-
child = spawnWith(plan.bin, plan.
|
|
6621
|
+
child = intent === "isolated-login" ? spawnWith(plan.bin, plan.args, plan.envKind === "anti" ? login.antiEnv : login.sysEnv, plan.watch ? opts.onExit : void 0) : spawnWith(plan.bin, plan.args);
|
|
6217
6622
|
} catch (e) {
|
|
6218
6623
|
evidence.error = e && e.code || String(e);
|
|
6219
|
-
return
|
|
6624
|
+
return fail("spawn-failed");
|
|
6220
6625
|
}
|
|
6221
|
-
if (!child) return
|
|
6626
|
+
if (!child) return fail("spawn-failed");
|
|
6627
|
+
if (evidence.profile) deferredRemove(evidence.profile, opts.profileMs === void 0 ? 30 * 60 * 1e3 : opts.profileMs);
|
|
6222
6628
|
const seen = await observe(child, observeMs, opts.setTimeout);
|
|
6223
6629
|
evidence.error = seen.stage === "error" ? String(seen.code) : null;
|
|
6224
6630
|
evidence.exitCode = seen.code === void 0 ? null : seen.code;
|
|
@@ -6236,137 +6642,17 @@ var require_browser = __commonJS({
|
|
|
6236
6642
|
}
|
|
6237
6643
|
return outcome({ ok: true, confirmed: exitDecides, handedOff: !exitDecides, url, evidence });
|
|
6238
6644
|
}
|
|
6239
|
-
function listBrowsers(o) {
|
|
6240
|
-
const ov = o || {};
|
|
6241
|
-
const inv = detector.inventory(ov.platform, { force: ov.force === true });
|
|
6242
|
-
return {
|
|
6243
|
-
ok: true,
|
|
6244
|
-
platform: inv.platform,
|
|
6245
|
-
cached: inv.cached === true,
|
|
6246
|
-
default: inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
|
|
6247
|
-
browsers: (inv.browsers || []).map((b) => ({
|
|
6248
|
-
id: b.id,
|
|
6249
|
-
name: b.name,
|
|
6250
|
-
engine: b.engine || engineOf(b.bin),
|
|
6251
|
-
bin: b.bin,
|
|
6252
|
-
sources: b.sources && b.sources.length ? b.sources : [b.source],
|
|
6253
|
-
isDefault: b.id === inv.defaultId
|
|
6254
|
-
})),
|
|
6255
|
-
probed: inv.probed || []
|
|
6256
|
-
};
|
|
6257
|
-
}
|
|
6258
|
-
function invalidateBrowsers(platform) {
|
|
6259
|
-
return detector.invalidate(platform);
|
|
6260
|
-
}
|
|
6261
|
-
function _spawnDetachedIgnored(bin, args) {
|
|
6262
|
-
try {
|
|
6263
|
-
const p = spawnOS.detachedIgnored(bin, args);
|
|
6264
|
-
p.on("error", () => {
|
|
6265
|
-
});
|
|
6266
|
-
p.unref();
|
|
6267
|
-
return p;
|
|
6268
|
-
} catch {
|
|
6269
|
-
return null;
|
|
6270
|
-
}
|
|
6271
|
-
}
|
|
6272
|
-
function _spawnDetached(bin, args, env, onExit) {
|
|
6273
|
-
let child;
|
|
6274
|
-
try {
|
|
6275
|
-
child = spawnOS.detachedIgnored(bin, args, { env: env || process.env });
|
|
6276
|
-
} catch {
|
|
6277
|
-
return null;
|
|
6278
|
-
}
|
|
6279
|
-
child.on("error", () => {
|
|
6280
|
-
});
|
|
6281
|
-
if (typeof onExit === "function") child.on("exit", () => {
|
|
6282
|
-
try {
|
|
6283
|
-
onExit();
|
|
6284
|
-
} catch {
|
|
6285
|
-
}
|
|
6286
|
-
});
|
|
6287
|
-
child.unref();
|
|
6288
|
-
return child;
|
|
6289
|
-
}
|
|
6290
|
-
function isolatedPlan(platform, url, opts) {
|
|
6291
|
-
const o = opts || {};
|
|
6292
|
-
const pl = platform || process.platform;
|
|
6293
|
-
const picked = o.pick || pickLauncher(pl, o.inventory);
|
|
6294
|
-
const b = picked.browser;
|
|
6295
|
-
const form = formOfBin(pl, b);
|
|
6296
|
-
const baseArgs = b && b.baseArgs || [];
|
|
6297
|
-
if (form.direct && form.engine === "chromium" && o.profileDir) {
|
|
6298
|
-
const args = ["--incognito", "--user-data-dir=" + o.profileDir];
|
|
6299
|
-
if (Array.isArray(o.size) && o.size.length === 2) args.push("--window-size=" + o.size[0] + "," + o.size[1]);
|
|
6300
|
-
if (o.lang) args.push("--lang=" + o.lang);
|
|
6301
|
-
args.push("--no-first-run", "--no-default-browser-check", "--disable-session-crashed-bubble");
|
|
6302
|
-
return { bin: b.bin, args: [...baseArgs, ...args, url], isolated: true, watch: true, envKind: "anti", label: "chromium", pick: picked.how };
|
|
6303
|
-
}
|
|
6304
|
-
if (form.direct && form.engine === "firefox" && o.profileDir) {
|
|
6305
|
-
return {
|
|
6306
|
-
bin: b.bin,
|
|
6307
|
-
args: [...baseArgs, "--no-remote", "--profile", o.profileDir, "-private-window", url],
|
|
6308
|
-
isolated: true,
|
|
6309
|
-
watch: true,
|
|
6310
|
-
envKind: "anti",
|
|
6311
|
-
label: "firefox",
|
|
6312
|
-
pick: picked.how
|
|
6313
|
-
};
|
|
6314
|
-
}
|
|
6315
|
-
if (form.direct) {
|
|
6316
|
-
return { bin: b.bin, args: baseArgs.concat([url]), isolated: false, watch: false, envKind: "sys", label: path2.basename(b.bin), pick: picked.how };
|
|
6317
|
-
}
|
|
6318
|
-
const c = openCommand(pl, url);
|
|
6319
|
-
if (!c) return { bin: null, args: [url], isolated: false, watch: false, envKind: "sys", label: null, pick: picked.how };
|
|
6320
|
-
return { bin: c.cmd, args: c.args, isolated: false, watch: false, envKind: "sys", label: c.cmd, pick: picked.how };
|
|
6321
|
-
}
|
|
6322
|
-
function binAvailable(bin) {
|
|
6323
|
-
if (!bin) return false;
|
|
6324
|
-
if (bin.includes("/") || bin.includes("\\") || /^[A-Za-z]:[\\/]/.test(bin)) return isExecutableFile(bin);
|
|
6325
|
-
return resolveExecutable(bin) !== null;
|
|
6326
|
-
}
|
|
6327
|
-
function launchIsolated(url, o) {
|
|
6328
|
-
const opts = o || {};
|
|
6329
|
-
if (!isSafeHttpUrl(url)) return Object.assign(outcome({ ok: false, reason: "unsafe-url", url: String(url || "") }), { bin: null, isolated: false });
|
|
6330
|
-
const antiEnv = opts.antiEnv || opts.sysEnv || process.env;
|
|
6331
|
-
const sysEnv = opts.sysEnv || process.env;
|
|
6332
|
-
const onExit = opts.onExit;
|
|
6333
|
-
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
6334
|
-
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetached;
|
|
6335
|
-
const fail = (reason, extra) => Object.assign(outcome(Object.assign({ ok: false, reason, url }, extra)), { bin: null, isolated: false });
|
|
6336
|
-
try {
|
|
6337
|
-
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) => detector.inventory(platform, deps));
|
|
6338
|
-
const inv = "inventory" in opts ? opts.inventory : resolveInv(process.platform, opts.resolveDeps || {});
|
|
6339
|
-
const plan = isolatedPlan(process.platform, url, {
|
|
6340
|
-
inventory: inv,
|
|
6341
|
-
pick: opts.pick,
|
|
6342
|
-
profileDir: opts.profileDir,
|
|
6343
|
-
size: opts.size,
|
|
6344
|
-
lang: opts.lang
|
|
6345
|
-
});
|
|
6346
|
-
const evidence = { bin: plan.bin, engine: plan.label, via: plan.isolated ? "browser" : "dispatcher", diagnostics: launchDiagnostics(inv, plan, plan.pick) };
|
|
6347
|
-
if (!avail(plan.bin)) return fail("no-launcher", { evidence });
|
|
6348
|
-
const env = plan.envKind === "anti" ? antiEnv : sysEnv;
|
|
6349
|
-
const p = spawnWith(plan.bin, plan.args, env, plan.watch ? onExit : void 0);
|
|
6350
|
-
if (!p) return fail("spawn-failed", { evidence });
|
|
6351
|
-
return Object.assign(outcome({ ok: true, confirmed: false, handedOff: true, url, evidence }), { bin: plan.label, isolated: plan.isolated });
|
|
6352
|
-
} catch (e) {
|
|
6353
|
-
return fail("spawn-failed", { error: FAILURE_TEXT["spawn-failed"] + "\uFF08" + (e && e.code || e) + "\uFF09" });
|
|
6354
|
-
}
|
|
6355
|
-
}
|
|
6356
6645
|
module2.exports = {
|
|
6357
6646
|
openBrowser,
|
|
6358
|
-
launchIsolated,
|
|
6359
6647
|
openCommand,
|
|
6360
6648
|
openPlan,
|
|
6361
6649
|
isolatedPlan,
|
|
6362
|
-
pickLauncher,
|
|
6363
6650
|
ownsItsWindow,
|
|
6364
6651
|
observeSpawn,
|
|
6365
6652
|
isSafeHttpUrl,
|
|
6366
6653
|
binAvailable,
|
|
6367
|
-
listBrowsers,
|
|
6368
|
-
invalidateBrowsers,
|
|
6369
6654
|
launchDiagnostics,
|
|
6655
|
+
loginEnv,
|
|
6370
6656
|
// 探测层的解析原语经此转出(唯一实现处在 ./browser-inventory.js):门禁与消费方按同一出口取用,
|
|
6371
6657
|
// 不在别处再写第二份平台解析。
|
|
6372
6658
|
engineOf,
|
|
@@ -6723,6 +7009,7 @@ var require_os = __commonJS({
|
|
|
6723
7009
|
var execPath = require_exec_path();
|
|
6724
7010
|
var desktop = require_desktop();
|
|
6725
7011
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
7012
|
+
var environment = require_environment();
|
|
6726
7013
|
var PLATFORM = process.platform;
|
|
6727
7014
|
var ARCH = process.arch;
|
|
6728
7015
|
var isLinux = PLATFORM === "linux";
|
|
@@ -6777,6 +7064,7 @@ var require_os = __commonJS({
|
|
|
6777
7064
|
}
|
|
6778
7065
|
return p;
|
|
6779
7066
|
}
|
|
7067
|
+
environment.bind({ capabilities });
|
|
6780
7068
|
module2.exports = {
|
|
6781
7069
|
PLATFORM,
|
|
6782
7070
|
ARCH,
|
|
@@ -6800,6 +7088,8 @@ var require_os = __commonJS({
|
|
|
6800
7088
|
// 导出模块对象会抛 platform.notify is not a function,把升级终态误判成失败。
|
|
6801
7089
|
notify: require_notify().notify,
|
|
6802
7090
|
browser: require_browser(),
|
|
7091
|
+
environment,
|
|
7092
|
+
// 环境表单(外部打开链路的事实底座 + 选路依据)
|
|
6803
7093
|
desktop,
|
|
6804
7094
|
// 图形会话可用性(Linux 需实测 socket)
|
|
6805
7095
|
autostart: require_autostart()
|
|
@@ -12918,6 +13208,60 @@ var require_access = __commonJS({
|
|
|
12918
13208
|
}
|
|
12919
13209
|
});
|
|
12920
13210
|
|
|
13211
|
+
// src/app/settings/browser.js
|
|
13212
|
+
var require_browser2 = __commonJS({
|
|
13213
|
+
"src/app/settings/browser.js"(exports2, module2) {
|
|
13214
|
+
"use strict";
|
|
13215
|
+
var platform = require_os();
|
|
13216
|
+
var { verifyPersisted } = require_access();
|
|
13217
|
+
module2.exports = {
|
|
13218
|
+
methods: {
|
|
13219
|
+
/** 当前偏好 + 候选清单 + 这一拍的分发依据(面板据此渲染选择器并说明「现在实际会用谁」)。 */
|
|
13220
|
+
externalBrowserStatus() {
|
|
13221
|
+
try {
|
|
13222
|
+
const form = platform.environment.form();
|
|
13223
|
+
const v = platform.environment.checkPreference(platform.environment.preferenceId(), form);
|
|
13224
|
+
return {
|
|
13225
|
+
ok: true,
|
|
13226
|
+
configured: !!form.preference && form.preference.configured === true,
|
|
13227
|
+
value: form.preference && form.preference.id || null,
|
|
13228
|
+
// stale=true:偏好所指已不在候选清单(被卸载/路径失效),本次分发已回落,需用户重选。
|
|
13229
|
+
stale: !!(form.pick && form.pick.stale),
|
|
13230
|
+
browser: v.browser,
|
|
13231
|
+
candidates: v.candidates,
|
|
13232
|
+
pick: form.pick || null,
|
|
13233
|
+
platform: form.platform
|
|
13234
|
+
};
|
|
13235
|
+
} catch (e) {
|
|
13236
|
+
return { ok: false, error: e.message };
|
|
13237
|
+
}
|
|
13238
|
+
},
|
|
13239
|
+
/** 设置/清除浏览器偏好(空串=清除,回到「按系统默认或候选次序分发」)。 */
|
|
13240
|
+
setExternalBrowser(id) {
|
|
13241
|
+
try {
|
|
13242
|
+
const form = platform.environment.form();
|
|
13243
|
+
const v = platform.environment.checkPreference(id, form);
|
|
13244
|
+
if (!v.ok) return { ok: false, error: v.error };
|
|
13245
|
+
const cfg = this.config || {};
|
|
13246
|
+
cfg.externalBrowser = v.id;
|
|
13247
|
+
const patch = { externalBrowser: v.id };
|
|
13248
|
+
if (this.configPath) {
|
|
13249
|
+
this.state.persistConfigPatch(patch);
|
|
13250
|
+
const persistError = verifyPersisted(this.configPath, patch);
|
|
13251
|
+
if (persistError) return { ok: false, error: persistError };
|
|
13252
|
+
}
|
|
13253
|
+
platform.environment.invalidate();
|
|
13254
|
+
if (this.events) this.events.append("external_browser_changed", { id: v.id, name: v.browser ? v.browser.name : null });
|
|
13255
|
+
return { ok: true, configured: !!v.id, value: v.id, browser: v.browser };
|
|
13256
|
+
} catch (e) {
|
|
13257
|
+
return { ok: false, error: e.message };
|
|
13258
|
+
}
|
|
13259
|
+
}
|
|
13260
|
+
}
|
|
13261
|
+
};
|
|
13262
|
+
}
|
|
13263
|
+
});
|
|
13264
|
+
|
|
12921
13265
|
// src/platform/os/netinfo.js
|
|
12922
13266
|
var require_netinfo = __commonJS({
|
|
12923
13267
|
"src/platform/os/netinfo.js"(exports2, module2) {
|
|
@@ -13135,6 +13479,7 @@ var require_facets = __commonJS({
|
|
|
13135
13479
|
{ name: "settings/node-lts", mod: require_node_lts() },
|
|
13136
13480
|
{ name: "settings/versions", mod: require_versions() },
|
|
13137
13481
|
{ name: "settings/access", mod: require_access() },
|
|
13482
|
+
{ name: "settings/browser", mod: require_browser2() },
|
|
13138
13483
|
{ name: "settings/lan-panel", mod: require_lan_panel() }
|
|
13139
13484
|
];
|
|
13140
13485
|
function installMethods(host2, methods) {
|
|
@@ -14677,6 +15022,7 @@ var require_core5 = __commonJS({
|
|
|
14677
15022
|
function composeCore(host2, rawConfig, configPath) {
|
|
14678
15023
|
host2.config = normalize(rawConfig, domainConfigExtension2());
|
|
14679
15024
|
host2.configPath = typeof configPath === "string" ? configPath : null;
|
|
15025
|
+
platform.environment.bind({ preference: () => host2.config && host2.config.externalBrowser || null });
|
|
14680
15026
|
host2._fileProtectStatus = null;
|
|
14681
15027
|
try {
|
|
14682
15028
|
const fp = platform.fileProtect;
|
|
@@ -18211,58 +18557,13 @@ var require_forward_core = __commonJS({
|
|
|
18211
18557
|
}
|
|
18212
18558
|
});
|
|
18213
18559
|
|
|
18214
|
-
// src/domains/router/ops/browser.js
|
|
18215
|
-
var require_browser2 = __commonJS({
|
|
18216
|
-
"src/domains/router/ops/browser.js"(exports2, module2) {
|
|
18217
|
-
"use strict";
|
|
18218
|
-
var platform = require_os();
|
|
18219
|
-
var desktop = require_desktop();
|
|
18220
|
-
var fs2 = require("node:fs");
|
|
18221
|
-
var os2 = require("node:os");
|
|
18222
|
-
var path2 = require("node:path");
|
|
18223
|
-
var crypto = require("node:crypto");
|
|
18224
|
-
function graphicalEnv() {
|
|
18225
|
-
return desktop.sessionEnv();
|
|
18226
|
-
}
|
|
18227
|
-
function openInBrowser(url, onExit) {
|
|
18228
|
-
try {
|
|
18229
|
-
const tmpProfile = path2.join(os2.tmpdir(), "dsh-oauth-" + crypto.randomBytes(8).toString("hex"));
|
|
18230
|
-
const sysEnv = Object.assign({}, process.env, graphicalEnv());
|
|
18231
|
-
const TZ_POOL = ["Asia/Shanghai", "Asia/Seoul", "Asia/Tokyo", "Asia/Singapore", "Europe/Berlin", "Europe/London", "Europe/Paris", "America/New_York", "America/Los_Angeles", "Australia/Sydney"];
|
|
18232
|
-
const LANG_POOL = ["zh-CN", "en-US", "en-GB", "ja-JP", "ko-KR", "de-DE", "fr-FR", "zh-TW"];
|
|
18233
|
-
const SIZE_POOL = [[1280, 800], [1366, 768], [1440, 900], [1536, 864], [1600, 900], [1680, 1050], [1920, 1080], [1024, 768], [1152, 864], [1280, 720]];
|
|
18234
|
-
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
18235
|
-
const size = pick(SIZE_POOL);
|
|
18236
|
-
const lang = pick(LANG_POOL);
|
|
18237
|
-
const tz = pick(TZ_POOL);
|
|
18238
|
-
const antiEnv = Object.assign({}, sysEnv, { TZ: tz, LANG: lang });
|
|
18239
|
-
const r = platform.browser.launchIsolated(url, { profileDir: tmpProfile, size, lang, antiEnv, sysEnv, onExit });
|
|
18240
|
-
if (!r || !r.ok) return { profile: null, result: r || { ok: false, reason: "spawn-failed" } };
|
|
18241
|
-
if (r.isolated) {
|
|
18242
|
-
const t30 = setTimeout(() => {
|
|
18243
|
-
try {
|
|
18244
|
-
fs2.rmSync(tmpProfile, { recursive: true, force: true });
|
|
18245
|
-
} catch {
|
|
18246
|
-
}
|
|
18247
|
-
}, 30 * 60 * 1e3);
|
|
18248
|
-
if (t30.unref) t30.unref();
|
|
18249
|
-
}
|
|
18250
|
-
return { profile: tmpProfile, result: r };
|
|
18251
|
-
} catch (e) {
|
|
18252
|
-
return { profile: null, result: { ok: false, reason: "spawn-failed", error: "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF1A" + (e && e.message || e) } };
|
|
18253
|
-
}
|
|
18254
|
-
}
|
|
18255
|
-
module2.exports = { graphicalEnv, openInBrowser };
|
|
18256
|
-
}
|
|
18257
|
-
});
|
|
18258
|
-
|
|
18259
18560
|
// src/domains/router/ops/oauth.js
|
|
18260
18561
|
var require_oauth = __commonJS({
|
|
18261
18562
|
"src/domains/router/ops/oauth.js"(exports2, module2) {
|
|
18262
18563
|
"use strict";
|
|
18263
|
-
var fs2 = require("node:fs");
|
|
18264
18564
|
var crypto = require("node:crypto");
|
|
18265
18565
|
var { createServer } = require("node:http");
|
|
18566
|
+
var { removeTreeDeferred } = require_fs();
|
|
18266
18567
|
function createOAuthOps(deps) {
|
|
18267
18568
|
const d = deps || {};
|
|
18268
18569
|
const ports = d.ports;
|
|
@@ -18427,20 +18728,21 @@ var require_oauth = __commonJS({
|
|
|
18427
18728
|
promise.catch(() => {
|
|
18428
18729
|
});
|
|
18429
18730
|
st._ccLoginPromise = promise;
|
|
18430
|
-
const opened = openInBrowser(authUrl, () => {
|
|
18731
|
+
const opened = await openInBrowser(authUrl, () => {
|
|
18431
18732
|
if (st._ccLoginRound !== roundId) return;
|
|
18432
18733
|
if (st._ccLoginReject) {
|
|
18433
|
-
const
|
|
18734
|
+
const r2 = st._ccLoginReject;
|
|
18434
18735
|
st._ccLoginReject = null;
|
|
18435
18736
|
st._ccLoginResolve = null;
|
|
18436
18737
|
try {
|
|
18437
|
-
|
|
18738
|
+
r2(new Error("\u6D4F\u89C8\u5668\u5DF2\u5173\u95ED\uFF0C\u767B\u5F55\u5DF2\u53D6\u6D88"));
|
|
18438
18739
|
} catch {
|
|
18439
18740
|
}
|
|
18440
18741
|
}
|
|
18441
18742
|
});
|
|
18442
|
-
const
|
|
18443
|
-
|
|
18743
|
+
const r = opened || { ok: false, reason: "spawn-failed" };
|
|
18744
|
+
const ev = r.evidence || {};
|
|
18745
|
+
if (!r.ok) {
|
|
18444
18746
|
st._ccLoginPromise = null;
|
|
18445
18747
|
st._ccLoginResolve = null;
|
|
18446
18748
|
st._ccLoginReject = null;
|
|
@@ -18460,13 +18762,13 @@ var require_oauth = __commonJS({
|
|
|
18460
18762
|
opened: false,
|
|
18461
18763
|
confirmed: false,
|
|
18462
18764
|
handedOff: false,
|
|
18463
|
-
reason:
|
|
18464
|
-
evidence:
|
|
18465
|
-
error: (
|
|
18765
|
+
reason: r.reason || "no-launcher",
|
|
18766
|
+
evidence: r.evidence || null,
|
|
18767
|
+
error: (r.error || "\u65E0\u6CD5\u8C03\u8D77\u7CFB\u7EDF\u6D4F\u89C8\u5668") + "\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u4E0B\u65B9\u5730\u5740\u5B8C\u6210\u6388\u6743"
|
|
18466
18768
|
};
|
|
18467
18769
|
}
|
|
18468
|
-
st._ccLogin = { state, port, server, tmpProfile:
|
|
18469
|
-
return Object.assign({},
|
|
18770
|
+
st._ccLogin = { state, port, server, tmpProfile: ev.profile || null };
|
|
18771
|
+
return Object.assign({}, r, {
|
|
18470
18772
|
ok: true,
|
|
18471
18773
|
authUrl,
|
|
18472
18774
|
url: authUrl,
|
|
@@ -18474,8 +18776,8 @@ var require_oauth = __commonJS({
|
|
|
18474
18776
|
port,
|
|
18475
18777
|
waitMs: 18e4,
|
|
18476
18778
|
opened: true,
|
|
18477
|
-
// 非隔离引擎(Safari
|
|
18478
|
-
isolated:
|
|
18779
|
+
// 非隔离引擎(Safari/打包器包装)由平台层降级:账号隔离不成立,换账号只能靠超时重发或手动窗口。
|
|
18780
|
+
isolated: ev.isolated === true
|
|
18479
18781
|
});
|
|
18480
18782
|
}
|
|
18481
18783
|
async function commandcodeLoginWait(timeoutMs) {
|
|
@@ -18521,15 +18823,7 @@ var require_oauth = __commonJS({
|
|
|
18521
18823
|
st._ccLoginResolve = st._ccLoginReject = null;
|
|
18522
18824
|
return { ok: false, error: e.message };
|
|
18523
18825
|
} finally {
|
|
18524
|
-
if (tmpProfile)
|
|
18525
|
-
const t60 = setTimeout(() => {
|
|
18526
|
-
try {
|
|
18527
|
-
fs2.rmSync(tmpProfile, { recursive: true, force: true });
|
|
18528
|
-
} catch {
|
|
18529
|
-
}
|
|
18530
|
-
}, 60 * 1e3);
|
|
18531
|
-
if (t60.unref) t60.unref();
|
|
18532
|
-
}
|
|
18826
|
+
if (tmpProfile) removeTreeDeferred(tmpProfile, 60 * 1e3);
|
|
18533
18827
|
}
|
|
18534
18828
|
}
|
|
18535
18829
|
return { commandcodeLoginStart, commandcodeLoginWait };
|
|
@@ -18983,8 +19277,8 @@ var require_router_ops = __commonJS({
|
|
|
18983
19277
|
"use strict";
|
|
18984
19278
|
require_port_segments();
|
|
18985
19279
|
var ports = require_ports().shared;
|
|
19280
|
+
var platform = require_os();
|
|
18986
19281
|
var { maskKey } = require_base();
|
|
18987
|
-
var { openInBrowser } = require_browser2();
|
|
18988
19282
|
var { createOAuthOps } = require_oauth();
|
|
18989
19283
|
var { createAppsRegistryOps } = require_apps_registry();
|
|
18990
19284
|
var { createQuotaSyncOps } = require_quotasync();
|
|
@@ -18992,6 +19286,7 @@ var require_router_ops = __commonJS({
|
|
|
18992
19286
|
function createAuxCore(deps) {
|
|
18993
19287
|
const d = deps || {};
|
|
18994
19288
|
const getProviders = d.getProviders || (() => []);
|
|
19289
|
+
const openInBrowser = (url, onExit) => platform.browser.openBrowser(url, { intent: "isolated-login", onExit });
|
|
18995
19290
|
const oauth = createOAuthOps({ ports, openInBrowser });
|
|
18996
19291
|
const apps = createAppsRegistryOps({
|
|
18997
19292
|
getProviders,
|
|
@@ -26009,7 +26304,7 @@ var require_guard = __commonJS({
|
|
|
26009
26304
|
var fs2 = require("node:fs");
|
|
26010
26305
|
var path2 = require("node:path");
|
|
26011
26306
|
function owns(pathname) {
|
|
26012
|
-
return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/env/
|
|
26307
|
+
return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/env/environment" || pathname === "/ports" || pathname === "/shutdown";
|
|
26013
26308
|
}
|
|
26014
26309
|
function fetchDshChangelog(res, sup) {
|
|
26015
26310
|
const v = sup && sup.nativeManager ? sup.nativeManager.versionInfo() : {};
|
|
@@ -26021,7 +26316,7 @@ var require_guard = __commonJS({
|
|
|
26021
26316
|
return res.end(md);
|
|
26022
26317
|
}
|
|
26023
26318
|
function handle(ctx) {
|
|
26024
|
-
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, browser } = ctx;
|
|
26319
|
+
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, browser, environment } = ctx;
|
|
26025
26320
|
if (req.method === "GET" && pathname === "/changelog") {
|
|
26026
26321
|
return fetchDshChangelog(res, sup);
|
|
26027
26322
|
}
|
|
@@ -26127,6 +26422,31 @@ var require_guard = __commonJS({
|
|
|
26127
26422
|
});
|
|
26128
26423
|
return;
|
|
26129
26424
|
}
|
|
26425
|
+
if (req.method === "GET" && pathname === "/settings/external-browser") {
|
|
26426
|
+
return send(200, sup.externalBrowserStatus());
|
|
26427
|
+
}
|
|
26428
|
+
if (req.method === "POST" && pathname === "/settings/external-browser") {
|
|
26429
|
+
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26430
|
+
req.resume();
|
|
26431
|
+
return send(403, {});
|
|
26432
|
+
}
|
|
26433
|
+
collectBody(req, res, 2048, (body) => {
|
|
26434
|
+
let id = null;
|
|
26435
|
+
let given = false;
|
|
26436
|
+
try {
|
|
26437
|
+
const j = body ? JSON.parse(body) : {};
|
|
26438
|
+
if (typeof j.id === "string") {
|
|
26439
|
+
id = j.id;
|
|
26440
|
+
given = true;
|
|
26441
|
+
}
|
|
26442
|
+
} catch {
|
|
26443
|
+
}
|
|
26444
|
+
if (!given) return send(400, { ok: false, error: '\u9700\u8981 {"id":"<\u5019\u9009 id>"}\uFF08\u7A7A\u4E32\u6E05\u9664\u504F\u597D\uFF09' });
|
|
26445
|
+
const r = sup.setExternalBrowser(id);
|
|
26446
|
+
return send(r.ok ? 200 : 500, r);
|
|
26447
|
+
});
|
|
26448
|
+
return;
|
|
26449
|
+
}
|
|
26130
26450
|
if (req.method === "POST" && pathname === "/shutdown") {
|
|
26131
26451
|
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26132
26452
|
req.resume();
|
|
@@ -26185,13 +26505,13 @@ var require_guard = __commonJS({
|
|
|
26185
26505
|
if (req.method === "GET" && pathname === "/env/node-lts") {
|
|
26186
26506
|
return sup.nodeLtsStatus().then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
|
|
26187
26507
|
}
|
|
26188
|
-
if (req.method === "GET" && pathname === "/env/
|
|
26508
|
+
if (req.method === "GET" && pathname === "/env/environment") {
|
|
26189
26509
|
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26190
26510
|
req.resume();
|
|
26191
26511
|
return send(403, { ok: false, error: "cross-origin request rejected" });
|
|
26192
26512
|
}
|
|
26193
|
-
const force = /[?&]force=1/.test(req.url || "");
|
|
26194
|
-
return Promise.resolve(
|
|
26513
|
+
const force = /[?&]force=1/.test(String(req.url || ""));
|
|
26514
|
+
return Promise.resolve(environment.form({ force, persist: force })).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: "\u73AF\u5883\u8868\u5355\u88C5\u914D\u5931\u8D25\uFF1A" + (e && e.message || e) }));
|
|
26195
26515
|
}
|
|
26196
26516
|
if (req.method === "POST" && pathname === "/env/open-url") {
|
|
26197
26517
|
if (!identity.loopback) {
|
|
@@ -27328,6 +27648,7 @@ var require_server = __commonJS({
|
|
|
27328
27648
|
var { identify } = require_identity3();
|
|
27329
27649
|
var { originAllowed, requestHasAccessKey, isShellOrigin } = require_security();
|
|
27330
27650
|
var browserExit = require_browser();
|
|
27651
|
+
var environmentExit = require_environment();
|
|
27331
27652
|
function safeFail(res, err, where) {
|
|
27332
27653
|
try {
|
|
27333
27654
|
const body = JSON.stringify({ ok: false, error: err && err.message || String(err) });
|
|
@@ -27347,6 +27668,7 @@ var require_server = __commonJS({
|
|
|
27347
27668
|
}
|
|
27348
27669
|
function createServer(sup, deps) {
|
|
27349
27670
|
const browser = deps && deps.browser || browserExit;
|
|
27671
|
+
const environment = deps && deps.environment || environmentExit;
|
|
27350
27672
|
return http2.createServer((req, res) => {
|
|
27351
27673
|
const shellOrigin = (() => {
|
|
27352
27674
|
const o = req.headers.origin;
|
|
@@ -27414,7 +27736,7 @@ var require_server = __commonJS({
|
|
|
27414
27736
|
} catch (e) {
|
|
27415
27737
|
return send(400, { error: "bad request encoding" });
|
|
27416
27738
|
}
|
|
27417
|
-
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf, browser };
|
|
27739
|
+
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf, browser, environment };
|
|
27418
27740
|
for (const d of API_DOMAINS) {
|
|
27419
27741
|
if (d.owns(pathname)) {
|
|
27420
27742
|
try {
|