Add proxy routing and sing-box support

This commit is contained in:
Fabian Freund
2026-05-22 18:16:31 +02:00
parent 51289f1266
commit a5974617aa
262 changed files with 32003 additions and 3962 deletions
@@ -15,7 +15,7 @@ const privateIdentifier = 'firefox-private'
type DoNotProxy = never[]
export const doNotProxy: DoNotProxy = []
const emergencyBreak: Socks5ProxyInfo = {
export const emergencyBreak: Socks5ProxyInfo = {
type: ProxyType.Socks5,
host: 'emergency-break-proxy.localhost',
port: 1,
@@ -1,4 +1,4 @@
import { Socks5ProxySettings } from 'src/domain/ProxySettings';
import { ProxySettings, Socks5ProxySettings } from 'src/domain/ProxySettings';
import { Store } from '../store/Store'
import BackgroundMain from './BackgroundMain'
@@ -8,7 +8,16 @@ const store = new Store()
interface Message {
id: String | undefined;
action: 'setProxyPort' | 'addContainerProxy' | 'removeContainerProxy' | 'healthcheck' | 'setSiteAssignments';
action: 'setProxyPort' |
'addContainerProxy' |
'removeContainerProxy' |
'upsertProxy' |
'removeProxy' |
'setContainerProxy' |
'clearContainerProxy' |
'removeContainerProxyRelation' |
'healthcheck' |
'setSiteAssignments';
args: any;
}
@@ -42,6 +51,32 @@ port.onMessage.addListener((raw: unknown): void => {
store.removeContainerProxyRelation(message.args, "tor")
console.log('removed container relation ' + message.args)
break
case "upsertProxy": {
const proxy = ProxySettings.tryFromDao(message.args)
if (proxy === undefined) {
console.error('invalid proxy settings ' + JSON.stringify(message.args))
break
}
store.putProxy(proxy)
console.log('upsert proxy ' + message.args.id)
break
}
case "removeProxy":
store.deleteProxyById(message.args)
console.log('removed proxy ' + message.args)
break
case "setContainerProxy":
store.setContainerProxyRelation(message.args.contextId, message.args.proxyId)
console.log('set container relation ' + message.args.contextId + ' -> ' + message.args.proxyId)
break
case "clearContainerProxy":
store.clearContainerProxyRelation(message.args)
console.log('cleared container relation ' + message.args)
break
case "removeContainerProxyRelation":
store.removeContainerProxyRelation(message.args.contextId, message.args.proxyId)
console.log('removed container relation ' + message.args.contextId + ' -> ' + message.args.proxyId)
break
case "setSiteAssignments":
const entries = new Map(Object.entries(message.args))
console.log('set site assignments ' + JSON.stringify(message.args))
@@ -224,6 +224,10 @@ export class Store {
this.relations[cookieStoreId] = [proxyId]
}
clearContainerProxyRelation(cookieStoreId: string): void {
delete this.relations[cookieStoreId]
}
removeContainerProxyRelation(cookieStoreId: string, proxyId: string): void {
const currentRelations = this.relations[cookieStoreId] ?? []
this.relations[cookieStoreId] = currentRelations.filter(id => id !== proxyId)
@@ -1,4 +1,4 @@
import BackgroundMain, { doNotProxy } from '../../src/background/BackgroundMain'
import BackgroundMain, { doNotProxy, emergencyBreak } from '../../src/background/BackgroundMain'
import { Store } from '../../src/store/Store'
import { expect } from 'chai'
@@ -41,6 +41,16 @@ describe('BackgroundMain', function () {
expect(result).to.be.not.empty
})
it('should block if an assigned proxy no longer exists', async () => {
const isolatedStore = new Store()
const isolatedBackgroundMain = new BackgroundMain({ store: isolatedStore })
isolatedStore.setContainerProxyRelation('general', 'missing-proxy')
const result = await isolatedBackgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'https://google.com', tabId: 0 })
expect(result).to.be.deep.equal([emergencyBreak])
})
it('should remove doNotProxyLocal flag from proxy settings if proxy is set up', async () => {
await givenSomeProxyIsSetUpForContainer({ containerId: 'firefox-default', host: undefined, doNotProxyLocal: undefined })
@@ -163,6 +163,15 @@ describe('Store', () => {
expect(relations.container1).to.be.deep.equal(['proxy1'])
expect(relations.container2).to.be.deep.equal(['proxy2'])
})
it('should keep a missing proxy relation distinguishable from no relation', () => {
const isolatedStore = new Store()
isolatedStore.setContainerProxyRelation('container1', 'deleted-proxy')
const result = isolatedStore.getProxiesForContainer('container1')
expect(result).to.be.deep.equal([])
})
})
describe('wildcard site assignments', function () {