Pier Angelo Vendrame pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser

Commits:

8 changed files:

Changes:

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
    ... ... @@ -6319,10 +6319,10 @@ public class GeckoSession {
    6319 6319
           }
    
    6320 6320
     
    
    6321 6321
           private static String normalizePath(String input) {
    
    6322
    -          // For an unclear reason, Android media picker delivers file paths
    
    6323
    -          // starting with double slash. Firefox performs path validation on
    
    6324
    -          // all paths, and double slash is deemed invalid.
    
    6325
    -          return input.startsWith("//") ? input.substring(1) : input;
    
    6322
    +        // For an unclear reason, Android media picker delivers file paths
    
    6323
    +        // starting with double slash. Firefox performs path validation on
    
    6324
    +        // all paths, and double slash is deemed invalid.
    
    6325
    +        return input.startsWith("//") ? input.substring(1) : input;
    
    6326 6326
           }
    
    6327 6327
     
    
    6328 6328
           private static String getFile(final @NonNull Context context, final @NonNull Uri uri) {
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
    ... ... @@ -9,671 +9,720 @@ package org.mozilla.geckoview;
    9 9
     import android.content.Context;
    
    10 10
     import android.os.AsyncTask;
    
    11 11
     import android.util.Log;
    
    12
    -
    
    13
    -import androidx.annotation.AnyThread;
    
    14 12
     import androidx.annotation.NonNull;
    
    15
    -import androidx.annotation.Nullable;
    
    16
    -
    
    17 13
     import java.io.BufferedReader;
    
    18 14
     import java.io.File;
    
    19 15
     import java.io.FileOutputStream;
    
    20 16
     import java.io.IOException;
    
    21 17
     import java.io.InputStream;
    
    22 18
     import java.io.InputStreamReader;
    
    19
    +import java.io.InterruptedIOException;
    
    23 20
     import java.util.ArrayList;
    
    21
    +import java.util.Arrays;
    
    24 22
     import java.util.HashMap;
    
    25 23
     import java.util.HashSet;
    
    26 24
     import java.util.Map;
    
    27
    -import java.util.Set;
    
    28
    -
    
    29 25
     import org.mozilla.gecko.EventDispatcher;
    
    30 26
     import org.mozilla.gecko.GeckoAppShell;
    
    31 27
     import org.mozilla.gecko.util.BundleEventListener;
    
    32 28
     import org.mozilla.gecko.util.EventCallback;
    
    33 29
     import org.mozilla.gecko.util.GeckoBundle;
    
    34
    -
    
    35 30
     import org.mozilla.geckoview.androidlegacysettings.TorLegacyAndroidSettings;
    
    36 31
     
    
    37 32
     public class TorIntegrationAndroid implements BundleEventListener {
    
    38
    -    private static final String TAG = "TorIntegrationAndroid";
    
    39
    -
    
    40
    -    // Events we listen to
    
    41
    -    private static final String EVENT_TOR_START = "GeckoView:Tor:StartTor";
    
    42
    -    private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
    
    43
    -    private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
    
    44
    -    private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
    
    45
    -    private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged";
    
    46
    -    private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
    
    47
    -    private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
    
    48
    -    private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
    
    49
    -    private static final String EVENT_TOR_LOGS = "GeckoView:Tor:Logs";
    
    50
    -    private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
    
    51
    -    private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
    
    52
    -    private static final String EVENT_SETTINGS_OPEN = "GeckoView:Tor:OpenSettings";
    
    53
    -
    
    54
    -    // Events we emit
    
    55
    -    private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
    
    56
    -    private static final String EVENT_SETTINGS_SET = "GeckoView:Tor:SettingsSet";
    
    57
    -    private static final String EVENT_SETTINGS_APPLY = "GeckoView:Tor:SettingsApply";
    
    58
    -    private static final String EVENT_SETTINGS_SAVE = "GeckoView:Tor:SettingsSave";
    
    59
    -    private static final String EVENT_BOOTSTRAP_BEGIN = "GeckoView:Tor:BootstrapBegin";
    
    60
    -    private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
    
    61
    -    private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
    
    62
    -    private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
    
    63
    -
    
    64
    -    private static final String CONTROL_PORT_FILE = "/control-ipc";
    
    65
    -    private static final String SOCKS_FILE = "/socks-ipc";
    
    66
    -    private static final String COOKIE_AUTH_FILE = "/auth-file";
    
    67
    -
    
    68
    -    private final String mLibraryDir;
    
    69
    -    private final String mCacheDir;
    
    70
    -    private final String mIpcDirectory;
    
    71
    -    private final File mDataDir;
    
    72
    -
    
    73
    -    private TorProcess mTorProcess = null;
    
    74
    -    /**
    
    75
    -     * The first time we run a Tor process in this session, we copy some configuration files to be
    
    76
    -     * sure we always have the latest version, but if we re-launch a tor process we do not need to
    
    77
    -     * copy them again.
    
    78
    -     */
    
    79
    -    private boolean mCopiedConfigFiles = false;
    
    80
    -    /**
    
    81
    -     * Allow multiple proxies to be started, even though it might not actually happen.
    
    82
    -     * The key should be positive (also 0 is not allowed).
    
    83
    -     */
    
    84
    -    private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
    
    85
    -    private int mMeekCounter;
    
    86
    -
    
    87
    -    /**
    
    88
    -     * mSettings is a Java-side copy of the authoritative settings in the JS code.
    
    89
    -     * It's useful to maintain as the UI may be fetching these options often and we don't watch each
    
    90
    -     * fetch to be a passthrough to JS with marshalling/unmarshalling each time.
    
    91
    -     */
    
    92
    -    private TorSettings mSettings = null;
    
    93
    -
    
    94
    -    /* package */ TorIntegrationAndroid(Context context) {
    
    95
    -        mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
    
    96
    -        mCacheDir = context.getCacheDir().getAbsolutePath();
    
    97
    -        mIpcDirectory = mCacheDir + "/tor-private";
    
    98
    -        mDataDir = new File(context.getFilesDir(), "tor");
    
    99
    -        registerListener();
    
    33
    +  private static final String TAG = "TorIntegrationAndroid";
    
    34
    +
    
    35
    +  // Events we listen to
    
    36
    +  private static final String EVENT_TOR_START = "GeckoView:Tor:StartTor";
    
    37
    +  private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
    
    38
    +  private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
    
    39
    +  private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
    
    40
    +  private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged";
    
    41
    +  private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
    
    42
    +  private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
    
    43
    +  private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
    
    44
    +  private static final String EVENT_TOR_LOGS = "GeckoView:Tor:Logs";
    
    45
    +  private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
    
    46
    +  private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
    
    47
    +  private static final String EVENT_SETTINGS_OPEN = "GeckoView:Tor:OpenSettings";
    
    48
    +
    
    49
    +  // Events we emit
    
    50
    +  private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
    
    51
    +  private static final String EVENT_SETTINGS_SET = "GeckoView:Tor:SettingsSet";
    
    52
    +  private static final String EVENT_SETTINGS_APPLY = "GeckoView:Tor:SettingsApply";
    
    53
    +  private static final String EVENT_SETTINGS_SAVE = "GeckoView:Tor:SettingsSave";
    
    54
    +  private static final String EVENT_BOOTSTRAP_BEGIN = "GeckoView:Tor:BootstrapBegin";
    
    55
    +  private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
    
    56
    +  private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
    
    57
    +  private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
    
    58
    +
    
    59
    +  private static final String CONTROL_PORT_FILE = "/control-ipc";
    
    60
    +  private static final String SOCKS_FILE = "/socks-ipc";
    
    61
    +  private static final String COOKIE_AUTH_FILE = "/auth-file";
    
    62
    +
    
    63
    +  private final String mLibraryDir;
    
    64
    +  private final String mCacheDir;
    
    65
    +  private final String mIpcDirectory;
    
    66
    +  private final File mDataDir;
    
    67
    +
    
    68
    +  private TorProcess mTorProcess = null;
    
    69
    +
    
    70
    +  /**
    
    71
    +   * The first time we run a Tor process in this session, we copy some configuration files to be
    
    72
    +   * sure we always have the latest version, but if we re-launch a tor process we do not need to
    
    73
    +   * copy them again.
    
    74
    +   */
    
    75
    +  private boolean mCopiedConfigFiles = false;
    
    76
    +
    
    77
    +  /**
    
    78
    +   * Allow multiple proxies to be started, even though it might not actually happen. The key should
    
    79
    +   * be positive (also 0 is not allowed).
    
    80
    +   */
    
    81
    +  private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
    
    82
    +
    
    83
    +  private int mMeekCounter;
    
    84
    +
    
    85
    +  /**
    
    86
    +   * mSettings is a Java-side copy of the authoritative settings in the JS code. It's useful to
    
    87
    +   * maintain as the UI may be fetching these options often and we don't watch each fetch to be a
    
    88
    +   * passthrough to JS with marshalling/unmarshalling each time.
    
    89
    +   */
    
    90
    +  private TorSettings mSettings = null;
    
    91
    +
    
    92
    +  /* package */ TorIntegrationAndroid(Context context) {
    
    93
    +    mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
    
    94
    +    mCacheDir = context.getCacheDir().getAbsolutePath();
    
    95
    +    mIpcDirectory = mCacheDir + "/tor-private";
    
    96
    +    mDataDir = new File(context.getFilesDir(), "tor");
    
    97
    +    registerListener();
    
    98
    +  }
    
    99
    +
    
    100
    +  /* package */ synchronized void shutdown() {
    
    101
    +    // FIXME: It seems this never gets called
    
    102
    +    if (mTorProcess != null) {
    
    103
    +      mTorProcess.shutdown();
    
    104
    +      mTorProcess = null;
    
    100 105
         }
    
    101
    -
    
    102
    -    /* package */ synchronized void shutdown() {
    
    103
    -        // FIXME: It seems this never gets called
    
    104
    -        if (mTorProcess != null) {
    
    105
    -            mTorProcess.shutdown();
    
    106
    -            mTorProcess = null;
    
    107
    -        }
    
    106
    +  }
    
    107
    +
    
    108
    +  private void registerListener() {
    
    109
    +    EventDispatcher.getInstance()
    
    110
    +        .registerUiThreadListener(
    
    111
    +            this,
    
    112
    +            EVENT_TOR_START,
    
    113
    +            EVENT_MEEK_START,
    
    114
    +            EVENT_MEEK_STOP,
    
    115
    +            EVENT_SETTINGS_READY,
    
    116
    +            EVENT_SETTINGS_CHANGED,
    
    117
    +            EVENT_CONNECT_STATE_CHANGED,
    
    118
    +            EVENT_CONNECT_ERROR,
    
    119
    +            EVENT_BOOTSTRAP_PROGRESS,
    
    120
    +            EVENT_BOOTSTRAP_COMPLETE,
    
    121
    +            EVENT_TOR_LOGS,
    
    122
    +            EVENT_SETTINGS_OPEN);
    
    123
    +  }
    
    124
    +
    
    125
    +  @Override // BundleEventListener
    
    126
    +  public synchronized void handleMessage(
    
    127
    +      final String event, final GeckoBundle message, final EventCallback callback) {
    
    128
    +    if (EVENT_TOR_START.equals(event)) {
    
    129
    +      startDaemon(message, callback);
    
    130
    +    } else if (EVENT_TOR_STOP.equals(event)) {
    
    131
    +      stopDaemon(message, callback);
    
    132
    +    } else if (EVENT_MEEK_START.equals(event)) {
    
    133
    +      startMeek(message, callback);
    
    134
    +    } else if (EVENT_MEEK_STOP.equals(event)) {
    
    135
    +      stopMeek(message, callback);
    
    136
    +    } else if (EVENT_SETTINGS_READY.equals(event)) {
    
    137
    +      try {
    
    138
    +        new SettingsLoader().execute(message);
    
    139
    +      } catch (Exception e) {
    
    140
    +        Log.e(TAG, "SettingsLoader error: " + e.toString());
    
    141
    +      }
    
    142
    +    } else if (EVENT_SETTINGS_CHANGED.equals(event)) {
    
    143
    +      GeckoBundle newSettings = message.getBundle("settings");
    
    144
    +      if (newSettings != null) {
    
    145
    +        // TODO: Should we notify listeners?
    
    146
    +        mSettings = new TorSettings(newSettings);
    
    147
    +      } else {
    
    148
    +        Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
    
    149
    +      }
    
    150
    +    } else if (EVENT_CONNECT_STATE_CHANGED.equals(event)) {
    
    151
    +      String state = message.getString("state");
    
    152
    +      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    153
    +        listener.onBootstrapStateChange(state);
    
    154
    +      }
    
    155
    +    } else if (EVENT_CONNECT_ERROR.equals(event)) {
    
    156
    +      String code = message.getString("code");
    
    157
    +      String msg = message.getString("message");
    
    158
    +      String phase = message.getString("phase");
    
    159
    +      String reason = message.getString("reason");
    
    160
    +      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    161
    +        listener.onBootstrapError(code, msg, phase, reason);
    
    162
    +      }
    
    163
    +    } else if (EVENT_BOOTSTRAP_PROGRESS.equals(event)) {
    
    164
    +      double progress = message.getDouble("progress");
    
    165
    +      boolean hasWarnings = message.getBoolean("hasWarnings");
    
    166
    +      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    167
    +        listener.onBootstrapProgress(progress, hasWarnings);
    
    168
    +      }
    
    169
    +    } else if (EVENT_BOOTSTRAP_COMPLETE.equals(event)) {
    
    170
    +      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    171
    +        listener.onBootstrapComplete();
    
    172
    +      }
    
    173
    +    } else if (EVENT_TOR_LOGS.equals(event)) {
    
    174
    +      String msg = message.getString("message");
    
    175
    +      String type = message.getString("logType");
    
    176
    +      for (TorLogListener listener : mLogListeners) {
    
    177
    +        listener.onLog(type, msg);
    
    178
    +      }
    
    179
    +    } else if (EVENT_SETTINGS_OPEN.equals(event)) {
    
    180
    +      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    181
    +        listener.onSettingsRequested();
    
    182
    +      }
    
    108 183
         }
    
    109
    -
    
    110
    -    private void registerListener() {
    
    111
    -        EventDispatcher.getInstance()
    
    112
    -                .registerUiThreadListener(
    
    113
    -                        this,
    
    114
    -                        EVENT_TOR_START,
    
    115
    -                        EVENT_MEEK_START,
    
    116
    -                        EVENT_MEEK_STOP,
    
    117
    -                        EVENT_SETTINGS_READY,
    
    118
    -                        EVENT_SETTINGS_CHANGED,
    
    119
    -                        EVENT_CONNECT_STATE_CHANGED,
    
    120
    -                        EVENT_CONNECT_ERROR,
    
    121
    -                        EVENT_BOOTSTRAP_PROGRESS,
    
    122
    -                        EVENT_BOOTSTRAP_COMPLETE,
    
    123
    -                        EVENT_TOR_LOGS,
    
    124
    -                        EVENT_SETTINGS_OPEN);
    
    184
    +  }
    
    185
    +
    
    186
    +  private class SettingsLoader extends AsyncTask<GeckoBundle, Void, TorSettings> {
    
    187
    +    protected TorSettings doInBackground(GeckoBundle... messages) {
    
    188
    +      GeckoBundle message = messages[0];
    
    189
    +      TorSettings settings;
    
    190
    +      if (TorLegacyAndroidSettings.unmigrated()) {
    
    191
    +        settings = TorLegacyAndroidSettings.loadTorSettings();
    
    192
    +      } else {
    
    193
    +        GeckoBundle bundle = message.getBundle("settings");
    
    194
    +        settings = new TorSettings(bundle);
    
    195
    +      }
    
    196
    +      return settings;
    
    125 197
         }
    
    126 198
     
    
    127
    -    @Override // BundleEventListener
    
    128
    -    public synchronized void handleMessage(
    
    129
    -            final String event, final GeckoBundle message, final EventCallback callback) {
    
    130
    -        if (EVENT_TOR_START.equals(event)) {
    
    131
    -            startDaemon(message, callback);
    
    132
    -        } else if (EVENT_TOR_STOP.equals(event)) {
    
    133
    -            stopDaemon(message, callback);
    
    134
    -        } else if (EVENT_MEEK_START.equals(event)) {
    
    135
    -            startMeek(message, callback);
    
    136
    -        } else if (EVENT_MEEK_STOP.equals(event)) {
    
    137
    -            stopMeek(message, callback);
    
    138
    -        } else if (EVENT_SETTINGS_READY.equals(event)) {
    
    139
    -            try {
    
    140
    -                new SettingsLoader().execute(message);
    
    141
    -            } catch(Exception e) {
    
    142
    -                Log.e(TAG, "SettingsLoader error: "+ e.toString());
    
    143
    -            }
    
    144
    -        } else if (EVENT_SETTINGS_CHANGED.equals(event)) {
    
    145
    -            GeckoBundle newSettings = message.getBundle("settings");
    
    146
    -            if (newSettings != null) {
    
    147
    -                // TODO: Should we notify listeners?
    
    148
    -                mSettings = new TorSettings(newSettings);
    
    149
    -            } else {
    
    150
    -                Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
    
    151
    -            }
    
    152
    -        } else if (EVENT_CONNECT_STATE_CHANGED.equals(event)) {
    
    153
    -            String state = message.getString("state");
    
    154
    -            for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
    
    155
    -                listener.onBootstrapStateChange(state);
    
    156
    -            }
    
    157
    -        } else if (EVENT_CONNECT_ERROR.equals(event)) {
    
    158
    -            String code = message.getString("code");
    
    159
    -            String msg = message.getString("message");
    
    160
    -            String phase = message.getString("phase");
    
    161
    -            String reason = message.getString("reason");
    
    162
    -            for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
    
    163
    -                listener.onBootstrapError(code, msg, phase, reason);
    
    164
    -            }
    
    165
    -        } else if (EVENT_BOOTSTRAP_PROGRESS.equals(event)) {
    
    166
    -            double progress = message.getDouble("progress");
    
    167
    -            boolean hasWarnings = message.getBoolean("hasWarnings");
    
    168
    -            for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
    
    169
    -                listener.onBootstrapProgress(progress, hasWarnings);
    
    170
    -            }
    
    171
    -        } else if (EVENT_BOOTSTRAP_COMPLETE.equals(event)) {
    
    172
    -            for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
    
    173
    -                listener.onBootstrapComplete();
    
    174
    -            }
    
    175
    -        } else if (EVENT_TOR_LOGS.equals(event)) {
    
    176
    -            String msg = message.getString("message");
    
    177
    -            String type = message.getString("logType");
    
    178
    -            for (TorLogListener listener: mLogListeners) {
    
    179
    -                    listener.onLog(type, msg);
    
    180
    -            }
    
    181
    -        } else if (EVENT_SETTINGS_OPEN.equals(event)) {
    
    182
    -            for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
    
    183
    -                listener.onSettingsRequested();
    
    184
    -            }
    
    185
    -        }
    
    199
    +    @Override
    
    200
    +    protected void onPostExecute(TorSettings torSettings) {
    
    201
    +      mSettings = torSettings;
    
    202
    +      if (TorLegacyAndroidSettings.unmigrated()) {
    
    203
    +        setSettings(mSettings, true, true);
    
    204
    +        TorLegacyAndroidSettings.setMigrated();
    
    205
    +      }
    
    206
    +    }
    
    207
    +  }
    
    208
    +
    
    209
    +  private synchronized void startDaemon(final GeckoBundle message, final EventCallback callback) {
    
    210
    +    // Let JS generate this to possibly reduce the chance of race conditions.
    
    211
    +    String handle = message.getString("handle", "");
    
    212
    +    if (handle.isEmpty()) {
    
    213
    +      Log.e(TAG, "Requested to start a tor process without a handle.");
    
    214
    +      callback.sendError("Expected a handle for the new process.");
    
    215
    +      return;
    
    186 216
         }
    
    217
    +    Log.d(TAG, "Starting the a tor process with handle " + handle);
    
    187 218
     
    
    188
    -    private class SettingsLoader extends AsyncTask<GeckoBundle, Void, TorSettings> {
    
    189
    -        protected TorSettings doInBackground(GeckoBundle... messages) {
    
    190
    -            GeckoBundle message = messages[0];
    
    191
    -            TorSettings settings;
    
    192
    -            if (TorLegacyAndroidSettings.unmigrated()) {
    
    193
    -                settings = TorLegacyAndroidSettings.loadTorSettings();
    
    194
    -            } else {
    
    195
    -                GeckoBundle bundle = message.getBundle("settings");
    
    196
    -                settings = new TorSettings(bundle);
    
    197
    -            }
    
    198
    -            return settings;
    
    199
    -        }
    
    219
    +    TorProcess previousProcess = mTorProcess;
    
    220
    +    if (previousProcess != null) {
    
    221
    +      Log.w(TAG, "We still have a running process: " + previousProcess.getHandle());
    
    222
    +    }
    
    223
    +    mTorProcess = new TorProcess(handle);
    
    224
    +
    
    225
    +    GeckoBundle bundle = new GeckoBundle(3);
    
    226
    +    bundle.putString("controlPortPath", mIpcDirectory + CONTROL_PORT_FILE);
    
    227
    +    bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
    
    228
    +    bundle.putString("cookieFilePath", mIpcDirectory + COOKIE_AUTH_FILE);
    
    229
    +    callback.sendSuccess(bundle);
    
    230
    +  }
    
    231
    +
    
    232
    +  private synchronized void stopDaemon(final GeckoBundle message, final EventCallback callback) {
    
    233
    +    if (mTorProcess == null) {
    
    234
    +      if (callback != null) {
    
    235
    +        callback.sendSuccess(null);
    
    236
    +      }
    
    237
    +      return;
    
    238
    +    }
    
    239
    +    String handle = message.getString("handle", "");
    
    240
    +    if (!mTorProcess.getHandle().equals(handle)) {
    
    241
    +      GeckoBundle bundle = new GeckoBundle(1);
    
    242
    +      bundle.putString(
    
    243
    +          "error", "The requested process has not been found. It might have already been stopped.");
    
    244
    +      callback.sendError(bundle);
    
    245
    +      return;
    
    246
    +    }
    
    247
    +    mTorProcess.shutdown();
    
    248
    +    mTorProcess = null;
    
    249
    +    callback.sendSuccess(null);
    
    250
    +  }
    
    251
    +
    
    252
    +  class TorProcess extends Thread {
    
    253
    +    private static final String EVENT_TOR_STARTED = "GeckoView:Tor:TorStarted";
    
    254
    +    private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
    
    255
    +    private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
    
    256
    +    private final String mHandle;
    
    257
    +    private Process mProcess = null;
    
    258
    +
    
    259
    +    TorProcess(String handle) {
    
    260
    +      mHandle = handle;
    
    261
    +      setName("tor-process-" + handle);
    
    262
    +      start();
    
    263
    +    }
    
    200 264
     
    
    201
    -        @Override
    
    202
    -        protected void onPostExecute(TorSettings torSettings) {
    
    203
    -            mSettings = torSettings;
    
    204
    -            if (TorLegacyAndroidSettings.unmigrated()) {
    
    205
    -                setSettings(mSettings, true, true);
    
    206
    -                TorLegacyAndroidSettings.setMigrated();
    
    207
    -            }
    
    265
    +    @Override
    
    266
    +    public void run() {
    
    267
    +      cleanIpcDirectory();
    
    268
    +
    
    269
    +      final String ipcDir = TorIntegrationAndroid.this.mIpcDirectory;
    
    270
    +      final ArrayList<String> args = new ArrayList<>();
    
    271
    +      args.add(mLibraryDir + "/libTor.so");
    
    272
    +      args.add("DisableNetwork");
    
    273
    +      args.add("1");
    
    274
    +      args.add("+__ControlPort");
    
    275
    +      args.add("unix:" + ipcDir + CONTROL_PORT_FILE);
    
    276
    +      args.add("+__SocksPort");
    
    277
    +      args.add("unix:" + ipcDir + SOCKS_FILE + " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth");
    
    278
    +      args.add("CookieAuthentication");
    
    279
    +      args.add("1");
    
    280
    +      args.add("CookieAuthFile");
    
    281
    +      args.add(ipcDir + COOKIE_AUTH_FILE);
    
    282
    +      args.add("DataDirectory");
    
    283
    +      args.add(mDataDir.getAbsolutePath());
    
    284
    +      boolean copied = true;
    
    285
    +      try {
    
    286
    +        copyAndUseConfigFile("--defaults-torrc", "torrc-defaults", args);
    
    287
    +      } catch (IOException e) {
    
    288
    +        Log.w(
    
    289
    +            TAG, "torrc-default cannot be created, pluggable transports will not be available", e);
    
    290
    +        copied = false;
    
    291
    +      }
    
    292
    +      // tor-browser#42607: For now we do not ship geoip databases, as we
    
    293
    +      // do not have the circuit display functionality and they allow us
    
    294
    +      // to save some space in the final APK.
    
    295
    +      /*try {
    
    296
    +          copyAndUseConfigFile("GeoIPFile", "geoip", args);
    
    297
    +          copyAndUseConfigFile("GeoIPv6File", "geoip6", args);
    
    298
    +      } catch (IOException e) {
    
    299
    +          Log.w(TAG, "GeoIP files cannot be created, this feature will not be available.", e);
    
    300
    +          copied = false;
    
    301
    +      }*/
    
    302
    +      mCopiedConfigFiles = copied;
    
    303
    +
    
    304
    +      Log.d(TAG, "Starting tor with the follwing args: " + args.toString());
    
    305
    +      final ProcessBuilder builder = new ProcessBuilder(args);
    
    306
    +      builder.directory(new File(mLibraryDir));
    
    307
    +      try {
    
    308
    +        mProcess = builder.start();
    
    309
    +      } catch (IOException e) {
    
    310
    +        Log.e(TAG, "Cannot start tor " + mHandle, e);
    
    311
    +        final GeckoBundle data = new GeckoBundle(2);
    
    312
    +        data.putString("handle", mHandle);
    
    313
    +        data.putString("error", e.getMessage());
    
    314
    +        EventDispatcher.getInstance().dispatch(EVENT_TOR_START_FAILED, data);
    
    315
    +        return;
    
    316
    +      }
    
    317
    +      Log.i(TAG, "Tor process " + mHandle + " started.");
    
    318
    +      {
    
    319
    +        final GeckoBundle data = new GeckoBundle(1);
    
    320
    +        data.putString("handle", mHandle);
    
    321
    +        EventDispatcher.getInstance().dispatch(EVENT_TOR_STARTED, data);
    
    322
    +      }
    
    323
    +      try {
    
    324
    +        BufferedReader reader =
    
    325
    +            new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
    
    326
    +        String line;
    
    327
    +        while ((line = reader.readLine()) != null) {
    
    328
    +          Log.i(TAG, "[tor-" + mHandle + "] " + line);
    
    208 329
             }
    
    330
    +      } catch (IOException e) {
    
    331
    +        Log.e(TAG, "Failed to read stdout of the tor process " + mHandle, e);
    
    332
    +      }
    
    333
    +      Log.d(TAG, "Exiting the stdout loop for process " + mHandle);
    
    334
    +      final GeckoBundle data = new GeckoBundle(2);
    
    335
    +      data.putString("handle", mHandle);
    
    336
    +      try {
    
    337
    +        data.putInt("status", mProcess.waitFor());
    
    338
    +      } catch (InterruptedException e) {
    
    339
    +        Log.e(TAG, "Failed to wait for the tor process " + mHandle, e);
    
    340
    +        data.putInt("status", 0xdeadbeef);
    
    341
    +      }
    
    342
    +      // FIXME: We usually don't reach this when the application is killed!
    
    343
    +      // So, we don't do our cleanup.
    
    344
    +      Log.i(TAG, "Tor process " + mHandle + " has exited.");
    
    345
    +      EventDispatcher.getInstance().dispatch(EVENT_TOR_EXITED, data);
    
    209 346
         }
    
    210 347
     
    
    211
    -    private synchronized void startDaemon(final GeckoBundle message, final EventCallback callback) {
    
    212
    -        // Let JS generate this to possibly reduce the chance of race conditions.
    
    213
    -        String handle = message.getString("handle", "");
    
    214
    -        if (handle.isEmpty()) {
    
    215
    -            Log.e(TAG, "Requested to start a tor process without a handle.");
    
    216
    -            callback.sendError("Expected a handle for the new process.");
    
    217
    -            return;
    
    348
    +    private void cleanIpcDirectory() {
    
    349
    +      File directory = new File(TorIntegrationAndroid.this.mIpcDirectory);
    
    350
    +      if (!directory.isDirectory()) {
    
    351
    +        if (!directory.mkdirs()) {
    
    352
    +          Log.e(TAG, "Failed to create the IPC directory.");
    
    353
    +          return;
    
    218 354
             }
    
    219
    -        Log.d(TAG, "Starting the a tor process with handle " + handle);
    
    220
    -
    
    221
    -        TorProcess previousProcess = mTorProcess;
    
    222
    -        if (previousProcess != null) {
    
    223
    -            Log.w(TAG, "We still have a running process: " + previousProcess.getHandle());
    
    355
    +        try {
    
    356
    +          // First remove the permissions for everybody...
    
    357
    +          directory.setReadable(false, false);
    
    358
    +          directory.setWritable(false, false);
    
    359
    +          directory.setExecutable(false, false);
    
    360
    +          // ... then add them back, but only for the owner.
    
    361
    +          directory.setReadable(true, true);
    
    362
    +          directory.setWritable(true, true);
    
    363
    +          directory.setExecutable(true, true);
    
    364
    +        } catch (SecurityException e) {
    
    365
    +          Log.e(TAG, "Could not set the permissions to the IPC directory.", e);
    
    224 366
             }
    
    225
    -        mTorProcess = new TorProcess(handle);
    
    367
    +        return;
    
    368
    +      }
    
    369
    +      // We assume we do not have child directories, only files
    
    370
    +      File[] maybeFiles = directory.listFiles();
    
    371
    +      if (maybeFiles != null) {
    
    372
    +        for (File file : maybeFiles) {
    
    373
    +          if (!file.delete()) {
    
    374
    +            Log.d(TAG, "Could not delete " + file);
    
    375
    +          }
    
    376
    +        }
    
    377
    +      }
    
    378
    +    }
    
    226 379
     
    
    227
    -        GeckoBundle bundle = new GeckoBundle(3);
    
    228
    -        bundle.putString("controlPortPath", mIpcDirectory + CONTROL_PORT_FILE);
    
    229
    -        bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
    
    230
    -        bundle.putString("cookieFilePath", mIpcDirectory + COOKIE_AUTH_FILE);
    
    231
    -        callback.sendSuccess(bundle);
    
    380
    +    private void copyAndUseConfigFile(String option, String name, ArrayList<String> args)
    
    381
    +        throws IOException {
    
    382
    +      File file = copyConfigFile(name);
    
    383
    +      args.add(option);
    
    384
    +      args.add(file.getAbsolutePath());
    
    232 385
         }
    
    233 386
     
    
    234
    -    private synchronized void stopDaemon(final GeckoBundle message, final EventCallback callback) {
    
    235
    -        if (mTorProcess == null) {
    
    236
    -            if (callback != null) {
    
    237
    -                callback.sendSuccess(null);
    
    238
    -            }
    
    239
    -            return;
    
    387
    +    private File copyConfigFile(String name) throws IOException {
    
    388
    +      final File file = new File(mCacheDir, name);
    
    389
    +      if (mCopiedConfigFiles && file.exists()) {
    
    390
    +        return file;
    
    391
    +      }
    
    392
    +
    
    393
    +      final Context context = GeckoAppShell.getApplicationContext();
    
    394
    +      final InputStream in = context.getAssets().open("common/" + name);
    
    395
    +      // Files.copy is API 26+, so use java.io and a loop for now.
    
    396
    +      FileOutputStream out = null;
    
    397
    +      try {
    
    398
    +        out = new FileOutputStream(file);
    
    399
    +      } catch (IOException e) {
    
    400
    +        in.close();
    
    401
    +        throw e;
    
    402
    +      }
    
    403
    +      try {
    
    404
    +        byte buffer[] = new byte[4096];
    
    405
    +        int read;
    
    406
    +        while ((read = in.read(buffer)) >= 0) {
    
    407
    +          out.write(buffer, 0, read);
    
    240 408
             }
    
    241
    -        String handle = message.getString("handle", "");
    
    242
    -        if (!mTorProcess.getHandle().equals(handle)) {
    
    243
    -            GeckoBundle bundle = new GeckoBundle(1);
    
    244
    -            bundle.putString("error", "The requested process has not been found. It might have already been stopped.");
    
    245
    -            callback.sendError(bundle);
    
    246
    -            return;
    
    409
    +      } finally {
    
    410
    +        try {
    
    411
    +          in.close();
    
    412
    +        } catch (IOException e) {
    
    413
    +          Log.w(TAG, "Cannot close the input stream for " + name);
    
    247 414
             }
    
    248
    -        mTorProcess.shutdown();
    
    249
    -        mTorProcess = null;
    
    250
    -        callback.sendSuccess(null);
    
    415
    +        try {
    
    416
    +          out.close();
    
    417
    +        } catch (IOException e) {
    
    418
    +          Log.w(TAG, "Cannot close the output stream for " + name);
    
    419
    +        }
    
    420
    +      }
    
    421
    +      return file;
    
    251 422
         }
    
    252 423
     
    
    253
    -    class TorProcess extends Thread {
    
    254
    -        private static final String EVENT_TOR_STARTED = "GeckoView:Tor:TorStarted";
    
    255
    -        private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
    
    256
    -        private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
    
    257
    -        private final String mHandle;
    
    258
    -        private Process mProcess = null;
    
    259
    -
    
    260
    -        TorProcess(String handle) {
    
    261
    -            mHandle = handle;
    
    262
    -            setName("tor-process-" + handle);
    
    263
    -            start();
    
    424
    +    public void shutdown() {
    
    425
    +      if (mProcess != null && mProcess.isAlive()) {
    
    426
    +        mProcess.destroy();
    
    427
    +      }
    
    428
    +      if (isAlive()) {
    
    429
    +        try {
    
    430
    +          join();
    
    431
    +        } catch (InterruptedException e) {
    
    432
    +          Log.e(
    
    433
    +              TAG,
    
    434
    +              "Cannot join the thread for tor process " + mHandle + ", possibly already terminated",
    
    435
    +              e);
    
    264 436
             }
    
    437
    +      }
    
    438
    +    }
    
    265 439
     
    
    266
    -        @Override
    
    267
    -        public void run() {
    
    268
    -            cleanIpcDirectory();
    
    269
    -
    
    270
    -            final String ipcDir = TorIntegrationAndroid.this.mIpcDirectory;
    
    271
    -            final ArrayList<String> args = new ArrayList<>();
    
    272
    -            args.add(mLibraryDir + "/libTor.so");
    
    273
    -            args.add("DisableNetwork");
    
    274
    -            args.add("1");
    
    275
    -            args.add("+__ControlPort");
    
    276
    -            args.add("unix:" + ipcDir + CONTROL_PORT_FILE);
    
    277
    -            args.add("+__SocksPort");
    
    278
    -            args.add("unix:" + ipcDir + SOCKS_FILE + " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth");
    
    279
    -            args.add("CookieAuthentication");
    
    280
    -            args.add("1");
    
    281
    -            args.add("CookieAuthFile");
    
    282
    -            args.add(ipcDir + COOKIE_AUTH_FILE);
    
    283
    -            args.add("DataDirectory");
    
    284
    -            args.add(mDataDir.getAbsolutePath());
    
    285
    -            boolean copied = true;
    
    286
    -            try {
    
    287
    -                copyAndUseConfigFile("--defaults-torrc", "torrc-defaults", args);
    
    288
    -            } catch (IOException e) {
    
    289
    -                Log.w(TAG, "torrc-default cannot be created, pluggable transports will not be available", e);
    
    290
    -                copied = false;
    
    291
    -            }
    
    292
    -            // tor-browser#42607: For now we do not ship geoip databases, as we
    
    293
    -            // do not have the circuit display functionality and they allow us
    
    294
    -            // to save some space in the final APK.
    
    295
    -            /*try {
    
    296
    -                copyAndUseConfigFile("GeoIPFile", "geoip", args);
    
    297
    -                copyAndUseConfigFile("GeoIPv6File", "geoip6", args);
    
    298
    -            } catch (IOException e) {
    
    299
    -                Log.w(TAG, "GeoIP files cannot be created, this feature will not be available.", e);
    
    300
    -                copied = false;
    
    301
    -            }*/
    
    302
    -            mCopiedConfigFiles = copied;
    
    303
    -
    
    304
    -            Log.d(TAG, "Starting tor with the follwing args: " + args.toString());
    
    305
    -            final ProcessBuilder builder = new ProcessBuilder(args);
    
    306
    -            builder.directory(new File(mLibraryDir));
    
    307
    -            try {
    
    308
    -                mProcess = builder.start();
    
    309
    -            } catch (IOException e) {
    
    310
    -                Log.e(TAG, "Cannot start tor " + mHandle, e);
    
    311
    -                final GeckoBundle data = new GeckoBundle(2);
    
    312
    -                data.putString("handle", mHandle);
    
    313
    -                data.putString("error", e.getMessage());
    
    314
    -                EventDispatcher.getInstance().dispatch(EVENT_TOR_START_FAILED, data);
    
    315
    -                return;
    
    316
    -            }
    
    317
    -            Log.i(TAG, "Tor process " + mHandle + " started.");
    
    318
    -            {
    
    319
    -                final GeckoBundle data = new GeckoBundle(1);
    
    320
    -                data.putString("handle", mHandle);
    
    321
    -                EventDispatcher.getInstance().dispatch(EVENT_TOR_STARTED, data);
    
    322
    -            }
    
    323
    -            try {
    
    324
    -                BufferedReader reader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
    
    325
    -                String line;
    
    326
    -                while ((line = reader.readLine()) != null) {
    
    327
    -                    Log.i(TAG, "[tor-" + mHandle + "] " + line);
    
    328
    -                }
    
    329
    -            } catch (IOException e) {
    
    330
    -                Log.e(TAG, "Failed to read stdout of the tor process " + mHandle, e);
    
    331
    -            }
    
    332
    -            Log.d(TAG, "Exiting the stdout loop for process " + mHandle);
    
    333
    -            final GeckoBundle data = new GeckoBundle(2);
    
    334
    -            data.putString("handle", mHandle);
    
    335
    -            try {
    
    336
    -                data.putInt("status", mProcess.waitFor());
    
    337
    -            } catch (InterruptedException e) {
    
    338
    -                Log.e(TAG, "Failed to wait for the tor process " + mHandle, e);
    
    339
    -                data.putInt("status", 0xdeadbeef);
    
    340
    -            }
    
    341
    -            // FIXME: We usually don't reach this when the application is killed!
    
    342
    -            // So, we don't do our cleanup.
    
    343
    -            Log.i(TAG, "Tor process " + mHandle + " has exited.");
    
    344
    -            EventDispatcher.getInstance().dispatch(EVENT_TOR_EXITED, data);
    
    345
    -        }
    
    440
    +    public String getHandle() {
    
    441
    +      return mHandle;
    
    442
    +    }
    
    443
    +  }
    
    444
    +
    
    445
    +  private synchronized void startMeek(final GeckoBundle message, final EventCallback callback) {
    
    446
    +    if (callback == null) {
    
    447
    +      Log.e(TAG, "Tried to start Meek without a callback.");
    
    448
    +      return;
    
    449
    +    }
    
    450
    +    mMeekCounter++;
    
    451
    +    mMeeks.put(
    
    452
    +        new Integer(mMeekCounter),
    
    453
    +        new MeekTransport(callback, mMeekCounter, message.getStringArray("arguments")));
    
    454
    +  }
    
    455
    +
    
    456
    +  private synchronized void stopMeek(final GeckoBundle message, final EventCallback callback) {
    
    457
    +    final Integer key = message.getInteger("id");
    
    458
    +    final MeekTransport meek = mMeeks.remove(key);
    
    459
    +    if (meek != null) {
    
    460
    +      meek.shutdown();
    
    461
    +    }
    
    462
    +    if (callback != null) {
    
    463
    +      callback.sendSuccess(null);
    
    464
    +    }
    
    465
    +  }
    
    466
    +
    
    467
    +  private class MeekTransport extends Thread {
    
    468
    +    private static final String TRANSPORT = "meek_lite";
    
    469
    +    private Process mProcess;
    
    470
    +    private final EventCallback mCallback;
    
    471
    +    private final int mId;
    
    472
    +
    
    473
    +    MeekTransport(final EventCallback callback, int id, String[] args) {
    
    474
    +      setName("meek-" + id);
    
    475
    +
    
    476
    +      final String command = mLibraryDir + "/libObfs4proxy.so";
    
    477
    +      ArrayList<String> argList = new ArrayList<String>();
    
    478
    +      argList.add(command);
    
    479
    +      if (args != null && args.length > 0) {
    
    480
    +        // Normally not used, but it helps to debug only by editing JS.
    
    481
    +        Log.d(TAG, "Requested custom arguments for meek: " + String.join(" ", args));
    
    482
    +        argList.addAll(Arrays.asList(args));
    
    483
    +      }
    
    484
    +      final ProcessBuilder builder = new ProcessBuilder(argList);
    
    485
    +
    
    486
    +      File ptStateDir = new File(mDataDir, "pt_state");
    
    487
    +      Log.d(TAG, "Using " + ptStateDir.getAbsolutePath() + " as a state directory for meek.");
    
    488
    +      final Map<String, String> env = builder.environment();
    
    489
    +      env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
    
    490
    +      env.put("TOR_PT_STATE_LOCATION", ptStateDir.getAbsolutePath());
    
    491
    +      env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
    
    492
    +      env.put("TOR_PT_CLIENT_TRANSPORTS", TRANSPORT);
    
    493
    +
    
    494
    +      mCallback = callback;
    
    495
    +      mId = id;
    
    496
    +      try {
    
    497
    +        // We expect this process to be short-lived, therefore we do not bother with
    
    498
    +        // implementing this as a service.
    
    499
    +        mProcess = builder.start();
    
    500
    +      } catch (IOException e) {
    
    501
    +        Log.e(TAG, "Cannot start the PT", e);
    
    502
    +        callback.sendError(e.getMessage());
    
    503
    +        return;
    
    504
    +      }
    
    505
    +      start();
    
    506
    +    }
    
    346 507
     
    
    347
    -        private void cleanIpcDirectory() {
    
    348
    -            File directory = new File(TorIntegrationAndroid.this.mIpcDirectory);
    
    349
    -            if (!directory.isDirectory()) {
    
    350
    -                if (!directory.mkdirs()) {
    
    351
    -                    Log.e(TAG, "Failed to create the IPC directory.");
    
    352
    -                    return;
    
    353
    -                }
    
    354
    -                try {
    
    355
    -                    // First remove the permissions for everybody...
    
    356
    -                    directory.setReadable(false, false);
    
    357
    -                    directory.setWritable(false, false);
    
    358
    -                    directory.setExecutable(false, false);
    
    359
    -                    // ... then add them back, but only for the owner.
    
    360
    -                    directory.setReadable(true, true);
    
    361
    -                    directory.setWritable(true, true);
    
    362
    -                    directory.setExecutable(true, true);
    
    363
    -                } catch (SecurityException e) {
    
    364
    -                    Log.e(TAG, "Could not set the permissions to the IPC directory.", e);
    
    365
    -                }
    
    366
    -                return;
    
    508
    +    /**
    
    509
    +     * Parse the standard output of the pluggable transport to find the hostname and port it is
    
    510
    +     * listening on.
    
    511
    +     *
    
    512
    +     * <p>See also the specs for the IPC protocol at https://spec.torproject.org/pt-spec/ipc.html.
    
    513
    +     */
    
    514
    +    @Override
    
    515
    +    public void run() {
    
    516
    +      final String PROTOCOL_VERSION = "1";
    
    517
    +      String hostname = "";
    
    518
    +      boolean valid = false;
    
    519
    +      int port = 0;
    
    520
    +      String error = "Did not see a CMETHOD";
    
    521
    +      try {
    
    522
    +        InputStreamReader isr = new InputStreamReader(mProcess.getInputStream());
    
    523
    +        BufferedReader reader = new BufferedReader(isr);
    
    524
    +        String line;
    
    525
    +        while ((line = reader.readLine()) != null) {
    
    526
    +          line = line.trim();
    
    527
    +          Log.d(TAG, "Meek line: " + line);
    
    528
    +          // Split produces always at least one item
    
    529
    +          String[] tokens = line.split(" ");
    
    530
    +          if ("VERSION".equals(tokens[0])
    
    531
    +              && (tokens.length != 2 || !PROTOCOL_VERSION.equals(tokens[1]))) {
    
    532
    +            error = "Bad version: " + line;
    
    533
    +            break;
    
    534
    +          }
    
    535
    +          if ("CMETHOD".equals(tokens[0])) {
    
    536
    +            if (tokens.length != 4) {
    
    537
    +              error = "Bad number of tokens in CMETHOD: " + line;
    
    538
    +              break;
    
    367 539
                 }
    
    368
    -            // We assume we do not have child directories, only files
    
    369
    -            File[] maybeFiles = directory.listFiles();
    
    370
    -            if (maybeFiles != null) {
    
    371
    -                for (File file : maybeFiles) {
    
    372
    -                    if (!file.delete()) {
    
    373
    -                        Log.d(TAG, "Could not delete " + file);
    
    374
    -                    }
    
    375
    -                }
    
    540
    +            if (!tokens[1].equals(TRANSPORT)) {
    
    541
    +              error = "Unexpected transport: " + tokens[1];
    
    542
    +              break;
    
    376 543
                 }
    
    377
    -        }
    
    378
    -
    
    379
    -        private void copyAndUseConfigFile(String option, String name, ArrayList<String> args) throws IOException {
    
    380
    -            File file = copyConfigFile(name);
    
    381
    -            args.add(option);
    
    382
    -            args.add(file.getAbsolutePath());
    
    383
    -        }
    
    384
    -
    
    385
    -        private File copyConfigFile(String name) throws IOException {
    
    386
    -            final File file = new File(mCacheDir, name);
    
    387
    -            if (mCopiedConfigFiles && file.exists()) {
    
    388
    -                return file;
    
    544
    +            if (!"socks5".equals(tokens[2])) {
    
    545
    +              error = "Unexpected proxy type: " + tokens[2];
    
    546
    +              break;
    
    389 547
                 }
    
    390
    -
    
    391
    -            final Context context = GeckoAppShell.getApplicationContext();
    
    392
    -            final InputStream in = context.getAssets().open("common/" + name);
    
    393
    -            // Files.copy is API 26+, so use java.io and a loop for now.
    
    394
    -            FileOutputStream out = null;
    
    395
    -            try {
    
    396
    -                out = new FileOutputStream(file);
    
    397
    -            } catch (IOException e) {
    
    398
    -                in.close();
    
    399
    -                throw e;
    
    548
    +            String[] addr = tokens[3].split(":");
    
    549
    +            if (addr.length != 2) {
    
    550
    +              error = "Invalid address";
    
    551
    +              break;
    
    400 552
                 }
    
    553
    +            hostname = addr[0];
    
    401 554
                 try {
    
    402
    -                byte buffer[] = new byte[4096];
    
    403
    -                int read;
    
    404
    -                while ((read = in.read(buffer)) >= 0) {
    
    405
    -                    out.write(buffer, 0, read);
    
    406
    -                }
    
    407
    -            } finally {
    
    408
    -                try {
    
    409
    -                    in.close();
    
    410
    -                } catch (IOException e) {
    
    411
    -                    Log.w(TAG, "Cannot close the input stream for " + name);
    
    412
    -                }
    
    413
    -                try {
    
    414
    -                    out.close();
    
    415
    -                } catch (IOException e) {
    
    416
    -                    Log.w(TAG, "Cannot close the output stream for " + name);
    
    417
    -                }
    
    418
    -            }
    
    419
    -            return file;
    
    420
    -        }
    
    421
    -
    
    422
    -        public void shutdown() {
    
    423
    -            if (mProcess != null && mProcess.isAlive()) {
    
    424
    -                mProcess.destroy();
    
    555
    +              port = Integer.parseInt(addr[1]);
    
    556
    +            } catch (NumberFormatException e) {
    
    557
    +              error = "Invalid port: " + e.getMessage();
    
    558
    +              break;
    
    425 559
                 }
    
    426
    -            if (isAlive()) {
    
    427
    -                try {
    
    428
    -                    join();
    
    429
    -                } catch (InterruptedException e) {
    
    430
    -                    Log.e(TAG, "Cannot join the thread for tor process " + mHandle + ", possibly already terminated", e);
    
    431
    -                }
    
    560
    +            if (port < 1 || port > 65535) {
    
    561
    +              error = "Invalid port: out of bounds";
    
    562
    +              break;
    
    432 563
                 }
    
    564
    +            valid = true;
    
    565
    +            break;
    
    566
    +          }
    
    567
    +          if (tokens[0].endsWith("-ERROR")) {
    
    568
    +            error = "Seen an error: " + line;
    
    569
    +            break;
    
    570
    +          }
    
    433 571
             }
    
    434
    -
    
    435
    -        public String getHandle() {
    
    436
    -            return mHandle;
    
    437
    -        }
    
    572
    +      } catch (Exception e) {
    
    573
    +        error = e.getMessage();
    
    574
    +      }
    
    575
    +      if (valid) {
    
    576
    +        Log.d(TAG, "Setup a meek transport " + mId + ": " + hostname + ":" + port);
    
    577
    +        final GeckoBundle bundle = new GeckoBundle(3);
    
    578
    +        bundle.putInt("id", mId);
    
    579
    +        bundle.putString("address", hostname);
    
    580
    +        bundle.putInt("port", port);
    
    581
    +        mCallback.sendSuccess(bundle);
    
    582
    +      } else {
    
    583
    +        Log.e(TAG, "Failed to get a usable config from the PT: " + error);
    
    584
    +        mCallback.sendError(error);
    
    585
    +        return;
    
    586
    +      }
    
    587
    +      dumpStdout();
    
    438 588
         }
    
    439 589
     
    
    440
    -    private synchronized void startMeek(final GeckoBundle message, final EventCallback callback) {
    
    441
    -        if (callback == null) {
    
    442
    -            Log.e(TAG, "Tried to start Meek without a callback.");
    
    443
    -            return;
    
    444
    -        }
    
    445
    -        mMeekCounter++;
    
    446
    -        mMeeks.put(new Integer(mMeekCounter), new MeekTransport(callback, mMeekCounter));
    
    590
    +    void shutdown() {
    
    591
    +      if (mProcess != null) {
    
    592
    +        Log.i(TAG, "Shutting down meek process " + mId);
    
    593
    +        mProcess.destroy();
    
    594
    +        mProcess = null;
    
    595
    +      } else {
    
    596
    +        Log.w(
    
    597
    +            TAG,
    
    598
    +            "Shutdown request on the meek process " + mId + " that has already been shutdown.");
    
    599
    +      }
    
    600
    +      try {
    
    601
    +        join();
    
    602
    +      } catch (InterruptedException e) {
    
    603
    +        Log.e(TAG, "Could not join the meek thread", e);
    
    604
    +      }
    
    447 605
         }
    
    448 606
     
    
    449
    -    private synchronized void stopMeek(final GeckoBundle message, final EventCallback callback) {
    
    450
    -        final Integer key = message.getInteger("id");
    
    451
    -        final MeekTransport meek = mMeeks.remove(key);
    
    452
    -        if (meek != null) {
    
    453
    -            meek.shutdown();
    
    454
    -        }
    
    455
    -        if (callback != null) {
    
    456
    -            callback.sendSuccess(null);
    
    607
    +    void dumpStdout() {
    
    608
    +      try {
    
    609
    +        BufferedReader reader =
    
    610
    +            new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
    
    611
    +        String line;
    
    612
    +        while ((line = reader.readLine()) != null) {
    
    613
    +          Log.d(TAG, "[meek-" + mId + "] " + line);
    
    457 614
             }
    
    615
    +      } catch (InterruptedIOException e) {
    
    616
    +        // This happens normally, do not log it.
    
    617
    +      } catch (IOException e) {
    
    618
    +        Log.e(TAG, "Failed to read stdout of the meek process process " + mId, e);
    
    619
    +      }
    
    458 620
         }
    
    621
    +  }
    
    459 622
     
    
    460
    -    private class MeekTransport extends Thread {
    
    461
    -        private static final String TRANSPORT = "meek_lite";
    
    462
    -        private Process mProcess;
    
    463
    -        private final EventCallback mCallback;
    
    464
    -        private final int mId;
    
    465
    -
    
    466
    -        MeekTransport(final EventCallback callback, int id) {
    
    467
    -            setName("meek-" + id);
    
    468
    -            final ProcessBuilder builder = new ProcessBuilder(mLibraryDir + "/libObfs4proxy.so");
    
    469
    -            {
    
    470
    -                File ptStateDir = new File(mDataDir, "pt_state");
    
    471
    -                final Map<String, String> env = builder.environment();
    
    472
    -                env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
    
    473
    -                env.put("TOR_PT_STATE_LOCATION", ptStateDir.getAbsolutePath());
    
    474
    -                env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
    
    475
    -                env.put("TOR_PT_CLIENT_TRANSPORTS", TRANSPORT);
    
    476
    -            }
    
    477
    -            mCallback = callback;
    
    478
    -            mId = id;
    
    479
    -            try {
    
    480
    -                // We expect this process to be short-lived, therefore we do not bother with
    
    481
    -                // implementing this as a service.
    
    482
    -                mProcess = builder.start();
    
    483
    -            } catch (IOException e) {
    
    484
    -                Log.e(TAG, "Cannot start the PT", e);
    
    485
    -                callback.sendError(e.getMessage());
    
    486
    -                return;
    
    487
    -            }
    
    488
    -            start();
    
    489
    -        }
    
    623
    +  public interface BootstrapStateChangeListener {
    
    624
    +    void onBootstrapStateChange(String state);
    
    490 625
     
    
    491
    -        /**
    
    492
    -         * Parse the standard output of the pluggable transport to find the hostname and port it is
    
    493
    -         * listening on.
    
    494
    -         * <p>
    
    495
    -         * See also the specs for the IPC protocol at https://spec.torproject.org/pt-spec/ipc.html.
    
    496
    -         */
    
    497
    -        @Override
    
    498
    -        public void run() {
    
    499
    -            final String PROTOCOL_VERSION = "1";
    
    500
    -            String hostname = "";
    
    501
    -            boolean valid = false;
    
    502
    -            int port = 0;
    
    503
    -            String error = "Did not see a CMETHOD";
    
    504
    -            try {
    
    505
    -                InputStreamReader isr = new InputStreamReader(mProcess.getInputStream());
    
    506
    -                BufferedReader reader = new BufferedReader(isr);
    
    507
    -                String line;
    
    508
    -                while ((line = reader.readLine()) != null) {
    
    509
    -                    line = line.trim();
    
    510
    -                    Log.d(TAG, "Meek line: " + line);
    
    511
    -                    // Split produces always at least one item
    
    512
    -                    String[] tokens = line.split(" ");
    
    513
    -                    if ("VERSION".equals(tokens[0]) && (tokens.length != 2 || !PROTOCOL_VERSION.equals(tokens[1]))) {
    
    514
    -                        error = "Bad version: " + line;
    
    515
    -                        break;
    
    516
    -                    }
    
    517
    -                    if ("CMETHOD".equals(tokens[0])) {
    
    518
    -                        if (tokens.length != 4) {
    
    519
    -                            error = "Bad number of tokens in CMETHOD: " + line;
    
    520
    -                            break;
    
    521
    -                        }
    
    522
    -                        if (!tokens[1].equals(TRANSPORT)) {
    
    523
    -                            error = "Unexpected transport: " + tokens[1];
    
    524
    -                            break;
    
    525
    -                        }
    
    526
    -                        if (!"socks5".equals(tokens[2])) {
    
    527
    -                            error = "Unexpected proxy type: " + tokens[2];
    
    528
    -                            break;
    
    529
    -                        }
    
    530
    -                        String[] addr = tokens[3].split(":");
    
    531
    -                        if (addr.length != 2) {
    
    532
    -                            error = "Invalid address";
    
    533
    -                            break;
    
    534
    -                        }
    
    535
    -                        hostname = addr[0];
    
    536
    -                        try {
    
    537
    -                            port = Integer.parseInt(addr[1]);
    
    538
    -                        } catch (NumberFormatException e) {
    
    539
    -                            error = "Invalid port: " + e.getMessage();
    
    540
    -                            break;
    
    541
    -                        }
    
    542
    -                        if (port < 1 || port > 65535) {
    
    543
    -                            error = "Invalid port: out of bounds";
    
    544
    -                            break;
    
    545
    -                        }
    
    546
    -                        valid = true;
    
    547
    -                        break;
    
    548
    -                    }
    
    549
    -                    if (tokens[0].endsWith("-ERROR")) {
    
    550
    -                        error = "Seen an error: " + line;
    
    551
    -                        break;
    
    552
    -                    }
    
    553
    -                }
    
    554
    -            } catch (Exception e) {
    
    555
    -                error = e.getMessage();
    
    556
    -            }
    
    557
    -            if (valid) {
    
    558
    -                Log.d(TAG, "Setup a meek transport " + mId + ": " + hostname + ":" + port);
    
    559
    -                final GeckoBundle bundle = new GeckoBundle(3);
    
    560
    -                bundle.putInt("id", mId);
    
    561
    -                bundle.putString("address", hostname);
    
    562
    -                bundle.putInt("port", port);
    
    563
    -                mCallback.sendSuccess(bundle);
    
    564
    -            } else {
    
    565
    -                Log.e(TAG, "Failed to get a usable config from the PT: " + error);
    
    566
    -                mCallback.sendError(error);
    
    567
    -            }
    
    568
    -        }
    
    626
    +    void onBootstrapProgress(double progress, boolean hasWarnings);
    
    569 627
     
    
    570
    -        void shutdown() {
    
    571
    -            if (mProcess != null) {
    
    572
    -                mProcess.destroy();
    
    573
    -                mProcess = null;
    
    574
    -            }
    
    575
    -            try {
    
    576
    -                join();
    
    577
    -            } catch (InterruptedException e) {
    
    578
    -                Log.e(TAG, "Could not join the meek thread", e);
    
    579
    -            }
    
    580
    -        }
    
    581
    -    }
    
    628
    +    void onBootstrapComplete();
    
    582 629
     
    
    583
    -    public interface BootstrapStateChangeListener {
    
    584
    -        void onBootstrapStateChange(String state);
    
    585
    -        void onBootstrapProgress(double progress, boolean hasWarnings);
    
    586
    -        void onBootstrapComplete();
    
    587
    -        void onBootstrapError(String code, String message, String phase, String reason);
    
    588
    -        void onSettingsRequested();
    
    589
    -    }
    
    630
    +    void onBootstrapError(String code, String message, String phase, String reason);
    
    590 631
     
    
    591
    -    public interface TorLogListener {
    
    592
    -        void onLog(String logType, String message);
    
    593
    -    }
    
    632
    +    void onSettingsRequested();
    
    633
    +  }
    
    594 634
     
    
    595
    -    private @NonNull void reloadSettings() {
    
    596
    -        EventDispatcher.getInstance().queryBundle(EVENT_SETTINGS_GET).then( new GeckoResult.OnValueListener<GeckoBundle, Void>() {
    
    597
    -            public GeckoResult<Void> onValue(final GeckoBundle bundle) {
    
    635
    +  public interface TorLogListener {
    
    636
    +    void onLog(String logType, String message);
    
    637
    +  }
    
    638
    +
    
    639
    +  private @NonNull void reloadSettings() {
    
    640
    +    EventDispatcher.getInstance()
    
    641
    +        .queryBundle(EVENT_SETTINGS_GET)
    
    642
    +        .then(
    
    643
    +            new GeckoResult.OnValueListener<GeckoBundle, Void>() {
    
    644
    +              public GeckoResult<Void> onValue(final GeckoBundle bundle) {
    
    598 645
                     mSettings = new TorSettings(bundle);
    
    599 646
                     return new GeckoResult<Void>();
    
    600
    -            }
    
    601
    -        });
    
    602
    -    }
    
    647
    +              }
    
    648
    +            });
    
    649
    +  }
    
    603 650
     
    
    604
    -    public TorSettings getSettings() {
    
    605
    -        return mSettings;
    
    606
    -    }
    
    651
    +  public TorSettings getSettings() {
    
    652
    +    return mSettings;
    
    653
    +  }
    
    607 654
     
    
    608
    -    public void setSettings(final TorSettings settings, boolean save, boolean apply) {
    
    609
    -        mSettings = settings;
    
    655
    +  public void setSettings(final TorSettings settings, boolean save, boolean apply) {
    
    656
    +    mSettings = settings;
    
    610 657
     
    
    611
    -        emitSetSettings(settings, save, apply).then(
    
    658
    +    emitSetSettings(settings, save, apply)
    
    659
    +        .then(
    
    612 660
                 new GeckoResult.OnValueListener<Void, Void>() {
    
    613
    -                public GeckoResult<Void> onValue(Void v) {
    
    614
    -                    return new GeckoResult<Void>();
    
    615
    -                }
    
    661
    +              public GeckoResult<Void> onValue(Void v) {
    
    662
    +                return new GeckoResult<Void>();
    
    663
    +              }
    
    616 664
                 },
    
    617 665
                 new GeckoResult.OnExceptionListener<Void>() {
    
    618
    -                public GeckoResult<Void> onException(final Throwable e) {
    
    619
    -                    Log.e(TAG, "Failed to set settings", e);
    
    620
    -                    reloadSettings();
    
    621
    -                    return new GeckoResult<Void>();
    
    622
    -                }
    
    666
    +              public GeckoResult<Void> onException(final Throwable e) {
    
    667
    +                Log.e(TAG, "Failed to set settings", e);
    
    668
    +                reloadSettings();
    
    669
    +                return new GeckoResult<Void>();
    
    670
    +              }
    
    623 671
                 });
    
    624
    -    }
    
    625
    -
    
    626
    -    private @NonNull GeckoResult<Void> emitSetSettings(final TorSettings settings, boolean save, boolean apply) {
    
    627
    -        GeckoBundle bundle = new GeckoBundle(3);
    
    628
    -        bundle.putBoolean("save", save);
    
    629
    -        bundle.putBoolean("apply", apply);
    
    630
    -        bundle.putBundle("settings", settings.asGeckoBundle());
    
    631
    -        return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SET, bundle);
    
    632
    -    }
    
    633
    -
    
    634
    -    public @NonNull GeckoResult<Void> applySettings() {
    
    635
    -        return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_APPLY);
    
    636
    -    }
    
    637
    -
    
    638
    -    public @NonNull GeckoResult<Void> saveSettings() {
    
    639
    -        return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SAVE);
    
    640
    -    }
    
    641
    -
    
    642
    -    public @NonNull GeckoResult<Void> beginBootstrap() {
    
    643
    -        return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
    
    644
    -    }
    
    645
    -
    
    646
    -    public @NonNull GeckoResult<Void> beginAutoBootstrap(final String countryCode) {
    
    647
    -        final GeckoBundle bundle = new GeckoBundle(1);
    
    648
    -        bundle.putString("countryCode", countryCode);
    
    649
    -        return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN_AUTO, bundle);
    
    650
    -    }
    
    651
    -
    
    652
    -    public @NonNull GeckoResult<Void> beginAutoBootstrap() {
    
    653
    -        return beginAutoBootstrap(null);
    
    654
    -    }
    
    655
    -
    
    656
    -    public @NonNull GeckoResult<Void> cancelBootstrap() {
    
    657
    -        return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
    
    658
    -    }
    
    659
    -
    
    660
    -    public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    661
    -        mBootstrapStateListeners.add(listener);
    
    662
    -    }
    
    663
    -
    
    664
    -    public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    665
    -        mBootstrapStateListeners.remove(listener);
    
    666
    -    }
    
    667
    -
    
    668
    -    private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
    
    669
    -
    
    670
    -    public void registerLogListener(TorLogListener listener) {
    
    671
    -        mLogListeners.add(listener);
    
    672
    -    }
    
    673
    -
    
    674
    -    public void unregisterLogListener(TorLogListener listener) {
    
    675
    -        mLogListeners.remove(listener);
    
    676
    -    }
    
    677
    -
    
    678
    -    private final HashSet<TorLogListener> mLogListeners = new HashSet<>();
    
    672
    +  }
    
    673
    +
    
    674
    +  private @NonNull GeckoResult<Void> emitSetSettings(
    
    675
    +      final TorSettings settings, boolean save, boolean apply) {
    
    676
    +    GeckoBundle bundle = new GeckoBundle(3);
    
    677
    +    bundle.putBoolean("save", save);
    
    678
    +    bundle.putBoolean("apply", apply);
    
    679
    +    bundle.putBundle("settings", settings.asGeckoBundle());
    
    680
    +    return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SET, bundle);
    
    681
    +  }
    
    682
    +
    
    683
    +  public @NonNull GeckoResult<Void> applySettings() {
    
    684
    +    return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_APPLY);
    
    685
    +  }
    
    686
    +
    
    687
    +  public @NonNull GeckoResult<Void> saveSettings() {
    
    688
    +    return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SAVE);
    
    689
    +  }
    
    690
    +
    
    691
    +  public @NonNull GeckoResult<Void> beginBootstrap() {
    
    692
    +    return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
    
    693
    +  }
    
    694
    +
    
    695
    +  public @NonNull GeckoResult<Void> beginAutoBootstrap(final String countryCode) {
    
    696
    +    final GeckoBundle bundle = new GeckoBundle(1);
    
    697
    +    bundle.putString("countryCode", countryCode);
    
    698
    +    return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN_AUTO, bundle);
    
    699
    +  }
    
    700
    +
    
    701
    +  public @NonNull GeckoResult<Void> beginAutoBootstrap() {
    
    702
    +    return beginAutoBootstrap(null);
    
    703
    +  }
    
    704
    +
    
    705
    +  public @NonNull GeckoResult<Void> cancelBootstrap() {
    
    706
    +    return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
    
    707
    +  }
    
    708
    +
    
    709
    +  public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    710
    +    mBootstrapStateListeners.add(listener);
    
    711
    +  }
    
    712
    +
    
    713
    +  public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    714
    +    mBootstrapStateListeners.remove(listener);
    
    715
    +  }
    
    716
    +
    
    717
    +  private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
    
    718
    +
    
    719
    +  public void registerLogListener(TorLogListener listener) {
    
    720
    +    mLogListeners.add(listener);
    
    721
    +  }
    
    722
    +
    
    723
    +  public void unregisterLogListener(TorLogListener listener) {
    
    724
    +    mLogListeners.remove(listener);
    
    725
    +  }
    
    726
    +
    
    727
    +  private final HashSet<TorLogListener> mLogListeners = new HashSet<>();
    
    679 728
     }

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
    1 1
     package org.mozilla.geckoview;
    
    2 2
     
    
    3 3
     import android.util.Log;
    
    4
    -
    
    5 4
     import org.mozilla.gecko.util.GeckoBundle;
    
    6 5
     
    
    7 6
     public class TorSettings {
    
    8 7
     
    
    9
    -    public enum BridgeSource {
    
    10
    -        Invalid(-1),
    
    11
    -        BuiltIn(0),
    
    12
    -        BridgeDB(1),
    
    13
    -        UserProvided(2);
    
    14
    -
    
    15
    -        private int source;
    
    16
    -
    
    17
    -        BridgeSource(final int source) {
    
    18
    -            this.source = source;
    
    19
    -        }
    
    20
    -
    
    21
    -        public static BridgeSource fromInt(int i) {
    
    22
    -            switch (i) {
    
    23
    -                case -1: return Invalid;
    
    24
    -                case 0: return BuiltIn;
    
    25
    -                case 1: return BridgeDB;
    
    26
    -                case 2: return UserProvided;
    
    27
    -            }
    
    28
    -            return Invalid;
    
    29
    -        }
    
    30
    -
    
    31
    -        public int toInt() {
    
    32
    -            return this.source;
    
    33
    -        }
    
    8
    +  public enum BridgeSource {
    
    9
    +    Invalid(-1),
    
    10
    +    BuiltIn(0),
    
    11
    +    BridgeDB(1),
    
    12
    +    UserProvided(2);
    
    13
    +
    
    14
    +    private int source;
    
    15
    +
    
    16
    +    BridgeSource(final int source) {
    
    17
    +      this.source = source;
    
    34 18
         }
    
    35 19
     
    
    36
    -    public enum ProxyType {
    
    37
    -        Invalid(-1),
    
    38
    -        Socks4(0),
    
    39
    -        Socks5(1),
    
    40
    -        HTTPS(2);
    
    41
    -
    
    42
    -        private int type;
    
    43
    -
    
    44
    -        ProxyType(final int type) {
    
    45
    -            this.type = type;
    
    46
    -        }
    
    47
    -
    
    48
    -        public int toInt() {
    
    49
    -            return type;
    
    50
    -        }
    
    51
    -
    
    52
    -        public static ProxyType fromInt(int i) {
    
    53
    -            switch (i) {
    
    54
    -                case -1: return Invalid;
    
    55
    -                case 0: return Socks4;
    
    56
    -                case 1: return Socks5;
    
    57
    -                case 2: return HTTPS;
    
    58
    -            }
    
    59
    -            return Invalid;
    
    60
    -        }
    
    20
    +    public static BridgeSource fromInt(int i) {
    
    21
    +      switch (i) {
    
    22
    +        case -1:
    
    23
    +          return Invalid;
    
    24
    +        case 0:
    
    25
    +          return BuiltIn;
    
    26
    +        case 1:
    
    27
    +          return BridgeDB;
    
    28
    +        case 2:
    
    29
    +          return UserProvided;
    
    30
    +      }
    
    31
    +      return Invalid;
    
    61 32
         }
    
    62 33
     
    
    63
    -    public enum BridgeBuiltinType {
    
    64
    -        /* TorSettings.sys.mjs ~ln43:  string: obfs4|meek-azure|snowflake|etc */
    
    65
    -        Invalid("invalid"),
    
    66
    -        Obfs4("obfs4"),
    
    67
    -        MeekAzure("meek-azure"),
    
    68
    -        Snowflake("snowflake");
    
    34
    +    public int toInt() {
    
    35
    +      return this.source;
    
    36
    +    }
    
    37
    +  }
    
    69 38
     
    
    39
    +  public enum ProxyType {
    
    40
    +    Invalid(-1),
    
    41
    +    Socks4(0),
    
    42
    +    Socks5(1),
    
    43
    +    HTTPS(2);
    
    70 44
     
    
    71
    -        private String type;
    
    45
    +    private int type;
    
    72 46
     
    
    73
    -        BridgeBuiltinType(String type) {
    
    74
    -            this.type = type;
    
    75
    -        }
    
    47
    +    ProxyType(final int type) {
    
    48
    +      this.type = type;
    
    49
    +    }
    
    76 50
     
    
    77
    -        public String toString() {
    
    78
    -            return type;
    
    79
    -        }
    
    51
    +    public int toInt() {
    
    52
    +      return type;
    
    53
    +    }
    
    80 54
     
    
    81
    -        public static BridgeBuiltinType fromString(String s) {
    
    82
    -            switch (s) {
    
    83
    -                case "obfs4": return Obfs4;
    
    84
    -                case "meek-azure": return MeekAzure;
    
    85
    -                case "snowflake": return Snowflake;
    
    86
    -            }
    
    87
    -            return Invalid;
    
    88
    -        }
    
    55
    +    public static ProxyType fromInt(int i) {
    
    56
    +      switch (i) {
    
    57
    +        case -1:
    
    58
    +          return Invalid;
    
    59
    +        case 0:
    
    60
    +          return Socks4;
    
    61
    +        case 1:
    
    62
    +          return Socks5;
    
    63
    +        case 2:
    
    64
    +          return HTTPS;
    
    65
    +      }
    
    66
    +      return Invalid;
    
    67
    +    }
    
    68
    +  }
    
    69
    +
    
    70
    +  public enum BridgeBuiltinType {
    
    71
    +    /* TorSettings.sys.mjs ~ln43:  string: obfs4|meek-azure|snowflake|etc */
    
    72
    +    Invalid("invalid"),
    
    73
    +    Obfs4("obfs4"),
    
    74
    +    MeekAzure("meek-azure"),
    
    75
    +    Snowflake("snowflake");
    
    76
    +
    
    77
    +    private String type;
    
    89 78
     
    
    79
    +    BridgeBuiltinType(String type) {
    
    80
    +      this.type = type;
    
    90 81
         }
    
    91 82
     
    
    92
    -    private boolean loaded = false;
    
    83
    +    public String toString() {
    
    84
    +      return type;
    
    85
    +    }
    
    93 86
     
    
    94
    -    public boolean enabled = true;
    
    87
    +    public static BridgeBuiltinType fromString(String s) {
    
    88
    +      switch (s) {
    
    89
    +        case "obfs4":
    
    90
    +          return Obfs4;
    
    91
    +        case "meek-azure":
    
    92
    +          return MeekAzure;
    
    93
    +        case "snowflake":
    
    94
    +          return Snowflake;
    
    95
    +      }
    
    96
    +      return Invalid;
    
    97
    +    }
    
    98
    +  }
    
    95 99
     
    
    96
    -    public boolean quickstart = false;
    
    100
    +  private boolean loaded = false;
    
    97 101
     
    
    98
    -    // bridges section
    
    99
    -    public boolean bridgesEnabled = false;
    
    100
    -    public BridgeSource bridgesSource = BridgeSource.Invalid;
    
    101
    -    public BridgeBuiltinType bridgesBuiltinType = BridgeBuiltinType.Invalid;
    
    102
    -    public String[] bridgeBridgeStrings;
    
    102
    +  public boolean enabled = true;
    
    103 103
     
    
    104
    -    // proxy section
    
    105
    -    public boolean proxyEnabled = false;
    
    106
    -    public ProxyType proxyType = ProxyType.Invalid;
    
    107
    -    public String proxyAddress = "";
    
    108
    -    public int proxyPort = 0;
    
    109
    -    public String proxyUsername = "";
    
    110
    -    public String proxyPassword = "";
    
    104
    +  public boolean quickstart = false;
    
    111 105
     
    
    112
    -    // firewall section
    
    113
    -    public boolean firewallEnabled = false;
    
    114
    -    public int[] firewallAllowedPorts;
    
    106
    +  // bridges section
    
    107
    +  public boolean bridgesEnabled = false;
    
    108
    +  public BridgeSource bridgesSource = BridgeSource.Invalid;
    
    109
    +  public BridgeBuiltinType bridgesBuiltinType = BridgeBuiltinType.Invalid;
    
    110
    +  public String[] bridgeBridgeStrings;
    
    115 111
     
    
    116
    -    public TorSettings() {
    
    117
    -    }
    
    112
    +  // proxy section
    
    113
    +  public boolean proxyEnabled = false;
    
    114
    +  public ProxyType proxyType = ProxyType.Invalid;
    
    115
    +  public String proxyAddress = "";
    
    116
    +  public int proxyPort = 0;
    
    117
    +  public String proxyUsername = "";
    
    118
    +  public String proxyPassword = "";
    
    119
    +
    
    120
    +  // firewall section
    
    121
    +  public boolean firewallEnabled = false;
    
    122
    +  public int[] firewallAllowedPorts;
    
    123
    +
    
    124
    +  public TorSettings() {}
    
    125
    +
    
    126
    +  public TorSettings(GeckoBundle bundle) {
    
    127
    +    try {
    
    128
    +      GeckoBundle qs = bundle.getBundle("quickstart");
    
    129
    +      GeckoBundle bridges = bundle.getBundle("bridges");
    
    130
    +      GeckoBundle proxy = bundle.getBundle("proxy");
    
    131
    +      GeckoBundle firewall = bundle.getBundle("firewall");
    
    132
    +
    
    133
    +      bridgesEnabled = bridges.getBoolean("enabled");
    
    134
    +      bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
    
    135
    +      bridgesBuiltinType = BridgeBuiltinType.fromString(bridges.getString("builtin_type"));
    
    136
    +      bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
    
    118 137
     
    
    119
    -    public TorSettings(GeckoBundle bundle) {
    
    120
    -        try {
    
    121
    -            GeckoBundle qs = bundle.getBundle("quickstart");
    
    122
    -            GeckoBundle bridges = bundle.getBundle("bridges");
    
    123
    -            GeckoBundle proxy = bundle.getBundle("proxy");
    
    124
    -            GeckoBundle firewall = bundle.getBundle("firewall");
    
    125
    -
    
    126
    -            bridgesEnabled = bridges.getBoolean("enabled");
    
    127
    -            bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
    
    128
    -            bridgesBuiltinType = BridgeBuiltinType.fromString(bridges.getString("builtin_type"));
    
    129
    -            bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
    
    130
    -
    
    131
    -            quickstart = qs.getBoolean("enabled");
    
    132
    -
    
    133
    -            firewallEnabled = firewall.getBoolean("enabled");
    
    134
    -            firewallAllowedPorts = firewall.getIntArray("allowed_ports");
    
    135
    -
    
    136
    -            proxyEnabled = proxy.getBoolean("enabled");
    
    137
    -            proxyAddress = proxy.getString("address");
    
    138
    -            proxyUsername = proxy.getString("username");
    
    139
    -            proxyPassword = proxy.getString("password");
    
    140
    -            proxyPort = proxy.getInt("port");
    
    141
    -            proxyType = ProxyType.fromInt(proxy.getInt("type"));
    
    142
    -
    
    143
    -            loaded = true;
    
    144
    -        } catch (Exception e) {
    
    145
    -            Log.e("TorSettings", "bundle access error: " + e.toString(), e);
    
    146
    -        }
    
    138
    +      quickstart = qs.getBoolean("enabled");
    
    139
    +
    
    140
    +      firewallEnabled = firewall.getBoolean("enabled");
    
    141
    +      firewallAllowedPorts = firewall.getIntArray("allowed_ports");
    
    142
    +
    
    143
    +      proxyEnabled = proxy.getBoolean("enabled");
    
    144
    +      proxyAddress = proxy.getString("address");
    
    145
    +      proxyUsername = proxy.getString("username");
    
    146
    +      proxyPassword = proxy.getString("password");
    
    147
    +      proxyPort = proxy.getInt("port");
    
    148
    +      proxyType = ProxyType.fromInt(proxy.getInt("type"));
    
    149
    +
    
    150
    +      loaded = true;
    
    151
    +    } catch (Exception e) {
    
    152
    +      Log.e("TorSettings", "bundle access error: " + e.toString(), e);
    
    147 153
         }
    
    154
    +  }
    
    148 155
     
    
    149
    -    public GeckoBundle asGeckoBundle() {
    
    150
    -        GeckoBundle bundle = new GeckoBundle();
    
    156
    +  public GeckoBundle asGeckoBundle() {
    
    157
    +    GeckoBundle bundle = new GeckoBundle();
    
    151 158
     
    
    152
    -        GeckoBundle qs = new GeckoBundle();
    
    153
    -        GeckoBundle bridges = new GeckoBundle();
    
    154
    -        GeckoBundle proxy = new GeckoBundle();
    
    155
    -        GeckoBundle firewall = new GeckoBundle();
    
    159
    +    GeckoBundle qs = new GeckoBundle();
    
    160
    +    GeckoBundle bridges = new GeckoBundle();
    
    161
    +    GeckoBundle proxy = new GeckoBundle();
    
    162
    +    GeckoBundle firewall = new GeckoBundle();
    
    156 163
     
    
    157
    -        bridges.putBoolean("enabled", bridgesEnabled);
    
    158
    -        bridges.putInt("source", bridgesSource.toInt());
    
    159
    -        bridges.putString("builtin_type", bridgesBuiltinType.toString());
    
    160
    -        bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
    
    164
    +    bridges.putBoolean("enabled", bridgesEnabled);
    
    165
    +    bridges.putInt("source", bridgesSource.toInt());
    
    166
    +    bridges.putString("builtin_type", bridgesBuiltinType.toString());
    
    167
    +    bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
    
    161 168
     
    
    162
    -        qs.putBoolean("enabled", quickstart);
    
    169
    +    qs.putBoolean("enabled", quickstart);
    
    163 170
     
    
    164
    -        firewall.putBoolean("enabled", firewallEnabled);
    
    165
    -        firewall.putIntArray("allowed_ports", firewallAllowedPorts);
    
    171
    +    firewall.putBoolean("enabled", firewallEnabled);
    
    172
    +    firewall.putIntArray("allowed_ports", firewallAllowedPorts);
    
    166 173
     
    
    167
    -        proxy.putBoolean("enabled", proxyEnabled);
    
    168
    -        proxy.putString("address", proxyAddress);
    
    169
    -        proxy.putString("username", proxyUsername);
    
    170
    -        proxy.putString("password", proxyPassword);
    
    171
    -        proxy.putInt("port", proxyPort);
    
    172
    -        proxy.putInt("type", proxyType.toInt());
    
    174
    +    proxy.putBoolean("enabled", proxyEnabled);
    
    175
    +    proxy.putString("address", proxyAddress);
    
    176
    +    proxy.putString("username", proxyUsername);
    
    177
    +    proxy.putString("password", proxyPassword);
    
    178
    +    proxy.putInt("port", proxyPort);
    
    179
    +    proxy.putInt("type", proxyType.toInt());
    
    173 180
     
    
    174
    -        bundle.putBundle("quickstart", qs);
    
    175
    -        bundle.putBundle("bridges", bridges);
    
    176
    -        bundle.putBundle("proxy", proxy);
    
    177
    -        bundle.putBundle("firewall", firewall);
    
    181
    +    bundle.putBundle("quickstart", qs);
    
    182
    +    bundle.putBundle("bridges", bridges);
    
    183
    +    bundle.putBundle("proxy", proxy);
    
    184
    +    bundle.putBundle("firewall", firewall);
    
    178 185
     
    
    179
    -        return bundle;
    
    180
    -    }
    
    186
    +    return bundle;
    
    187
    +  }
    
    181 188
     
    
    182
    -    public boolean isLoaded() {
    
    183
    -        return this.loaded;
    
    184
    -    }
    
    189
    +  public boolean isLoaded() {
    
    190
    +    return this.loaded;
    
    191
    +  }
    
    185 192
     }

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
    ... ... @@ -49,9 +49,7 @@ public class WebRequest extends WebMessage {
    49 49
       /** The value of the Referer header for this request. */
    
    50 50
       public final @Nullable String referrer;
    
    51 51
     
    
    52
    -  /**
    
    53
    -   * The value of the origin of this request.
    
    54
    -   */
    
    52
    +  /** The value of the origin of this request. */
    
    55 53
       public final @Nullable String origin;
    
    56 54
     
    
    57 55
       @Retention(RetentionPolicy.SOURCE)
    
    ... ... @@ -248,10 +246,10 @@ public class WebRequest extends WebMessage {
    248 246
          * @param origin A URI String
    
    249 247
          * @return This Builder instance.
    
    250 248
          */
    
    251
    -     public @NonNull Builder origin(final @Nullable String origin) {
    
    252
    -       mOrigin = origin;
    
    253
    -       return this;
    
    254
    -     }
    
    249
    +    public @NonNull Builder origin(final @Nullable String origin) {
    
    250
    +      mOrigin = origin;
    
    251
    +      return this;
    
    252
    +    }
    
    255 253
     
    
    256 254
         /**
    
    257 255
          * @return A {@link WebRequest} constructed with the values from this Builder instance.
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/Prefs.java
    ... ... @@ -2,71 +2,68 @@ package org.mozilla.geckoview.androidlegacysettings;
    2 2
     
    
    3 3
     import android.content.Context;
    
    4 4
     import android.content.SharedPreferences;
    
    5
    -import org.mozilla.gecko.GeckoAppShell;
    
    6
    -
    
    7 5
     import java.util.Locale;
    
    6
    +import org.mozilla.gecko.GeckoAppShell;
    
    8 7
     
    
    9 8
     // tor-android-service utils/Prefs.java
    
    10 9
     
    
    11 10
     /* package */ class Prefs {
    
    12
    -    private final static String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
    
    13
    -    private final static String PREF_BRIDGES_LIST = "pref_bridges_list";
    
    11
    +  private static final String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
    
    12
    +  private static final String PREF_BRIDGES_LIST = "pref_bridges_list";
    
    14 13
     
    
    15
    -    private static SharedPreferences prefs;
    
    14
    +  private static SharedPreferences prefs;
    
    16 15
     
    
    17
    -    // OrbotConstants
    
    18
    -    private final static String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences";
    
    16
    +  // OrbotConstants
    
    17
    +  private static final String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences";
    
    19 18
     
    
    19
    +  // tor-android-service utils/TorServiceUtil.java
    
    20 20
     
    
    21
    -    // tor-android-service utils/TorServiceUtil.java
    
    22
    -
    
    23
    -    private static void setContext() {
    
    24
    -        if (prefs == null) {
    
    25
    -            prefs = GeckoAppShell.getApplicationContext().getSharedPreferences(PREF_TOR_SHARED_PREFS,
    
    26
    -                    Context.MODE_MULTI_PROCESS);
    
    27
    -        }
    
    21
    +  private static void setContext() {
    
    22
    +    if (prefs == null) {
    
    23
    +      prefs =
    
    24
    +          GeckoAppShell.getApplicationContext()
    
    25
    +              .getSharedPreferences(PREF_TOR_SHARED_PREFS, Context.MODE_MULTI_PROCESS);
    
    28 26
         }
    
    29
    -
    
    30
    -    public static boolean getBoolean(String key, boolean def) {
    
    31
    -        setContext();
    
    32
    -        return prefs.getBoolean(key, def);
    
    33
    -    }
    
    34
    -
    
    35
    -    public static void putBoolean(String key, boolean value) {
    
    36
    -        setContext();
    
    37
    -        prefs.edit().putBoolean(key, value).apply();
    
    38
    -    }
    
    39
    -
    
    40
    -    public static void putString(String key, String value) {
    
    41
    -        setContext();
    
    42
    -        prefs.edit().putString(key, value).apply();
    
    27
    +  }
    
    28
    +
    
    29
    +  public static boolean getBoolean(String key, boolean def) {
    
    30
    +    setContext();
    
    31
    +    return prefs.getBoolean(key, def);
    
    32
    +  }
    
    33
    +
    
    34
    +  public static void putBoolean(String key, boolean value) {
    
    35
    +    setContext();
    
    36
    +    prefs.edit().putBoolean(key, value).apply();
    
    37
    +  }
    
    38
    +
    
    39
    +  public static void putString(String key, String value) {
    
    40
    +    setContext();
    
    41
    +    prefs.edit().putString(key, value).apply();
    
    42
    +  }
    
    43
    +
    
    44
    +  public static String getString(String key, String def) {
    
    45
    +    setContext();
    
    46
    +    return prefs.getString(key, def);
    
    47
    +  }
    
    48
    +
    
    49
    +  public static boolean bridgesEnabled() {
    
    50
    +    setContext();
    
    51
    +    // for Locale.getDefault().getLanguage().equals("fa"), bridges were enabled by default (and
    
    52
    +    // it was meek). This was a default set in 2019 code, but it is not a good default anymore,
    
    53
    +    // so we removed the check.
    
    54
    +    return prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
    
    55
    +  }
    
    56
    +
    
    57
    +  public static String getBridgesList() {
    
    58
    +    setContext();
    
    59
    +    String list = prefs.getString(PREF_BRIDGES_LIST, "");
    
    60
    +    // list might be empty if the default PT was used, so check also if bridges are enabled.
    
    61
    +    if (list.isEmpty() && prefs.getBoolean(PREF_BRIDGES_ENABLED, false)) {
    
    62
    +      // Even though the check on the fa locale is not good to enable bridges by default, we
    
    63
    +      // still check it here, because if the list was empty, it was likely that it was the
    
    64
    +      // choice for users with this locale.
    
    65
    +      return (Locale.getDefault().getLanguage().equals("fa")) ? "meek" : "obfs4";
    
    43 66
         }
    
    44
    -
    
    45
    -    public static String getString(String key, String def) {
    
    46
    -        setContext();
    
    47
    -        return prefs.getString(key, def);
    
    48
    -    }
    
    49
    -
    
    50
    -    public static boolean bridgesEnabled() {
    
    51
    -        setContext();
    
    52
    -        // for Locale.getDefault().getLanguage().equals("fa"), bridges were enabled by default (and
    
    53
    -        // it was meek). This was a default set in 2019 code, but it is not a good default anymore,
    
    54
    -        // so we removed the check.
    
    55
    -        return prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
    
    56
    -    }
    
    57
    -
    
    58
    -    public static String getBridgesList() {
    
    59
    -        setContext();
    
    60
    -        String list = prefs.getString(PREF_BRIDGES_LIST, "");
    
    61
    -        // list might be empty if the default PT was used, so check also if bridges are enabled.
    
    62
    -        if (list.isEmpty() && prefs.getBoolean(PREF_BRIDGES_ENABLED, false)) {
    
    63
    -            // Even though the check on the fa locale is not good to enable bridges by default, we
    
    64
    -            // still check it here, because if the list was empty, it was likely that it was the
    
    65
    -            // choice for users with this locale.
    
    66
    -            return (Locale.getDefault().getLanguage().equals("fa")) ? "meek": "obfs4";
    
    67
    -        }
    
    68
    -        return list;
    
    69
    -    }
    
    70
    -
    
    71
    -
    
    67
    +    return list;
    
    68
    +  }
    
    72 69
     }

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
    ... ... @@ -4,70 +4,71 @@ import org.mozilla.geckoview.TorSettings;
    4 4
     
    
    5 5
     public class TorLegacyAndroidSettings {
    
    6 6
     
    
    7
    -    private static String PREF_USE_MOZ_PREFS = "tor_use_moz_prefs";
    
    7
    +  private static String PREF_USE_MOZ_PREFS = "tor_use_moz_prefs";
    
    8 8
     
    
    9
    -    public static boolean unmigrated() {
    
    10
    -        return !Prefs.getBoolean(PREF_USE_MOZ_PREFS, false);
    
    11
    -    }
    
    9
    +  public static boolean unmigrated() {
    
    10
    +    return !Prefs.getBoolean(PREF_USE_MOZ_PREFS, false);
    
    11
    +  }
    
    12 12
     
    
    13
    -    public static void setUnmigrated() {
    
    14
    -        Prefs.putBoolean(PREF_USE_MOZ_PREFS, false);
    
    15
    -    }
    
    13
    +  public static void setUnmigrated() {
    
    14
    +    Prefs.putBoolean(PREF_USE_MOZ_PREFS, false);
    
    15
    +  }
    
    16 16
     
    
    17
    -    public static void setMigrated() {
    
    18
    -        Prefs.putBoolean(PREF_USE_MOZ_PREFS, true);
    
    19
    -    }
    
    17
    +  public static void setMigrated() {
    
    18
    +    Prefs.putBoolean(PREF_USE_MOZ_PREFS, true);
    
    19
    +  }
    
    20 20
     
    
    21
    -    public static TorSettings loadTorSettings() {
    
    22
    -        TorSettings settings = new TorSettings();
    
    21
    +  public static TorSettings loadTorSettings() {
    
    22
    +    TorSettings settings = new TorSettings();
    
    23 23
     
    
    24
    -        // always true, tor is enabled in TB
    
    25
    -        settings.enabled = true;
    
    24
    +    // always true, tor is enabled in TB
    
    25
    +    settings.enabled = true;
    
    26 26
     
    
    27
    -        // firefox-android disconnected quick start a while ago so it's untracked
    
    28
    -        settings.quickstart = false;
    
    27
    +    // firefox-android disconnected quick start a while ago so it's untracked
    
    28
    +    settings.quickstart = false;
    
    29 29
     
    
    30
    -        settings.bridgesEnabled = Prefs.bridgesEnabled();
    
    30
    +    settings.bridgesEnabled = Prefs.bridgesEnabled();
    
    31 31
     
    
    32
    -        // tor-android-service CustomTorInstaller.java
    
    33
    -/*
    
    34
    -        BridgesList is an overloaded field, which can cause some confusion.
    
    35
    -        The list can be:
    
    36
    -          1) a filter like obfs4, meek, or snowflake OR
    
    37
    -          2) it can be a custom bridge
    
    38
    -        For (1), we just pass back all bridges, the filter will occur
    
    39
    -          elsewhere in the library.
    
    40
    -        For (2) we return the bridge list as a raw stream.
    
    41
    -        If length is greater than 9, then we know this is a custom bridge
    
    42
    -     */
    
    43
    -        String userDefinedBridgeList = Prefs.getBridgesList();
    
    44
    -        boolean userDefinedBridge = userDefinedBridgeList.length() > 9;
    
    45
    -        // Terrible hack. Must keep in sync with topl::addBridgesFromResources.
    
    46
    -        if (!userDefinedBridge) {
    
    47
    -            settings.bridgesSource = TorSettings.BridgeSource.BuiltIn;
    
    48
    -            switch (userDefinedBridgeList) {
    
    49
    -                case "obfs4":
    
    50
    -                case "snowflake":
    
    51
    -                    settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.fromString(userDefinedBridgeList);
    
    52
    -                    break;
    
    53
    -                case "meek":
    
    54
    -                    settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.MeekAzure;
    
    55
    -                    break;
    
    56
    -                default:
    
    57
    -                    settings.bridgesSource = TorSettings.BridgeSource.Invalid;
    
    58
    -                    break;
    
    59
    -            }
    
    60
    -        } else {
    
    61
    -            settings.bridgesSource = TorSettings.BridgeSource.UserProvided; // user provided
    
    62
    -            settings.bridgeBridgeStrings = userDefinedBridgeList.split("\r\n");
    
    63
    -        }
    
    32
    +    // tor-android-service CustomTorInstaller.java
    
    33
    +    /*
    
    34
    +       BridgesList is an overloaded field, which can cause some confusion.
    
    35
    +       The list can be:
    
    36
    +         1) a filter like obfs4, meek, or snowflake OR
    
    37
    +         2) it can be a custom bridge
    
    38
    +       For (1), we just pass back all bridges, the filter will occur
    
    39
    +         elsewhere in the library.
    
    40
    +       For (2) we return the bridge list as a raw stream.
    
    41
    +       If length is greater than 9, then we know this is a custom bridge
    
    42
    +    */
    
    43
    +    String userDefinedBridgeList = Prefs.getBridgesList();
    
    44
    +    boolean userDefinedBridge = userDefinedBridgeList.length() > 9;
    
    45
    +    // Terrible hack. Must keep in sync with topl::addBridgesFromResources.
    
    46
    +    if (!userDefinedBridge) {
    
    47
    +      settings.bridgesSource = TorSettings.BridgeSource.BuiltIn;
    
    48
    +      switch (userDefinedBridgeList) {
    
    49
    +        case "obfs4":
    
    50
    +        case "snowflake":
    
    51
    +          settings.bridgesBuiltinType =
    
    52
    +              TorSettings.BridgeBuiltinType.fromString(userDefinedBridgeList);
    
    53
    +          break;
    
    54
    +        case "meek":
    
    55
    +          settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.MeekAzure;
    
    56
    +          break;
    
    57
    +        default:
    
    58
    +          settings.bridgesSource = TorSettings.BridgeSource.Invalid;
    
    59
    +          break;
    
    60
    +      }
    
    61
    +    } else {
    
    62
    +      settings.bridgesSource = TorSettings.BridgeSource.UserProvided; // user provided
    
    63
    +      settings.bridgeBridgeStrings = userDefinedBridgeList.split("\r\n");
    
    64
    +    }
    
    64 65
     
    
    65
    -        // Tor Browser Android doesn't take proxy and firewall settings
    
    66
    -        settings.proxyEnabled = false;
    
    66
    +    // Tor Browser Android doesn't take proxy and firewall settings
    
    67
    +    settings.proxyEnabled = false;
    
    67 68
     
    
    68
    -        settings.firewallEnabled = false;
    
    69
    -        settings.firewallAllowedPorts = new int[0];
    
    69
    +    settings.firewallEnabled = false;
    
    70
    +    settings.firewallAllowedPorts = new int[0];
    
    70 71
     
    
    71
    -        return settings;
    
    72
    -    }
    
    72
    +    return settings;
    
    73
    +  }
    
    73 74
     }

  • toolkit/modules/DomainFrontedRequests.sys.mjs
    ... ... @@ -444,7 +444,7 @@ export class DomainFrontRequestBuilder {
    444 444
     
    
    445 445
       async init(reflector, front) {
    
    446 446
         if (this.#inited) {
    
    447
    -      throw new Error("MoatRPC: Already initialized");
    
    447
    +      throw new Error("DomainFrontRequestBuilder: Already initialized");
    
    448 448
         }
    
    449 449
     
    
    450 450
         const meekTransport =
    
    ... ... @@ -464,7 +464,7 @@ export class DomainFrontRequestBuilder {
    464 464
     
    
    465 465
       buildHttpHandler(uriString) {
    
    466 466
         if (!this.#inited) {
    
    467
    -      throw new Error("MoatRPC: Not initialized");
    
    467
    +      throw new Error("DomainFrontRequestBuilder: Not initialized");
    
    468 468
         }
    
    469 469
     
    
    470 470
         const { proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword } =
    

  • toolkit/modules/Moat.sys.mjs
    ... ... @@ -119,7 +119,7 @@ export class MoatRPC {
    119 119
         ch.requestMethod = "HEAD";
    
    120 120
     
    
    121 121
         const listener = new InternetTestResponseListener();
    
    122
    -    await ch.asyncOpen(listener, ch);
    
    122
    +    ch.asyncOpen(listener, ch);
    
    123 123
         return listener.status;
    
    124 124
       }
    
    125 125