@myassis/gateway 1.0.39 → 1.0.41
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.
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.updateService = exports.checkForUpdates = exports.restartService = exports.stopService = exports.startService = exports.uninstallService = exports.installService = exports.getServiceInfo = exports.SERVICE_DISPLAY_NAME = exports.SERVICE_NAME = void 0;
|
|
6
|
+
exports.execAsUser = exports.isHelperReady = exports.stopHelper = exports.updateService = exports.checkForUpdates = exports.restartService = exports.stopService = exports.startService = exports.uninstallService = exports.installService = exports.getServiceInfo = exports.SERVICE_DISPLAY_NAME = exports.SERVICE_NAME = void 0;
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const util_1 = require("util");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
@@ -11,6 +11,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
const axios_1 = __importDefault(require("axios"));
|
|
12
12
|
const shared_1 = require("@myassis/shared");
|
|
13
13
|
const os_1 = __importDefault(require("os"));
|
|
14
|
+
const net_1 = __importDefault(require("net"));
|
|
14
15
|
const logger = (0, shared_1.getLogger)('ServiceManager');
|
|
15
16
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
16
17
|
exports.SERVICE_NAME = 'myassis-gateway';
|
|
@@ -549,3 +550,299 @@ async function updateService() {
|
|
|
549
550
|
}
|
|
550
551
|
}
|
|
551
552
|
exports.updateService = updateService;
|
|
553
|
+
// ═══════════════════════════════════════════════════════════
|
|
554
|
+
// 用户态 Helper 进程管理 — Windows 专用
|
|
555
|
+
// 目标:在当前登录用户的桌面会话中以该用户身份执行命令
|
|
556
|
+
// 架构:
|
|
557
|
+
// Service (SYSTEM) ──TCP/IPC──> Helper (当前登录用户)
|
|
558
|
+
// ═══════════════════════════════════════════════════════════
|
|
559
|
+
/** IPC 端口号(Service <-> Helper 通信) */
|
|
560
|
+
const HELPER_PORT = 19630;
|
|
561
|
+
/** Helper 超时时间(毫秒) */
|
|
562
|
+
const HELPER_TIMEOUT_MS = 60000;
|
|
563
|
+
/** 当前活跃的 Helper 进程 */
|
|
564
|
+
let helperProcess = null;
|
|
565
|
+
/** Helper 连接 socket */
|
|
566
|
+
let helperSocket = null;
|
|
567
|
+
/** Helper 是否就绪 */
|
|
568
|
+
let helperReady = false;
|
|
569
|
+
/** Helper 等待队列 */
|
|
570
|
+
const helperPending = new Map();
|
|
571
|
+
/**
|
|
572
|
+
* Helper Socket 收到的数据缓冲区(可能跨多条消息)
|
|
573
|
+
*/
|
|
574
|
+
let helperDataBuf = '';
|
|
575
|
+
/**
|
|
576
|
+
* 处理 Helper 返回的数据(JSON 数组,可能跨多次 TCP 推送)
|
|
577
|
+
*/
|
|
578
|
+
function handleHelperData(chunk) {
|
|
579
|
+
helperDataBuf += chunk;
|
|
580
|
+
// Helper 可能一次推送多条 JSON 行(每条以 \n 结尾)
|
|
581
|
+
const lines = helperDataBuf.split('\n');
|
|
582
|
+
// 保留最后不完整的行(等待下一块数据)
|
|
583
|
+
helperDataBuf = lines.pop() || '';
|
|
584
|
+
for (const line of lines) {
|
|
585
|
+
if (!line.trim())
|
|
586
|
+
continue;
|
|
587
|
+
try {
|
|
588
|
+
const resp = JSON.parse(line);
|
|
589
|
+
const pending = helperPending.get(resp.id);
|
|
590
|
+
if (!pending)
|
|
591
|
+
continue;
|
|
592
|
+
clearTimeout(pending.timer);
|
|
593
|
+
helperPending.delete(resp.id);
|
|
594
|
+
if (resp.success) {
|
|
595
|
+
pending.resolve({ stdout: resp.stdout || '', stderr: resp.stderr || '', exitCode: resp.exitCode ?? 0 });
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
pending.reject(new Error(resp.error || 'Helper command failed'));
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
catch { /* ignore parse errors */ }
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* 停止 Helper 进程
|
|
606
|
+
*/
|
|
607
|
+
async function stopHelper() {
|
|
608
|
+
helperReady = false;
|
|
609
|
+
if (helperSocket) {
|
|
610
|
+
try {
|
|
611
|
+
helperSocket.destroy();
|
|
612
|
+
}
|
|
613
|
+
catch { /* ignore */ }
|
|
614
|
+
helperSocket = null;
|
|
615
|
+
}
|
|
616
|
+
if (helperProcess) {
|
|
617
|
+
try {
|
|
618
|
+
helperProcess.kill();
|
|
619
|
+
}
|
|
620
|
+
catch { /* ignore */ }
|
|
621
|
+
helperProcess = null;
|
|
622
|
+
}
|
|
623
|
+
for (const [id, p] of helperPending) {
|
|
624
|
+
clearTimeout(p.timer);
|
|
625
|
+
p.reject(new Error('Helper stopped'));
|
|
626
|
+
}
|
|
627
|
+
helperPending.clear();
|
|
628
|
+
}
|
|
629
|
+
exports.stopHelper = stopHelper;
|
|
630
|
+
/**
|
|
631
|
+
* 查询 Helper 是否就绪
|
|
632
|
+
*/
|
|
633
|
+
function isHelperReady() {
|
|
634
|
+
return helperReady && helperSocket !== null;
|
|
635
|
+
}
|
|
636
|
+
exports.isHelperReady = isHelperReady;
|
|
637
|
+
/**
|
|
638
|
+
* 通过 Helper 进程执行命令(以当前登录用户身份)
|
|
639
|
+
*/
|
|
640
|
+
async function execAsUser(command, cwd) {
|
|
641
|
+
// 确保 Helper 已启动
|
|
642
|
+
if (!helperReady || !helperSocket) {
|
|
643
|
+
const started = await spawnHelperAsUser();
|
|
644
|
+
if (!started) {
|
|
645
|
+
return { stdout: '', stderr: 'Failed to start helper process', exitCode: -1 };
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
const id = newCmdId();
|
|
649
|
+
const timeout = HELPER_TIMEOUT_MS;
|
|
650
|
+
return new Promise((resolve, reject) => {
|
|
651
|
+
const timer = setTimeout(() => {
|
|
652
|
+
helperPending.delete(id);
|
|
653
|
+
reject(new Error('Command timeout'));
|
|
654
|
+
}, timeout);
|
|
655
|
+
helperPending.set(id, { resolve, reject, timer });
|
|
656
|
+
const req = JSON.stringify({ id, command, cwd: cwd || os_1.default.homedir() });
|
|
657
|
+
const data = Buffer.from(req + '\n', 'utf8');
|
|
658
|
+
if (!helperSocket) {
|
|
659
|
+
clearTimeout(timer);
|
|
660
|
+
helperPending.delete(id);
|
|
661
|
+
reject(new Error('Helper socket not available'));
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
helperSocket.once('error', (err) => {
|
|
665
|
+
clearTimeout(timer);
|
|
666
|
+
helperPending.delete(id);
|
|
667
|
+
helperReady = false;
|
|
668
|
+
reject(err);
|
|
669
|
+
});
|
|
670
|
+
helperSocket.write(data, () => {
|
|
671
|
+
// 等待 Helper 响应(由 handleHelperData 处理)
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
exports.execAsUser = execAsUser;
|
|
676
|
+
/**
|
|
677
|
+
* 生成随机命令 ID
|
|
678
|
+
*/
|
|
679
|
+
function newCmdId() {
|
|
680
|
+
return Date.now() + '-' + Math.random().toString(36).slice(2, 9);
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* 生成 Helper 的 PowerShell 执行脚本
|
|
684
|
+
*/
|
|
685
|
+
function buildHelperScript() {
|
|
686
|
+
const l = [];
|
|
687
|
+
const push = (x) => l.push(x);
|
|
688
|
+
push('# User Helper Process - Myassis Gateway');
|
|
689
|
+
push('$port = ' + HELPER_PORT);
|
|
690
|
+
push("$ErrorActionPreference = 'Stop'");
|
|
691
|
+
push('function Write-Log { param([string]$m) Write-Host "[$(Get-Date -Format HH:mm:ss)] $m" }');
|
|
692
|
+
push('Write-Log "helper started (PID=$PID)"');
|
|
693
|
+
push('$listener = [System.Net.Sockets.TcpListener]::Start($port)');
|
|
694
|
+
push('$listener.Start()');
|
|
695
|
+
push('Write-Log "listening on port $port"');
|
|
696
|
+
push('while ($true) {');
|
|
697
|
+
push(' $client = $listener.AcceptTcpClient()');
|
|
698
|
+
push(' $stream = $client.GetStream()');
|
|
699
|
+
push(' $reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8)');
|
|
700
|
+
push(' $line = $reader.ReadLine()');
|
|
701
|
+
push(' $client.Close()');
|
|
702
|
+
push(' if (-not $line) { continue }');
|
|
703
|
+
push(' Write-Log "received: $line"');
|
|
704
|
+
push(' try {');
|
|
705
|
+
push(' $cmd = $line | ConvertFrom-Json');
|
|
706
|
+
push(' $id = $cmd.id');
|
|
707
|
+
push(' $command = $cmd.command');
|
|
708
|
+
push(' $cwd = if ($cmd.cwd) { $cmd.cwd } else { $env:USERPROFILE }');
|
|
709
|
+
push(' Write-Log "executing: $command"');
|
|
710
|
+
push(' $stdoutFile = "$env:TEMP\\myassis-stdout-$id.txt"');
|
|
711
|
+
push(' $stderrFile = "$env:TEMP\\myassis-stderr-$id.txt"');
|
|
712
|
+
push(' $proc = Start-Process -FilePath "cmd.exe" -ArgumentList "/c $command" -WorkingDirectory $cwd -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdoutFile -RedirectStandardError $stderrFile');
|
|
713
|
+
push(' $stdout = if (Test-Path $stdoutFile) { Get-Content $stdoutFile -Raw -Encoding UTF8 } else { "" }');
|
|
714
|
+
push(' $stderr = if (Test-Path $stderrFile) { Get-Content $stderrFile -Raw -Encoding UTF8 } else { "" }');
|
|
715
|
+
push(' Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue');
|
|
716
|
+
push(' Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue');
|
|
717
|
+
push(' $exitCode = $proc.ExitCode');
|
|
718
|
+
push(' Write-Log "done (exit=$exitCode)"');
|
|
719
|
+
push(' $resp = @{ id=$id; success=$true; stdout=$stdout; stderr=$stderr; exitCode=$exitCode } | ConvertTo-Json -Compress');
|
|
720
|
+
push(' $nl = [Environment]::NewLine');
|
|
721
|
+
push(' $bytes = [System.Text.Encoding]::UTF8.GetBytes($resp + $nl)');
|
|
722
|
+
push(' $client.Client.Send($bytes)');
|
|
723
|
+
push(' } catch {');
|
|
724
|
+
push(' Write-Log "error: $($_.Exception.Message)"');
|
|
725
|
+
push(' try {');
|
|
726
|
+
push(' $resp = @{ id=$id; success=$false; error=$($_.Exception.Message) } | ConvertTo-Json -Compress');
|
|
727
|
+
push(' $nl = [Environment]::NewLine');
|
|
728
|
+
push(' $bytes = [System.Text.Encoding]::UTF8.GetBytes($resp + $nl)');
|
|
729
|
+
push(' $client.Client.Send($bytes)');
|
|
730
|
+
push(' } catch { }');
|
|
731
|
+
push(' }');
|
|
732
|
+
push('}');
|
|
733
|
+
return l.join('\r\n');
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* 查找当前登录用户的会话 ID(Explorer.exe 所在会话)
|
|
737
|
+
*/
|
|
738
|
+
async function getUserSessionId() {
|
|
739
|
+
try {
|
|
740
|
+
const { stdout } = await execAsync('powershell -NoProfile -Command "Get-Process Explorer -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty SessionId"', { timeout: 5000 });
|
|
741
|
+
const n = parseInt(stdout.trim(), 10);
|
|
742
|
+
if (!isNaN(n) && n > 0)
|
|
743
|
+
return n;
|
|
744
|
+
}
|
|
745
|
+
catch { /* ignore */ }
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
async function spawnHelperAsUser() {
|
|
749
|
+
if (process.platform !== 'win32')
|
|
750
|
+
return false;
|
|
751
|
+
if (helperReady && helperSocket)
|
|
752
|
+
return true;
|
|
753
|
+
const sessionId = await getUserSessionId();
|
|
754
|
+
if (!sessionId) {
|
|
755
|
+
logger.warn('Cannot get user session ID');
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
logger.info('Trying to spawn helper in session ' + sessionId);
|
|
759
|
+
const scriptContent = buildHelperScript();
|
|
760
|
+
let scriptPath = '';
|
|
761
|
+
let launchPath = '';
|
|
762
|
+
try {
|
|
763
|
+
scriptPath = path_1.default.join(os_1.default.tmpdir(), 'myassis-gateway-helper-' + Date.now() + '.ps1');
|
|
764
|
+
launchPath = path_1.default.join(os_1.default.tmpdir(), 'myassis-gateway-launch-' + Date.now() + '.ps1');
|
|
765
|
+
// Write with BOM for UTF-8
|
|
766
|
+
fs_1.default.writeFileSync(scriptPath, '\uFEFF' + scriptContent, 'utf8');
|
|
767
|
+
const psLaunchScript = [
|
|
768
|
+
'$ErrorActionPreference = \'Stop\'',
|
|
769
|
+
'Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @\'',
|
|
770
|
+
' [DllImport("wtsapi32.dll", SetLastError=true)] public static extern bool WTSQueryUserToken(int sessionId, out IntPtr token);',
|
|
771
|
+
' [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);',
|
|
772
|
+
' [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; }',
|
|
773
|
+
' [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; }',
|
|
774
|
+
"'@",
|
|
775
|
+
'$sessionId = ' + sessionId,
|
|
776
|
+
'$tokenPtr = [IntPtr]::Zero',
|
|
777
|
+
'$ok = [Win32.NativeMethods]::WTSQueryUserToken($sessionId, [ref]$tokenPtr)',
|
|
778
|
+
'if (-not $ok) { Write-Error "WTSQueryUserToken failed"; exit 1 }',
|
|
779
|
+
'$si = New-Object Win32.NativeMethods+STARTUPINFO',
|
|
780
|
+
'$si.cb = [Runtime.InteropServices.Marshal]::SizeOf($si)',
|
|
781
|
+
'$si.lpDesktop = "WinSta0\\Default"',
|
|
782
|
+
'$pi = [Win32.NativeMethods+PROCESS_INFORMATION]::new()',
|
|
783
|
+
'$cmdLine = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \\\"" + "' + scriptPath.replace(/\\\\/g, '\\\\\\\\') + '" + "\\\""',
|
|
784
|
+
'$envBlock = [IntPtr]::Zero',
|
|
785
|
+
'$bInherit = $true',
|
|
786
|
+
'$CREATE_NO_WINDOW = 0x08000000',
|
|
787
|
+
'$CREATE_UNICODE_ENVIRONMENT = 0x00040000',
|
|
788
|
+
'$flags = $CREATE_NO_WINDOW -bor $CREATE_UNICODE_ENVIRONMENT',
|
|
789
|
+
'$result = [Win32.NativeMethods]::CreateProcessAsUser($tokenPtr, $null, $cmdLine, [IntPtr]::Zero, [IntPtr]::Zero, $bInherit, $flags, $envBlock, $null, [ref]$si, [ref]$pi)',
|
|
790
|
+
'[void][Win32.NativeMethods]',
|
|
791
|
+
'if (-not $result) { Write-Error "CreateProcessAsUser failed (code=$LASTEXITCODE)"; exit 1 }',
|
|
792
|
+
'[void][Runtime.InteropServices.Marshal]::Release($tokenPtr)',
|
|
793
|
+
'Write-Output "started pid=$($pi.dwProcessId)"',
|
|
794
|
+
].join('\r\n');
|
|
795
|
+
fs_1.default.writeFileSync(launchPath, '\uFEFF' + psLaunchScript, 'utf8');
|
|
796
|
+
const { stdout } = await execAsync('powershell -NoProfile -ExecutionPolicy Bypass -File "' + launchPath + '"', { timeout: 15000, windowsHide: true });
|
|
797
|
+
logger.info('Helper launch output: ' + stdout.trim());
|
|
798
|
+
// Wait for helper to become ready,连接成功后升级为持久 socket
|
|
799
|
+
const maxWait = 5000;
|
|
800
|
+
const start = Date.now();
|
|
801
|
+
while (Date.now() - start < maxWait) {
|
|
802
|
+
try {
|
|
803
|
+
await new Promise((resolve, reject) => {
|
|
804
|
+
const s = net_1.default.createConnection(HELPER_PORT, '127.0.0.1');
|
|
805
|
+
s.setTimeout(500);
|
|
806
|
+
s.on('connect', () => { s.destroy(); resolve(); });
|
|
807
|
+
s.on('timeout', () => { s.destroy(); reject(new Error('timeout')); });
|
|
808
|
+
s.on('error', () => { s.destroy(); reject(new Error('error')); });
|
|
809
|
+
});
|
|
810
|
+
// Helper 已就绪,建立持久 socket
|
|
811
|
+
helperSocket = net_1.default.createConnection(HELPER_PORT, '127.0.0.1');
|
|
812
|
+
helperSocket.setTimeout(0);
|
|
813
|
+
helperSocket.on('data', (chunk) => {
|
|
814
|
+
handleHelperData(chunk.toString('utf8'));
|
|
815
|
+
});
|
|
816
|
+
helperSocket.on('error', (err) => {
|
|
817
|
+
logger.error('Helper socket error: ' + err.message);
|
|
818
|
+
helperReady = false;
|
|
819
|
+
});
|
|
820
|
+
helperSocket.on('close', () => {
|
|
821
|
+
helperReady = false;
|
|
822
|
+
logger.info('Helper socket closed');
|
|
823
|
+
});
|
|
824
|
+
helperReady = true;
|
|
825
|
+
logger.info('Helper process ready');
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
catch {
|
|
829
|
+
await new Promise(r => setTimeout(r, 500));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return helperReady;
|
|
833
|
+
}
|
|
834
|
+
catch (err) {
|
|
835
|
+
logger.error('Helper launch failed: ' + (err.message || err));
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
finally {
|
|
839
|
+
try {
|
|
840
|
+
fs_1.default.unlinkSync(scriptPath);
|
|
841
|
+
}
|
|
842
|
+
catch { /* ignore */ }
|
|
843
|
+
try {
|
|
844
|
+
fs_1.default.unlinkSync(launchPath);
|
|
845
|
+
}
|
|
846
|
+
catch { /* ignore */ }
|
|
847
|
+
}
|
|
848
|
+
}
|
|
@@ -10,6 +10,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
const os_1 = __importDefault(require("os"));
|
|
11
11
|
const shared_1 = require("@myassis/shared");
|
|
12
12
|
const crypto_1 = __importDefault(require("crypto"));
|
|
13
|
+
const ServiceManager_js_1 = require("../ServiceManager.js");
|
|
13
14
|
const logger = (0, shared_1.getLogger)('exec');
|
|
14
15
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
16
|
// 待批准的命令缓存:token -> { command, cwd, timeout, sessionId, expiresAt }
|
|
@@ -71,14 +72,15 @@ function generateApprovalToken() {
|
|
|
71
72
|
}
|
|
72
73
|
/** 检查命令是否危险 */
|
|
73
74
|
function isDangerousCommand(command) {
|
|
75
|
+
// 命令分隔符(起始位置、空格、shell 操作符)隔离的危险关键字
|
|
74
76
|
const dangerousPatterns = [
|
|
75
|
-
/rm\s+-rf\s+\//,
|
|
76
|
-
/format\s+[a-z]:/i,
|
|
77
|
-
/del\s+\/[sfq]\s+\*/i,
|
|
78
|
-
/shutdown/i,
|
|
79
|
-
/reboot/i,
|
|
80
|
-
/mkfs/i,
|
|
81
|
-
/dd\s+if=.*of=\/dev\//i,
|
|
77
|
+
/(^|[\s;|&])rm\s+-rf\s+\//,
|
|
78
|
+
/(^|[\s;|&])format\s+[a-z]:/i,
|
|
79
|
+
/(^|[\s;|&])del\s+\/[sfq]\s+\*/i,
|
|
80
|
+
/(^|[\s;|&])shutdown\b/i,
|
|
81
|
+
/(^|[\s;|&])reboot\b/i,
|
|
82
|
+
/(^|[\s;|&])mkfs\b/i,
|
|
83
|
+
/(^|[\s;|&])dd\s+if=.*of=\/dev\//i,
|
|
82
84
|
];
|
|
83
85
|
for (const reg of dangerousPatterns) {
|
|
84
86
|
if (reg.test(command))
|
|
@@ -169,11 +171,28 @@ exports.execTool = {
|
|
|
169
171
|
success: false,
|
|
170
172
|
needsApproval: true,
|
|
171
173
|
approvalToken: token,
|
|
172
|
-
errorMessage:
|
|
174
|
+
errorMessage: `${command}`,
|
|
173
175
|
});
|
|
174
176
|
return;
|
|
175
177
|
}
|
|
176
178
|
}
|
|
179
|
+
// Windows 下通过 Helper 以登录用户身份执行
|
|
180
|
+
if (process.platform === 'win32') {
|
|
181
|
+
try {
|
|
182
|
+
const result = await (0, ServiceManager_js_1.execAsUser)(command, cwd);
|
|
183
|
+
resolve({
|
|
184
|
+
success: result.exitCode === 0,
|
|
185
|
+
output: result.stdout.substring(0, 100000),
|
|
186
|
+
errorMessage: result.stderr.substring(0, 100000),
|
|
187
|
+
exitCode: result.exitCode,
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
resolve({ success: false, errorMessage: e?.message || String(e) });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
177
196
|
const options = {
|
|
178
197
|
cwd,
|
|
179
198
|
timeout,
|