Skip to content
Snippets Groups Projects
Commit 64fd04bf authored by henry's avatar henry
Browse files

fixup! Lox integration

Bug 42489: Require a loxId argument for most methods.

This ensures that a method only works on the credentials of the
*expected* loxId, rather than the newest `TorSettings.bridges.lox_id`
value which may change during a session.

We also add `#activeLoxId` to stay in sync with
`TorSettings.brigdes.lox_id`. We merge `clearInvites` into its updater.
parent 21115918
Branches
Tags
1 merge request!970Update Lox module
......@@ -91,6 +91,40 @@ class LoxImpl {
#events = [];
#backgroundInterval = null;
/**
* The lox ID that is currently active.
*
* Stays in sync with TorSettings.bridges.lox_id. null when uninitialized.
*
* @type {string?}
*/
#activeLoxId = null;
/**
* Update the active lox id.
*/
#updateActiveLoxId() {
const loxId = lazy.TorSettings.bridges.lox_id;
if (loxId === this.#activeLoxId) {
return;
}
lazy.logger.debug(
`#activeLoxId switching from "${this.#activeLoxId}" to "${loxId}"`
);
if (this.#activeLoxId !== null) {
lazy.logger.debug(
`Clearing event data and invites for "${this.#activeLoxId}"`
);
// If not initializing clear the metadata for the old lox ID when it
// changes.
this.clearEventData(this.#activeLoxId);
// TODO: Do we want to keep invites? See tor-browser#42453
this.#invites = [];
this.#store();
}
this.#activeLoxId = loxId;
}
observe(subject, topic, data) {
switch (topic) {
case lazy.TorSettingsTopics.SettingsChanged:
......@@ -100,11 +134,8 @@ class LoxImpl {
changes.includes("bridges.source") ||
changes.includes("bridges.lox_id")
) {
// if lox_id has changed, clear event and invite queues
if (changes.includes("bridges.lox_id")) {
this.clearEventData();
this.clearInvites();
}
// The lox_id may have changed.
this.#updateActiveLoxId();
// Only run background tasks if Lox is enabled
if (this.#inuse) {
......@@ -121,6 +152,8 @@ class LoxImpl {
}
break;
case lazy.TorSettingsTopics.Ready:
// Set the initial #activeLoxId.
this.#updateActiveLoxId();
// Run background tasks every 12 hours if Lox is enabled
if (this.#inuse) {
this.#backgroundInterval = setInterval(
......@@ -134,9 +167,9 @@ class LoxImpl {
get #inuse() {
return (
Boolean(this.#activeLoxId) &&
lazy.TorSettings.bridges.enabled === true &&
lazy.TorSettings.bridges.source === lazy.TorBridgeSource.Lox &&
lazy.TorSettings.bridges.lox_id
lazy.TorSettings.bridges.source === lazy.TorBridgeSource.Lox
);
}
......@@ -318,7 +351,12 @@ class LoxImpl {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
const loxId = lazy.TorSettings.bridges.lox_id;
// Only run background tasks for the active lox ID.
const loxId = this.#activeLoxId;
if (!loxId) {
lazy.logger.warn("No loxId for the background task");
return;
}
try {
const levelup = await this.#attemptUpgrade(loxId);
if (levelup) {
......@@ -490,14 +528,14 @@ class LoxImpl {
* - there is no saved Lox credential, or
* - the saved credential does not have any invitations available.
*
* @param {string} loxId - The ID to generate an invite for.
* @returns {string} A valid Lox invitation.
*/
async generateInvite() {
async generateInvite(loxId) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
const loxId = lazy.TorSettings.bridges.lox_id;
if (!loxId || !this.#credentials[loxId]) {
if (!this.#credentials[loxId]) {
throw new LoxError(LoxErrors.MissingCredential);
}
await this.#getPubKeys();
......@@ -538,15 +576,15 @@ class LoxImpl {
/**
* Get the number of invites that a user has remaining.
*
* @param {string} loxId - The ID to check.
* @returns {int} The number of invites that can still be generated by a
* user's credential.
*/
getRemainingInviteCount() {
getRemainingInviteCount(loxId) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
const loxId = lazy.TorSettings.bridges.lox_id;
if (!loxId || !this.#credentials[loxId]) {
if (!this.#credentials[loxId]) {
throw new LoxError(LoxErrors.MissingCredential);
}
return parseInt(lazy.get_invites_remaining(this.#credentials[loxId]));
......@@ -610,7 +648,7 @@ class LoxImpl {
if (level < 1) {
// attempt trust promotion instead
try {
success = await this.#trustMigration();
success = await this.#trustMigration(loxId);
} catch (err) {
lazy.logger.error(err);
return false;
......@@ -640,14 +678,11 @@ class LoxImpl {
/**
* Attempt to migrate from an untrusted to a trusted Lox credential
*
* @param {string} loxId - The ID to use.
* @returns {Promise<bool>} A bool value indicated whether the credential
* was successfully migrated.
*/
async #trustMigration() {
const loxId = lazy.TorSettings.bridges.lox_id;
if (!loxId || !this.#credentials[loxId]) {
throw new LoxError(LoxErrors.MissingCredential);
}
async #trustMigration(loxId) {
await this.#getPubKeys();
return new Promise((resolve, reject) => {
let request = "";
......@@ -715,61 +750,68 @@ class LoxImpl {
/**
* Get a list of accumulated events.
*
* @param {string} loxId - The ID to get events for.
* @returns {EventData[]} A list of the accumulated, unacknowledged events
* associated with a user's credential.
*/
getEventData() {
getEventData(loxId) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
const loxId = lazy.TorSettings.bridges.lox_id;
if (!loxId || !this.#credentials[loxId]) {
throw new LoxError(LoxErrors.MissingCredential);
if (loxId !== this.#activeLoxId) {
lazy.logger.warn(
`No event data for loxId ${loxId} since it was replaced by ${
this.#activeLoxId
}`
);
return [];
}
return this.#events;
}
/**
* Clears accumulated event data.
*
* Should be called whenever the user acknowledges the existing events.
*
* @param {string} loxId - The ID to clear events for.
*/
clearEventData() {
clearEventData(loxId) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
this.#events = [];
this.#store();
}
/**
* Clears accumulated invitations.
*/
clearInvites() {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
if (loxId !== this.#activeLoxId) {
lazy.logger.warn(
`Not clearing event data for loxId ${loxId} since it was replaced by ${
this.#activeLoxId
}`
);
return;
}
this.#invites = [];
this.#events = [];
this.#store();
}
/**
* @typedef {object} UnlockData
*
* @property {string} date - The date-time for the next level up, formatted as YYYY-MM-DDTHH:mm:ssZ.
* @property {integer} nextLevel - The next level. Levels count from 0, so this will be 1 or greater.
*
* @property {string} date - The date-time for the next level up, formatted as
* YYYY-MM-DDTHH:mm:ssZ.
* @property {integer} nextLevel - The next level. Levels count from 0, so
* this will be 1 or greater.
*/
/**
* Get details about the next feature unlock.
*
* @param {string} loxId - The ID to get the unlock for.
* @returns {UnlockData} - Details about the next unlock.
*/
async getNextUnlock() {
async getNextUnlock(loxId) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
const loxId = lazy.TorSettings.bridges.lox_id;
if (!loxId || !this.#credentials[loxId]) {
if (!this.#credentials[loxId]) {
throw new LoxError(LoxErrors.MissingCredential);
}
await this.#getConstants();
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment