terminal-bridge-setup 2.3.0 → 2.4.0
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.
|
@@ -288,7 +288,9 @@ function connectBridge() {
|
|
|
288
288
|
|
|
289
289
|
// ============== 手动扫描 xterm(popup 触发)==============
|
|
290
290
|
// 遍历所有 tab 的所有 frame,发 term-ping 探测有没有 xterm。
|
|
291
|
-
//
|
|
291
|
+
// 关键:reload 插件后已打开的页面里没有 content script,ping 无人响应。
|
|
292
|
+
// 所以 ping 失败时用 chrome.scripting 主动注入 content.js,再 ping 一次。
|
|
293
|
+
// 这样用户 reload 插件后不用刷新页面,点「捕捉终端」就能自动恢复。
|
|
292
294
|
async function scanAllTabsForXterm() {
|
|
293
295
|
const tabs = await chrome.tabs.query({});
|
|
294
296
|
let found = 0;
|
|
@@ -306,26 +308,25 @@ async function scanAllTabsForXterm() {
|
|
|
306
308
|
} catch { continue; }
|
|
307
309
|
if (!frames) continue;
|
|
308
310
|
|
|
309
|
-
// 对每个 frame 发 term-ping(必须指定 frameId 才能到 iframe)
|
|
310
311
|
for (const frame of frames) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
);
|
|
321
|
-
}
|
|
312
|
+
// 第一次 ping(content script 可能已经在跑)
|
|
313
|
+
let res = await pingFrame(tab.id, frame.frameId);
|
|
314
|
+
|
|
315
|
+
// ping 失败:content script 没注入(reload 插件后常见)→ 主动注入再 ping
|
|
316
|
+
if (!res) {
|
|
317
|
+
console.log("[bg] ping 失败,尝试注入 content.js 到 tab", tab.id, "frame", frame.frameId);
|
|
318
|
+
await injectContentScript(tab.id, frame.frameId);
|
|
319
|
+
// 注入后等一下让 IIFE 执行 + term-ping 监听器注册
|
|
320
|
+
await new Promise(r => setTimeout(r, 200));
|
|
321
|
+
res = await pingFrame(tab.id, frame.frameId);
|
|
322
|
+
}
|
|
323
|
+
|
|
322
324
|
if (res && res.ready) {
|
|
323
325
|
found++;
|
|
324
326
|
termReadyTabs.add(tab.id);
|
|
325
|
-
termReadyFrames.set(tab.id, frame.frameId);
|
|
327
|
+
termReadyFrames.set(tab.id, frame.frameId);
|
|
326
328
|
foundTabs.push({ tabId: tab.id, href: res.href });
|
|
327
329
|
console.log("[bg] 扫描发现 xterm: tab", tab.id, "frame", frame.frameId, res.href);
|
|
328
|
-
// 自动 attach
|
|
329
330
|
attachDebugger(tab.id);
|
|
330
331
|
break; // 一个 tab 找到一个就够
|
|
331
332
|
}
|
|
@@ -341,6 +342,39 @@ async function scanAllTabsForXterm() {
|
|
|
341
342
|
};
|
|
342
343
|
}
|
|
343
344
|
|
|
345
|
+
// 向指定 frame 发 term-ping
|
|
346
|
+
function pingFrame(tabId, frameId) {
|
|
347
|
+
return new Promise((resolve) => {
|
|
348
|
+
try {
|
|
349
|
+
chrome.tabs.sendMessage(
|
|
350
|
+
tabId,
|
|
351
|
+
{ type: "term-ping" },
|
|
352
|
+
{ frameId },
|
|
353
|
+
(r) => {
|
|
354
|
+
if (chrome.runtime.lastError) { resolve(null); return; }
|
|
355
|
+
resolve(r);
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
} catch { resolve(null); }
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 用 chrome.scripting 主动注入 content.js 到指定 frame
|
|
363
|
+
// 解决 reload 插件后已打开页面没有 content script 的问题
|
|
364
|
+
async function injectContentScript(tabId, frameId) {
|
|
365
|
+
try {
|
|
366
|
+
await chrome.scripting.executeScript({
|
|
367
|
+
target: { tabId, frameIds: [frameId] },
|
|
368
|
+
files: ["content.js"],
|
|
369
|
+
});
|
|
370
|
+
return true;
|
|
371
|
+
} catch (err) {
|
|
372
|
+
// 有些 frame(如 about:blank)注入会失败,忽略
|
|
373
|
+
console.log("[bg] 注入 content.js 失败 tab", tabId, "frame", frameId, ":", err.message);
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
344
378
|
function sendToBridge(obj) {
|
|
345
379
|
if (bridgeWs && bridgeWs.readyState === WebSocket.OPEN) {
|
|
346
380
|
try { bridgeWs.send(JSON.stringify(obj)); } catch {}
|
|
@@ -401,15 +435,35 @@ async function injectToXterm(text, reqId) {
|
|
|
401
435
|
return;
|
|
402
436
|
}
|
|
403
437
|
|
|
438
|
+
// 第一轮:ping 现有 content script
|
|
404
439
|
for (const frame of frames) {
|
|
405
440
|
const r = await sendToFrame(tabId, frame.frameId, text, reqId, true /*pingOnly*/);
|
|
406
441
|
if (r) {
|
|
407
442
|
targetFrameId = frame.frameId;
|
|
408
|
-
termReadyFrames.set(tabId, targetFrameId);
|
|
443
|
+
termReadyFrames.set(tabId, targetFrameId);
|
|
409
444
|
ok = await sendToFrame(tabId, targetFrameId, text, reqId);
|
|
410
445
|
break;
|
|
411
446
|
}
|
|
412
447
|
}
|
|
448
|
+
|
|
449
|
+
// 第二轮:第一轮全失败说明 content script 没注入(reload 插件后常见)
|
|
450
|
+
// 主动注入 content.js 到每个 frame,再 ping + 注入
|
|
451
|
+
if (!ok) {
|
|
452
|
+
console.log("[bg] 降级探测全失败,尝试主动注入 content.js");
|
|
453
|
+
for (const frame of frames) {
|
|
454
|
+
await injectContentScript(tabId, frame.frameId);
|
|
455
|
+
}
|
|
456
|
+
await new Promise(r => setTimeout(r, 200)); // 等 IIFE 执行
|
|
457
|
+
for (const frame of frames) {
|
|
458
|
+
const r = await sendToFrame(tabId, frame.frameId, text, reqId, true /*pingOnly*/);
|
|
459
|
+
if (r) {
|
|
460
|
+
targetFrameId = frame.frameId;
|
|
461
|
+
termReadyFrames.set(tabId, targetFrameId);
|
|
462
|
+
ok = await sendToFrame(tabId, targetFrameId, text, reqId);
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
413
467
|
}
|
|
414
468
|
|
|
415
469
|
if (ok) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"version": "2.0.0",
|
|
5
5
|
"description": "桥接 JumpServer Web 终端,让 Agent 能远程执行命令并获取输出",
|
|
6
6
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtsnqR6PcFUueZwYria79tVbstvjk+tM7PpvIXILm5xbd6bAdjDIhzg3lsnKioVfvxjfvT+s6vJsiOYa9ojVZyJMFc5m/05TYqr770ovYwQmz0e88fmiy6dUoSulbtKvBCSLbN6OOL7u+ul8ixLZ/HautxSmou/eNgAFPmhE+4UueE7wfCqcgMYvjLvEzlqTVumMW+5LKw9YsRk6WhHPghY1a3MVUn3eQOWXBtQTEUy3wBM3v4wHxLwDeinVOR4f/P87IlUNo84C5DeimoFit0qCj3K04hS8MIYCLCYZc3v9ftRJDJBkAoah6Eaqj7JajbS3KvLR1ctOYfDhubgmURQIDAQAB",
|
|
7
|
-
"permissions": ["debugger", "tabs", "alarms", "webNavigation", "nativeMessaging"],
|
|
7
|
+
"permissions": ["debugger", "tabs", "alarms", "webNavigation", "nativeMessaging", "scripting"],
|
|
8
8
|
"background": {
|
|
9
9
|
"service_worker": "background.js"
|
|
10
10
|
},
|
package/package.json
CHANGED