tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SessionMigration.sys.mjs (4484B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const lazy = {};
      6 
      7 ChromeUtils.defineESModuleGetters(lazy, {
      8  E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
      9  SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
     10  TabGroupState: "resource:///modules/sessionstore/TabGroupState.sys.mjs",
     11 });
     12 
     13 var SessionMigrationInternal = {
     14  /**
     15   * Convert the original session restore state into a minimal state. It will
     16   * only contain:
     17   * - open windows
     18   *   - with tabs
     19   *     - with history entries with only title, url, triggeringPrincipal
     20   *     - with pinned state
     21   *     - with tab group info
     22   *     - with selected tab info
     23   *   - with selected window info
     24   * - saved tab groups
     25   *
     26   * The complete state is then wrapped into the "about:welcomeback" page as
     27   * form field info to be restored when restoring the state.
     28   */
     29  convertState(aStateObj) {
     30    let state = {
     31      selectedWindow: aStateObj.selectedWindow,
     32      _closedWindows: [],
     33    };
     34    let savedGroups = aStateObj.savedGroups || [];
     35    state.windows = aStateObj.windows.map(function (oldWin) {
     36      var win = { extData: {} };
     37      if (oldWin.groups) {
     38        win.groups = oldWin.groups;
     39      }
     40      let groupsToSave = new Map();
     41      win.tabs = oldWin.tabs.map(function (oldTab) {
     42        var tab = {};
     43        // Keep only titles, urls and triggeringPrincipals for history entries
     44        tab.entries = oldTab.entries.map(function (entry) {
     45          return {
     46            url: entry.url,
     47            triggeringPrincipal_base64: entry.triggeringPrincipal_base64,
     48            title: entry.title,
     49          };
     50        });
     51        tab.index = oldTab.index;
     52        tab.hidden = oldTab.hidden;
     53        tab.pinned = oldTab.pinned;
     54        if (oldTab.groupId) {
     55          tab.groupId = oldTab.groupId;
     56          let groupStateToSave = oldWin.groups.find(
     57            groupState => groupState.id == oldTab.groupId
     58          );
     59          let groupToSave = groupsToSave.get(groupStateToSave.id);
     60          if (!groupToSave) {
     61            groupToSave =
     62              lazy.TabGroupState.savedInClosedWindow(groupStateToSave);
     63            // If the session is manually restored, these groups will be removed from the saved groups list
     64            // to prevent duplication.
     65            groupToSave.removeAfterRestore = true;
     66            groupsToSave.set(groupStateToSave.id, groupToSave);
     67          }
     68          groupToSave.tabs.push(
     69            lazy.SessionStore.formatTabStateForSavedGroup(tab)
     70          );
     71        }
     72        return tab;
     73      });
     74      groupsToSave.forEach(groupState => {
     75        const alreadySavedGroup = savedGroups.find(
     76          existingGroup => existingGroup.id == groupState.id
     77        );
     78        if (alreadySavedGroup) {
     79          alreadySavedGroup.removeAfterRestore = true;
     80        } else {
     81          savedGroups.push(groupState);
     82        }
     83      });
     84      win.selected = oldWin.selected;
     85      win._closedTabs = [];
     86      return win;
     87    });
     88    let url = "about:welcomeback";
     89    let formdata = { id: { sessionData: state }, url };
     90    let entry = {
     91      url,
     92      triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL,
     93    };
     94    return {
     95      windows: [{ tabs: [{ entries: [entry], formdata }] }],
     96      savedGroups,
     97    };
     98  },
     99  /**
    100   * Asynchronously read session restore state (JSON) from a path
    101   */
    102  readState(aPath) {
    103    return IOUtils.readJSON(aPath, { decompress: true });
    104  },
    105  /**
    106   * Asynchronously write session restore state as JSON to a path
    107   */
    108  writeState(aPath, aState) {
    109    return IOUtils.writeJSON(aPath, aState, {
    110      compress: true,
    111      tmpPath: `${aPath}.tmp`,
    112    });
    113  },
    114 };
    115 
    116 export var SessionMigration = {
    117  /**
    118   * Migrate a limited set of session data from one path to another.
    119   */
    120  migrate(aFromPath, aToPath) {
    121    return (async function () {
    122      let inState = await SessionMigrationInternal.readState(aFromPath);
    123      let outState = SessionMigrationInternal.convertState(inState);
    124      // Unfortunately, we can't use SessionStore's own SessionFile to
    125      // write out the data because it has a dependency on the profile dir
    126      // being known. When the migration runs, there is no guarantee that
    127      // that's true.
    128      await SessionMigrationInternal.writeState(aToPath, outState);
    129    })();
    130  },
    131 };