Skip to content

Commit

Permalink
Fix update of the proxy badge
Browse files Browse the repository at this point in the history
  • Loading branch information
ruihildt committed Aug 19, 2024
1 parent e3f8206 commit 78477e4
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 119 deletions.
8 changes: 2 additions & 6 deletions src/background/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { addExtensionsListeners } from '@/helpers/extensions';
import { cleanProxyListeners, initProxyListeners } from '@/helpers/socksProxy';
import { initProxyListeners } from '@/helpers/proxyListeners';

// only on dev mode
if (import.meta.hot) {
Expand All @@ -10,9 +10,5 @@ if (import.meta.hot) {
// Add listeners on extension actions
addExtensionsListeners();

// Init proxy listeners
// Add listeners for proxy actions
initProxyListeners();

// Listeners for permissions changes
browser.permissions.onAdded.addListener(initProxyListeners);
browser.permissions.onRemoved.addListener(cleanProxyListeners);
4 changes: 2 additions & 2 deletions src/components/Location.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { NButton, NCollapse, NCollapseItem, NSpace } from 'naive-ui';
import LocationTabs from '@/components/LocationTabs.vue';
import { updateTabsProxyBadges } from '@/helpers/browserAction';
import getRandomSocksProxy from '@/helpers/getRandomSocksProxy';
import { updateCurrentTabProxyBadge } from '@/helpers/proxyBadge';
import useListProxies from '@/composables/useListProxies';
import useSocksProxy from '@/composables/useSocksProxy';
Expand Down Expand Up @@ -43,7 +43,7 @@ const setProxy = (
} else {
setGlobalProxy({ country, countryCode, city, hostname, ipv4_address, port });
}
updateTabsProxyBadges();
updateCurrentTabProxyBadge();
};
const clickServer = (
Expand Down
45 changes: 45 additions & 0 deletions src/components/Proxy/HomeProxyStatus.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts" setup>
import { computed, inject } from 'vue';
import IconLabel from '@/components/IconLabel.vue';
import useActiveTab from '@/composables/useActiveTab';
import { ConnectionKey, defaultConnection } from '@/composables/useConnection';
import useSocksProxy from '@/composables/useSocksProxy';
import useStore from '@/composables/useStore';
const { activeTabHost, isAboutPage } = useActiveTab();
const { currentHostProxyDetails, currentHostProxyEnabled, globalProxyDetails, globalProxyEnabled } =
useSocksProxy();
const { excludedHosts } = useStore();
const { connection } = inject(ConnectionKey, defaultConnection);
const currentHostExcluded = computed(() => {
return excludedHosts.value.includes(activeTabHost.value);
});
</script>

<template>
<IconLabel v-if="currentHostExcluded" type="info" class="my-2">
<strong>{{ activeTabHost }}</strong> is set to never be proxied
</IconLabel>

<IconLabel v-else-if="currentHostProxyEnabled && connection.isMullvad" type="info" class="my-2">
<strong>{{ activeTabHost }}</strong> is set to always be proxied through
<strong>{{ currentHostProxyDetails.server }}</strong>
</IconLabel>

<IconLabel
v-if="globalProxyEnabled && connection.isMullvad && !isAboutPage"
type="info"
class="my-2"
>
All websites are set to be proxied through
<strong>{{ globalProxyDetails.server }}</strong>
</IconLabel>

<IconLabel v-if="currentHostProxyEnabled && !connection.isMullvad" type="warning" class="my-2">
<strong>{{ activeTabHost }}</strong> can't be reached, either disconnect its proxy or connect to
Mullvad VPN.
</IconLabel>
</template>
14 changes: 5 additions & 9 deletions src/composables/useActiveTab.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { getActiveTabDetails } from '@/helpers/socksProxy';
import { ref } from 'vue';
import useProxyPermissions from '@/composables/useProxyPermissions';

const { proxyPermissionsGranted } = useProxyPermissions();
const activeTabHost = ref('');
const isAboutPage = ref(false);

const getActiveTab = async () => {
if (proxyPermissionsGranted.value) {
const activeWindow = await browser.windows.getCurrent({ populate: true });
const activeTab = activeWindow.tabs!.find((tab) => tab.active);
const activeTabDetails = await getActiveTabDetails();

const activeTabURL = new URL(activeTab!.url!);
activeTabHost.value = activeTabURL.hostname;
isAboutPage.value = activeTabURL.protocol === 'about:';
}
activeTabHost.value = activeTabDetails.host;
isAboutPage.value = activeTabDetails.protocol === 'about:';
};

const useActiveTab = () => {
getActiveTab();

return { activeTabHost, isAboutPage };
};

Expand Down
5 changes: 3 additions & 2 deletions src/composables/useProxyPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ const useProxyPermissions = () => {
proxyPermissionsGranted.value = await getProxyPermissions();
};

const triggerProxyPermissions = async () => {
const triggerRequestProxyPermissions = async () => {
proxyPermissionsGranted.value = await requestProxyPermissions();
return proxyPermissionsGranted.value;
};

checkProxyPermissions();

return { proxyPermissionsGranted, triggerProxyPermissions };
return { proxyPermissionsGranted, triggerRequestProxyPermissions };
};

export default useProxyPermissions;
8 changes: 5 additions & 3 deletions src/composables/useSocksProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ProxyInfoType,
ProxyOperationArgs,
} from '@/helpers/socksProxy.types';
import { updateTabsProxyBadges } from '@/helpers/browserAction';
import { updateCurrentTabProxyBadge } from '@/helpers/proxyBadge';

import useActiveTab from '@/composables/useActiveTab';
import useConnection from '@/composables/useConnection';
Expand Down Expand Up @@ -37,22 +37,24 @@ const currentHostProxyDNSEnabled = computed(() => currentHostProxyDetails.value?

const toggleGlobalProxy = () => {
globalProxyDetails.value.socksEnabled = !globalProxyDetails.value.socksEnabled;
updateTabsProxyBadges();
updateCurrentTabProxyBadge();
};
const toggleCurrentHostProxy = () => {
hostProxiesDetails.value[activeTabHost.value].socksEnabled = !currentHostProxyEnabled.value;
updateTabsProxyBadges();
updateCurrentTabProxyBadge();
};

const toggleGlobalProxyDNS = () => {
const updatedGlobalProxyDNS = !globalProxyDetails.value.proxyDNS;
globalProxyDetails.value.proxyDNS = updatedGlobalProxyDNS;
globalProxy.value.proxyDNS = updatedGlobalProxyDNS;
updateCurrentTabProxyBadge();
};
const toggleCurrentHostProxyDNS = () => {
const updatedCurrentHostProxyDNS = !currentHostProxyDetails.value.proxyDNS;
hostProxiesDetails.value[activeTabHost.value].proxyDNS = updatedCurrentHostProxyDNS;
hostProxies.value[activeTabHost.value].proxyDNS = updatedCurrentHostProxyDNS;
updateCurrentTabProxyBadge();
};

const setGlobalProxy = ({
Expand Down
38 changes: 10 additions & 28 deletions src/helpers/browserAction.ts → src/helpers/proxyBadge.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { ProxyDetails } from './socksProxy.types';
import { getActiveProxyDetails } from '@/helpers/socksProxy';
import { ProxyDetails } from '@/helpers/socksProxy.types';

export const initBrowserAction = () => {
// Each time a tab is updated, reset the browserAction for that tab
browser.tabs.onUpdated.addListener(updatedTabListener);
export const updateCurrentTabProxyBadge = async () => {
const activeTab = await browser.tabs.query({ active: true, currentWindow: true });

updateTabsProxyBadges();
if (activeTab[0]) {
await updateTabProxyBadge(activeTab[0], await getActiveProxyDetails());
}
};

// Update a tab browserAction badge & title
const updateTabProxyBadge = async (tab: browser.tabs.Tab, activeProxyDetails: ProxyDetails) => {
export const updateTabProxyBadge = async (
tab: browser.tabs.Tab,
activeProxyDetails: ProxyDetails,
) => {
const { id: tabId, url } = tab;
const { excludedHosts } = await browser.storage.local.get('excludedHosts');
const tabHost = new URL(url!).hostname;
Expand All @@ -32,27 +35,6 @@ const updateTabProxyBadge = async (tab: browser.tabs.Tab, activeProxyDetails: Pr
}
};

// Update state of the proxy badge & title, for all tabs
export const updateTabsProxyBadges = async () => {
const tabs = await browser.tabs.query({});
const activeProxyDetails = await getActiveProxyDetails();

for (const tab of tabs) {
if (tab.id !== undefined) {
updateTabProxyBadge(tab, activeProxyDetails);
}
}
};

export const updatedTabListener = async (
_tabId: number,
_changeInfo: browser.tabs._OnUpdatedChangeInfo,
tab: browser.tabs.Tab,
) => {
const activeProxyDetails = await getActiveProxyDetails();
updateTabProxyBadge(tab, activeProxyDetails);
};

const setTabExtBadge = async (
tab: browser.tabs.Tab,
proxy = true,
Expand Down
62 changes: 62 additions & 0 deletions src/helpers/proxyListeners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { getProxyPermissions } from '@/helpers/permissions';
import { updateCurrentTabProxyBadge, updateTabProxyBadge } from '@/helpers/proxyBadge';
import { getActiveProxyDetails, handleProxyRequest } from '@/helpers/socksProxy';

export const initProxyListeners = () => {
// Will init listeners on extension start if permissions are granted
initListeners();

// Will monitor permissions changes and update proxy accordingly
browser.permissions.onAdded.addListener(initListeners);
browser.permissions.onRemoved.addListener(cleanListeners);
};

const initListeners = async () => {
const proxyPermissionsGranted = await getProxyPermissions();

if (proxyPermissionsGranted) {
updateCurrentTabProxyBadge();

// Initialize tab listeners
browser.tabs.onActivated.addListener(handleActivedTab);
browser.tabs.onUpdated.addListener(handleUpdatedTab);

// Initialize proxy request listener
browser.proxy.onRequest.addListener(handleProxyRequest, { urls: ['<all_urls>'] });
}
};

const cleanListeners = async () => {
const proxyPermissionsGranted = await getProxyPermissions();

if (!proxyPermissionsGranted) {
// Clear the badge for all tabs
// TODO Add a notification to warn the user the proxy has been deactivated
const tabs = await browser.tabs.query({});
for (const tab of tabs) {
if (tab.id !== undefined) {
browser.browserAction.setBadgeText({ text: '', tabId: tab.id });
}
}

// Remove tab listeners
browser.tabs.onActivated.removeListener(handleActivedTab);
browser.tabs.onUpdated.removeListener(handleUpdatedTab);

// Remove proxy request listener
browser.proxy.onRequest.removeListener(handleProxyRequest);
}
};

const handleActivedTab = async (activeInfo: browser.tabs._OnActivatedActiveInfo) => {
const tab = await browser.tabs.get(activeInfo.tabId);
updateTabProxyBadge(tab, await getActiveProxyDetails());
};

const handleUpdatedTab = async (
_tabId: number,
_changeInfo: browser.tabs._OnUpdatedChangeInfo,
tab: browser.tabs.Tab,
) => {
updateTabProxyBadge(tab, await getActiveProxyDetails());
};
50 changes: 14 additions & 36 deletions src/helpers/socksProxy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import ipaddr from 'ipaddr.js';

import { RequestDetails, ProxyDetails } from './socksProxy.types';
import { getProxyPermissions } from './permissions';
import { initBrowserAction, updatedTabListener } from './browserAction';
import { RequestDetails, ProxyDetails } from '@/helpers/socksProxy.types';

const getGlobalProxyDetails = async (): Promise<ProxyDetails> => {
const response = await browser.storage.local.get('globalProxyDetails');
Expand All @@ -19,9 +17,8 @@ const getHostProxyDetails = async (): Promise<ProxyDetails> => {
if (hostProxiesDetails) {
const hostProxiesDetailsParsed = JSON.parse(hostProxiesDetails);
const proxiedHosts = Object.keys(hostProxiesDetailsParsed);
const activeTabHost = (await getActiveTabDetails()).host;

const activeTab = await browser.tabs.query({ active: true });
const activeTabHost = new URL(activeTab[0].url!).hostname;
if (
proxiedHosts.includes(activeTabHost) &&
hostProxiesDetailsParsed[activeTabHost].socksEnabled
Expand All @@ -32,46 +29,27 @@ const getHostProxyDetails = async (): Promise<ProxyDetails> => {
return { socksEnabled: false };
};

export const getActiveTabDetails = async () => {
const activeTab = await browser.tabs.query({ active: true });

return activeTab[0].url
? {
host: new URL(activeTab[0].url).hostname,
protocol: new URL(activeTab[0].url).protocol,
}
: { host: '', protocol: '' };
};

export const getActiveProxyDetails = async () => {
const globalProxyDetails = await getGlobalProxyDetails();
const hostProxyDetails = await getHostProxyDetails();
return hostProxyDetails.socksEnabled ? hostProxyDetails : globalProxyDetails;
};

export const initProxyRequests = () => {
browser.proxy.onRequest.addListener(handleProxyRequest, { urls: ['<all_urls>'] });
};

export const initProxyListeners = async () => {
const proxyPermissionsGranted = await getProxyPermissions();
if (proxyPermissionsGranted) {
await removeProxyListeners();
await addProxyListeners();
}
};

export const cleanProxyListeners = async () => {
const proxyPermissionsGranted = await getProxyPermissions();

if (!proxyPermissionsGranted) {
await removeProxyListeners();
}
};

const addProxyListeners = async () => {
initBrowserAction();
initProxyRequests();
};

const removeProxyListeners = async () => {
browser.tabs.onUpdated.removeListener(updatedTabListener);
browser.proxy.onRequest.removeListener(handleProxyRequest);
};

// TODO decide what how to handle fallback proxy (if proxy is invalid, it will fallback to Firefox proxy if configured)
// https://bugzilla.mozilla.org/show_bug.cgi?id=1750561

const handleProxyRequest = async (details: browser.proxy._OnRequestDetails) => {
export const handleProxyRequest = async (details: browser.proxy._OnRequestDetails) => {
const { globalProxy } = await browser.storage.local.get('globalProxy');
const { globalProxyDetails } = await browser.storage.local.get('globalProxyDetails');
const { excludedHosts } = await browser.storage.local.get('excludedHosts');
Expand Down
Loading

0 comments on commit 78477e4

Please sign in to comment.