Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions background.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,12 @@ function sendPopupStatus() {
if (deadPort) {
setPopupIcon("need-install");
console.log("sendPopupStatus... no nmPort");
const suffix = browserByte() + chrome.runtime.id;
sendToPopup({
installCmd:
"go run github.com/tailscale/ts-browser-ext@main --install=" +
browserByte() +
chrome.runtime.id,
installCmds: {
remote: "go run github.com/tailscale/ts-browser-ext@main --install=" + suffix,
local: "go run . --install=" + suffix,
},
});
return;
}
Expand Down Expand Up @@ -130,6 +131,15 @@ function connectToNativeHost() {
nmPort.onDisconnect.addListener(() => {
deadPort = true;
setPopupIcon("need-install");
// Clean up pending exit node callbacks to prevent hung promises
if (pendingExitNodesCallback) {
pendingExitNodesCallback({ error: "Disconnected from native host" });
pendingExitNodesCallback = null;
}
if (pendingSetExitNodeCallback) {
pendingSetExitNodeCallback({ error: "Disconnected from native host" });
pendingSetExitNodeCallback = null;
}
disableProxy();
const error = chrome.runtime.lastError;
if (error) {
Expand Down Expand Up @@ -163,6 +173,20 @@ function connectToNativeHost() {
if (message.status) {
lastStatus = message.status;
}
if (message.exitNodes) {
console.log("got exitNodes response:", message.exitNodes);
if (pendingExitNodesCallback) {
pendingExitNodesCallback(message.exitNodes);
pendingExitNodesCallback = null;
}
}
if (message.exitNodeSet) {
console.log("got exitNodeSet response:", message.exitNodeSet);
if (pendingSetExitNodeCallback) {
pendingSetExitNodeCallback(message.exitNodeSet);
pendingSetExitNodeCallback = null;
}
}
maybeSendInit();
sendPopupStatus();
});
Expand Down Expand Up @@ -239,6 +263,10 @@ chrome.storage.local.get("profileId", (result) => {
}
});

// Pending response callbacks for exit node requests
let pendingExitNodesCallback = null;
let pendingSetExitNodeCallback = null;
Comment thread
e-kotov marked this conversation as resolved.

// Listener for messages from the popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("bg: Received message:", message);
Expand All @@ -261,4 +289,34 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
setPopupIcon(proxyEnabled);
return true; // Keep the message channel open for the async response
}

if (message.command === "getExitNodes") {
console.log("bg: getExitNodes received");
if (deadPort || !nmPort) {
sendResponse({ error: "Not connected to native host" });
return true;
}
if (pendingExitNodesCallback) {
sendResponse({ error: "Request already in progress" });
return true;
}
pendingExitNodesCallback = sendResponse;
nmPort.postMessage({ cmd: "get-exit-nodes" });
return true; // Keep the message channel open for the async response
}

if (message.command === "setExitNode") {
console.log("bg: setExitNode received, IP:", message.exitNodeIP);
if (deadPort || !nmPort) {
sendResponse({ error: "Not connected to native host" });
return true;
}
if (pendingSetExitNodeCallback) {
sendResponse({ error: "Request already in progress" });
return true;
}
pendingSetExitNodeCallback = sendResponse;
nmPort.postMessage({ cmd: "set-exit-node", exitNodeIP: message.exitNodeIP || "" });
return true; // Keep the message channel open for the async response
}
});
79 changes: 70 additions & 9 deletions firefox/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function sendPopupStatus() {
// firefox requires that extensions settings proxies have private browsing access
browser.extension.isAllowedIncognitoAccess().then(isAllowed => {
if (!isAllowed) {
sendToPopup({
sendToPopup({
needsIncognitoPermission: true
});
}
Expand All @@ -96,11 +96,12 @@ function sendPopupStatus() {
if (deadPort) {
setPopupIcon("need-install");
console.log("sendPopupStatus... no nmPort");
const suffix = browserByte() + browser.runtime.id;
sendToPopup({
installCmd:
"go run github.com/tailscale/ts-browser-ext@main --install=" +
browserByte() +
browser.runtime.id,
installCmds: {
remote: "go run github.com/tailscale/ts-browser-ext@main --install=" + suffix,
local: "go run . --install=" + suffix,
},
});
return;
}
Expand All @@ -119,6 +120,10 @@ let nmPort = null; // even non-null if lacking permission
let deadPort = true;
let portError = null;

// Pending promise resolvers for exit node requests
let pendingExitNodesResolve = null;
let pendingSetExitNodeResolve = null;

Comment thread
e-kotov marked this conversation as resolved.
connectToNativeHost();

function connectToNativeHost() {
Expand All @@ -131,6 +136,15 @@ function connectToNativeHost() {
nmPort.onDisconnect.addListener(() => {
deadPort = true;
setPopupIcon("need-install");
// Clean up pending exit node resolvers to prevent hung promises
if (pendingExitNodesResolve) {
pendingExitNodesResolve({ error: "Disconnected from native host" });
pendingExitNodesResolve = null;
}
if (pendingSetExitNodeResolve) {
pendingSetExitNodeResolve({ error: "Disconnected from native host" });
pendingSetExitNodeResolve = null;
}
disableProxy();
const error = browser.runtime.lastError;
if (error) {
Expand Down Expand Up @@ -164,24 +178,45 @@ function connectToNativeHost() {
if (message.status) {
lastStatus = message.status;
}
if (message.exitNodes) {
console.log("got exitNodes response:", message.exitNodes);
if (pendingExitNodesResolve) {
pendingExitNodesResolve(message.exitNodes);
pendingExitNodesResolve = null;
}
}
if (message.exitNodeSet) {
console.log("got exitNodeSet response:", message.exitNodeSet);
if (pendingSetExitNodeResolve) {
pendingSetExitNodeResolve(message.exitNodeSet);
pendingSetExitNodeResolve = null;
}
}
maybeSendInit();
sendPopupStatus();
});
}

var lastProxyPort = 0;
var lastStatus = {}; // last Go status
var activeProxyHandler = null;

function setProxy(proxyPort) {
const handleProxyRequest = proxyHandler(proxyPort)
// Remove existing handler if any
if (activeProxyHandler) {
browser.proxy.onRequest.removeListener(activeProxyHandler);
activeProxyHandler = null;
}

if (proxyPort) {
proxyEnabled = true;
lastProxyPort = proxyPort;
console.log("Enabling proxy at port: " + proxyPort);
activeProxyHandler = proxyHandler(proxyPort);
browser.proxy.onRequest.addListener(activeProxyHandler, { urls: ["<all_urls>"] });
} else {
proxyEnabled = false;
console.log("Disabling proxy...");
browser.proxy.onRequest.removeListener(handleProxyRequest)
browser.proxy.settings
.set({
value: {
Expand All @@ -192,9 +227,7 @@ function setProxy(proxyPort) {
.then(() => {
console.log("Proxy disabled.");
});
return;
}
browser.proxy.onRequest.addListener(handleProxyRequest, { urls: ["<all_urls>"] })
}

var profileID = "";
Expand Down Expand Up @@ -253,4 +286,32 @@ browser.runtime.onMessage.addListener((message, sender) => {
}
return Promise.resolve({ status: lastStatus });
}

if (message.command === "getExitNodes") {
console.log("bg: getExitNodes received");
if (deadPort || !nmPort) {
return Promise.resolve({ error: "Not connected to native host" });
}
if (pendingExitNodesResolve) {
return Promise.resolve({ error: "Request already in progress" });
}
return new Promise((resolve) => {
pendingExitNodesResolve = resolve;
nmPort.postMessage({ cmd: "get-exit-nodes" });
});
}

if (message.command === "setExitNode") {
console.log("bg: setExitNode received, IP:", message.exitNodeIP);
if (deadPort || !nmPort) {
return Promise.resolve({ error: "Not connected to native host" });
}
if (pendingSetExitNodeResolve) {
return Promise.resolve({ error: "Request already in progress" });
}
return new Promise((resolve) => {
pendingSetExitNodeResolve = resolve;
nmPort.postMessage({ cmd: "set-exit-node", exitNodeIP: message.exitNodeIP || "" });
});
}
});
Loading