Skip to content

Commit

Permalink
Enable activating and deactivating the 'Firefox VPN' (#61)
Browse files Browse the repository at this point in the history
This PR...
- Adds a new `StateVPNOnPartial` state to the controller for when the
VPN client is also in StateOnPartial
- Adds a new ExtensionController to manage extension states (on, off,
idle, connecting - no UI for connecting in this PR as we'll need some
guidance from UX)
- Updates toolbarIcon, tabHandler, and the UI to use extensionController
instead of VPNController (where sensible).
- **Updates the ProxyHandler**
- Moves resolving the site contexts list into `proxyMap` into
ProxyHandler, since that is where other siteContexts things are
happening.
- Subscribes to the VPN controller for loophole, server, and exit server
location data to update the proxyMap.
- Processes and exposes the localproxy and exit location data into
arrays of proxyInfo objects as well as the proxyMap.
- **Updates the RequestHandler**: 
- Subscribes to ProxyHandler for updated localProxy, exitLocation, and
proxyMap
- Subscribes to extensionController state and uses extensionState
properties `bypassTunnel` and `useExitRelays` to conditionally proxy all
Firefox traffic, instead of only site specific traffic.

If we're generally good with the structure of these changes I will start
unbreaking and adding tests.
  • Loading branch information
lesleyjanenorton authored Sep 30, 2024
1 parent c3c9688 commit c3f1cf7
Show file tree
Hide file tree
Showing 15 changed files with 487 additions and 156 deletions.
111 changes: 111 additions & 0 deletions src/background/extensionController/extensionController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @ts-check

import { Component } from "../component.js";
import { VPNController, VPNState } from "../vpncontroller/index.js";
import { property } from "../../shared/property.js";
import { PropertyType } from "../../shared/ipc.js";
import {
FirefoxVPNState,
StateFirefoxVPNIdle,
StateFirefoxVPNDisabled,
StateFirefoxVPNEnabled,
StateFirefoxVPNConnecting,
} from "./states.js";

/**
*
* ExtensionController manages extension state and
* provides a method to the popup for disabling and enabling
* the "Firefox VPN".
*/
export class ExtensionController extends Component {
static properties = {
state: PropertyType.Bindable,
toggleConnectivity: PropertyType.Function,
};

/**
*
* @param {*} receiver
* @param {VPNController} vpnController
*/
constructor(receiver, vpnController) {
super(receiver);
this.vpnController = vpnController;
/** @type {FirefoxVPNState} */
this.#mState.value = new StateFirefoxVPNIdle();
this.vpnController.state.subscribe(
this.handleClientStateChanges.bind(this)
);
}

/** @type {VPNState} */
clientState;

async init() {}

toggleConnectivity() {
if (this.#mState.value.enabled) {
// We are turning off the extension

if (this.clientState.state == "OnPartial") {
// Send deactivation to client and wait for response
this.vpnController.postToApp("deactivate");
return;
}

return this.#mState.set(new StateFirefoxVPNDisabled(true));
}

// We are turning the extension on...
if (this.clientState.state == "Enabled") {
// Client is already enabled
this.#mState.set(new StateFirefoxVPNEnabled(false));
return;
}

this.#mState.set(new StateFirefoxVPNConnecting());
// Send activation to client and wait for response
this.vpnController.postToApp("activate");
}

get state() {
return this.#mState.readOnly;
}

/**
*
* @param {VPNState} newClientState
* @returns {Promise<Void>}
*/
async handleClientStateChanges(newClientState) {
const currentExtState = this.#mState.value;
this.clientState = newClientState;

switch (newClientState.state) {
case "Enabled":
if (!currentExtState.bypassTunnel) {
this.#mState.set(new StateFirefoxVPNEnabled(false));
}
break;

case "Disabled":
this.#mState.set(new StateFirefoxVPNDisabled(false));
break;

case "OnPartial":
this.#mState.set(new StateFirefoxVPNEnabled(true));
break;

default:
this.#mState.set(new StateFirefoxVPNIdle());
}
return;
}

#mState = property(new FirefoxVPNState());
}
6 changes: 6 additions & 0 deletions src/background/extensionController/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

export * from "./states.js";
export * from "./extensionController.js";
93 changes: 93 additions & 0 deletions src/background/extensionController/states.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @ts-check

export class FirefoxVPNState {
/**
*
* The current state of the extension.
* @type {string}
*/
state = "";

/**
* True when Firefox VPN is enabled.
* @type {boolean}
*/
enabled = false;

/**
* True when the Firefox VPN has been deactivated
* but the client VPN is connected.
* Determines whether all traffic should be proxied
* through the local socks proxy.
*
* @type {boolean}
*/
bypassTunnel = false;

/**
* True when the VPN is in StateOnPartial
* Determines whether all Firefox traffic should be routed
* through an exit relay
*
* @type {boolean}
*/
useExitRelays = false;
}

/**
* When Firefox VPN is On
*/
export class StateFirefoxVPNEnabled extends FirefoxVPNState {
/**
* @param {boolean} useExitRelays
*/
constructor(useExitRelays) {
super();
this.useExitRelays = useExitRelays;
}
state = "Enabled";
enabled = true;
bypassTunnel = false;
}

/**
* When Firefox VPN is Off
*/
export class StateFirefoxVPNDisabled extends FirefoxVPNState {
/**s
* @param {boolean} bypassTunnel
*/
constructor(bypassTunnel) {
super();
this.bypassTunnel = bypassTunnel;
}
state = "Disabled";
enabled = false;
useExitRelays = false;
}

/**
* When the client is unavailable
*/
export class StateFirefoxVPNIdle extends FirefoxVPNState {
state = "Idle";
enabled = false;
bypassTunnel = false;
useExitRelays = false;
}

/**
* When the FirefoxVPN is enabled from the popup
* and we're waiting for the client response and state change
* to StateOnPartial.
*/
export class StateFirefoxVPNConnecting extends FirefoxVPNState {
state = "Connecting";
enabled = false;
bypassTunnel = false;
useExitRelays = false;
}
10 changes: 6 additions & 4 deletions src/background/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { TabHandler } from "./tabHandler.js";
import { ToolbarIconHandler } from "./toolbarIconHandler.js";

import { VPNController } from "./vpncontroller/index.js";
import { ExtensionController } from "./extensionController/index.js";

import { expose } from "../shared/ipc.js";
import { TabReloader } from "./tabReloader.js";
Expand All @@ -20,15 +21,16 @@ class Main {

observers = new Set();
vpnController = new VPNController(this);
extController = new ExtensionController(this, this.vpnController);
logger = new Logger(this);
proxyHandler = new ProxyHandler(this, this.vpnController);
requestHandler = new RequestHandler(
this,
this.vpnController,
this.extController,
this.proxyHandler
);
tabHandler = new TabHandler(this, this.vpnController, this.proxyHandler);
toolbarIconHandler = new ToolbarIconHandler(this, this.vpnController);
tabHandler = new TabHandler(this, this.extController, this.proxyHandler);
toolbarIconHandler = new ToolbarIconHandler(this, this.extController);
tabReloader = new TabReloader(this, this.proxyHandler);

async init() {
Expand All @@ -38,7 +40,7 @@ class Main {
await observer.init();
}
expose(this.vpnController);
expose(this.tabHandler);
expose(this.extController);
expose(this.proxyHandler);

this.#handlingEvent = false;
Expand Down
1 change: 1 addition & 0 deletions src/background/proxyHandler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

export { SiteContext } from "./siteContext.js";
export { ProxyHandler } from "./proxyHandler.js";
export { ProxyUtils } from "./proxyUtils.js";
Loading

0 comments on commit c3f1cf7

Please sign in to comment.