Pier Angelo Vendrame pushed to branch tor-browser-115.6.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
1edf6cd0
by Pier Angelo Vendrame at 2023-12-20T17:50:17+00:00
-
e9cc4840
by Dan Ballard at 2023-12-20T17:50:17+00:00
6 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
- + mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
- + mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/Prefs.java
- + mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
- toolkit/modules/TorAndroidIntegration.sys.mjs
Changes:
... | ... | @@ -1008,6 +1008,14 @@ public final class GeckoRuntime implements Parcelable { |
1008 | 1008 | return mPushController;
|
1009 | 1009 | }
|
1010 | 1010 | |
1011 | + /**
|
|
1012 | + * Get the Tor integration controller for this runtime.
|
|
1013 | + */
|
|
1014 | + @UiThread
|
|
1015 | + public @NonNull TorIntegrationAndroid getTorIntegrationController() {
|
|
1016 | + return mTorIntegration;
|
|
1017 | + }
|
|
1018 | + |
|
1011 | 1019 | /**
|
1012 | 1020 | * Appends notes to crash report.
|
1013 | 1021 | *
|
... | ... | @@ -9,6 +9,10 @@ package org.mozilla.geckoview; |
9 | 9 | import android.content.Context;
|
10 | 10 | import android.util.Log;
|
11 | 11 | |
12 | +import androidx.annotation.AnyThread;
|
|
13 | +import androidx.annotation.NonNull;
|
|
14 | +import androidx.annotation.Nullable;
|
|
15 | + |
|
12 | 16 | import java.io.BufferedReader;
|
13 | 17 | import java.io.File;
|
14 | 18 | import java.io.IOException;
|
... | ... | @@ -22,9 +26,9 @@ import java.nio.file.attribute.PosixFilePermission; |
22 | 26 | import java.nio.file.attribute.PosixFilePermissions;
|
23 | 27 | import java.util.ArrayList;
|
24 | 28 | import java.util.HashMap;
|
29 | +import java.util.HashSet;
|
|
25 | 30 | import java.util.Map;
|
26 | 31 | import java.util.Set;
|
27 | -import java.util.UUID;
|
|
28 | 32 | |
29 | 33 | import org.mozilla.gecko.EventDispatcher;
|
30 | 34 | import org.mozilla.gecko.GeckoAppShell;
|
... | ... | @@ -32,13 +36,27 @@ import org.mozilla.gecko.util.BundleEventListener; |
32 | 36 | import org.mozilla.gecko.util.EventCallback;
|
33 | 37 | import org.mozilla.gecko.util.GeckoBundle;
|
34 | 38 | |
35 | -/* package */ class TorIntegrationAndroid implements BundleEventListener {
|
|
39 | +import org.mozilla.geckoview.androidlegacysettings.TorLegacyAndroidSettings;
|
|
40 | + |
|
41 | +public class TorIntegrationAndroid implements BundleEventListener {
|
|
36 | 42 | private static final String TAG = "TorIntegrationAndroid";
|
37 | 43 | |
38 | - private static final String TOR_EVENT_START = "GeckoView:Tor:StartTor";
|
|
39 | - private static final String TOR_EVENT_STOP = "GeckoView:Tor:StopTor";
|
|
40 | - private static final String MEEK_EVENT_START = "GeckoView:Tor:StartMeek";
|
|
41 | - private static final String MEEK_EVENT_STOP = "GeckoView:Tor:StopMeek";
|
|
44 | + // Events we listen to
|
|
45 | + private static final String EVENT_TOR_START = "GeckoView:Tor:StartTor";
|
|
46 | + private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
|
|
47 | + private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
|
|
48 | + private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
|
|
49 | + |
|
50 | + // Events we emit
|
|
51 | + private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
|
|
52 | + private static final String EVENT_SETTINGS_SET = "GeckoView:Tor:SettingsSet";
|
|
53 | + private static final String EVENT_SETTINGS_APPLY = "GeckoView:Tor:SettingsApply";
|
|
54 | + private static final String EVENT_SETTINGS_SAVE = "GeckoView:Tor:SettingsSave";
|
|
55 | + private static final String EVENT_BOOTSTRAP_BEGIN = "GeckoView:Tor:BootstrapBegin";
|
|
56 | + private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
|
|
57 | + private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
|
|
58 | + private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
|
|
59 | + private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
|
|
42 | 60 | |
43 | 61 | private static final String CONTROL_PORT_FILE = "/control-ipc";
|
44 | 62 | private static final String SOCKS_FILE = "/socks-ipc";
|
... | ... | @@ -63,7 +81,9 @@ import org.mozilla.gecko.util.GeckoBundle; |
63 | 81 | private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
|
64 | 82 | private int mMeekCounter;
|
65 | 83 | |
66 | - public TorIntegrationAndroid(Context context) {
|
|
84 | + private TorSettings mSettings = null;
|
|
85 | + |
|
86 | + /* package */ TorIntegrationAndroid(Context context) {
|
|
67 | 87 | mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
|
68 | 88 | mCacheDir = context.getCacheDir().toPath();
|
69 | 89 | mIpcDirectory = mCacheDir + "/tor-private";
|
... | ... | @@ -71,7 +91,7 @@ import org.mozilla.gecko.util.GeckoBundle; |
71 | 91 | registerListener();
|
72 | 92 | }
|
73 | 93 | |
74 | - public synchronized void shutdown() {
|
|
94 | + /* package */ synchronized void shutdown() {
|
|
75 | 95 | // FIXME: It seems this never gets called
|
76 | 96 | if (mTorProcess != null) {
|
77 | 97 | mTorProcess.shutdown();
|
... | ... | @@ -83,22 +103,36 @@ import org.mozilla.gecko.util.GeckoBundle; |
83 | 103 | EventDispatcher.getInstance()
|
84 | 104 | .registerUiThreadListener(
|
85 | 105 | this,
|
86 | - TOR_EVENT_START,
|
|
87 | - MEEK_EVENT_START,
|
|
88 | - MEEK_EVENT_STOP);
|
|
106 | + EVENT_TOR_START,
|
|
107 | + EVENT_MEEK_START,
|
|
108 | + EVENT_MEEK_STOP,
|
|
109 | + EVENT_SETTINGS_READY);
|
|
89 | 110 | }
|
90 | 111 | |
91 | 112 | @Override // BundleEventListener
|
92 | 113 | public synchronized void handleMessage(
|
93 | 114 | final String event, final GeckoBundle message, final EventCallback callback) {
|
94 | - if (TOR_EVENT_START.equals(event)) {
|
|
115 | + if (EVENT_TOR_START.equals(event)) {
|
|
95 | 116 | startDaemon(message, callback);
|
96 | - } else if (TOR_EVENT_STOP.equals(event)) {
|
|
117 | + } else if (EVENT_TOR_STOP.equals(event)) {
|
|
97 | 118 | stopDaemon(message, callback);
|
98 | - } else if (MEEK_EVENT_START.equals(event)) {
|
|
119 | + } else if (EVENT_MEEK_START.equals(event)) {
|
|
99 | 120 | startMeek(message, callback);
|
100 | - } else if (MEEK_EVENT_STOP.equals(event)) {
|
|
121 | + } else if (EVENT_MEEK_STOP.equals(event)) {
|
|
101 | 122 | stopMeek(message, callback);
|
123 | + } else if (EVENT_SETTINGS_READY.equals(event)) {
|
|
124 | + loadSettings(message);
|
|
125 | + }
|
|
126 | + }
|
|
127 | + |
|
128 | + private void loadSettings(GeckoBundle message) {
|
|
129 | + if (TorLegacyAndroidSettings.unmigrated()) {
|
|
130 | + mSettings = TorLegacyAndroidSettings.loadTorSettings();
|
|
131 | + setSettings(mSettings);
|
|
132 | + TorLegacyAndroidSettings.setMigrated();
|
|
133 | + } else {
|
|
134 | + GeckoBundle bundle = message.getBundle("settings");
|
|
135 | + mSettings = new TorSettings(bundle);
|
|
102 | 136 | }
|
103 | 137 | }
|
104 | 138 | |
... | ... | @@ -145,9 +179,9 @@ import org.mozilla.gecko.util.GeckoBundle; |
145 | 179 | }
|
146 | 180 | |
147 | 181 | class TorProcess extends Thread {
|
148 | - private static final String TOR_EVENT_STARTED = "GeckoView:Tor:TorStarted";
|
|
149 | - private static final String TOR_EVENT_START_FAILED = "GeckoView:Tor:TorStartFailed";
|
|
150 | - private static final String TOR_EVENT_EXITED = "GeckoView:Tor:TorExited";
|
|
182 | + private static final String EVENT_TOR_STARTED = "GeckoView:Tor:TorStarted";
|
|
183 | + private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
|
|
184 | + private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
|
|
151 | 185 | private final String mHandle;
|
152 | 186 | private Process mProcess = null;
|
153 | 187 | |
... | ... | @@ -202,14 +236,14 @@ import org.mozilla.gecko.util.GeckoBundle; |
202 | 236 | final GeckoBundle data = new GeckoBundle(2);
|
203 | 237 | data.putString("handle", mHandle);
|
204 | 238 | data.putString("error", e.getMessage());
|
205 | - EventDispatcher.getInstance().dispatch(TOR_EVENT_START_FAILED, data);
|
|
239 | + EventDispatcher.getInstance().dispatch(EVENT_TOR_START_FAILED, data);
|
|
206 | 240 | return;
|
207 | 241 | }
|
208 | 242 | Log.i(TAG, "Tor process " + mHandle + " started.");
|
209 | 243 | {
|
210 | 244 | final GeckoBundle data = new GeckoBundle(1);
|
211 | 245 | data.putString("handle", mHandle);
|
212 | - EventDispatcher.getInstance().dispatch(TOR_EVENT_STARTED, data);
|
|
246 | + EventDispatcher.getInstance().dispatch(EVENT_TOR_STARTED, data);
|
|
213 | 247 | }
|
214 | 248 | try {
|
215 | 249 | BufferedReader reader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
|
... | ... | @@ -232,7 +266,7 @@ import org.mozilla.gecko.util.GeckoBundle; |
232 | 266 | // FIXME: We usually don't reach this when the application is killed!
|
233 | 267 | // So, we don't do our cleanup.
|
234 | 268 | Log.i(TAG, "Tor process " + mHandle + " has exited.");
|
235 | - EventDispatcher.getInstance().dispatch(TOR_EVENT_EXITED, data);
|
|
269 | + EventDispatcher.getInstance().dispatch(EVENT_TOR_EXITED, data);
|
|
236 | 270 | }
|
237 | 271 | |
238 | 272 | private void cleanIpcDirectory() {
|
... | ... | @@ -432,4 +466,71 @@ import org.mozilla.gecko.util.GeckoBundle; |
432 | 466 | }
|
433 | 467 | }
|
434 | 468 | }
|
469 | + |
|
470 | + public static class BootstrapState {
|
|
471 | + // FIXME: We can do better than this :)
|
|
472 | + public GeckoBundle mBundle;
|
|
473 | + |
|
474 | + BootstrapState(GeckoBundle bundle) {
|
|
475 | + mBundle = bundle;
|
|
476 | + }
|
|
477 | + }
|
|
478 | + |
|
479 | + public interface BootstrapStateChangeListener {
|
|
480 | + void onBootstrapStateChange(BootstrapState state);
|
|
481 | + }
|
|
482 | + |
|
483 | + public @NonNull GeckoResult<GeckoBundle> getSettings() {
|
|
484 | + return EventDispatcher.getInstance().queryBundle(EVENT_SETTINGS_GET);
|
|
485 | + }
|
|
486 | + |
|
487 | + public @NonNull GeckoResult<Void> setSettings(final TorSettings settings) {
|
|
488 | + return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SET, settings.asGeckoBundle());
|
|
489 | + }
|
|
490 | + |
|
491 | + public @NonNull GeckoResult<Void> applySettings() {
|
|
492 | + return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_APPLY);
|
|
493 | + }
|
|
494 | + |
|
495 | + public @NonNull GeckoResult<Void> saveSettings() {
|
|
496 | + return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SAVE);
|
|
497 | + }
|
|
498 | + |
|
499 | + public @NonNull GeckoResult<Void> beginBootstrap() {
|
|
500 | + return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
|
|
501 | + }
|
|
502 | + |
|
503 | + public @NonNull GeckoResult<Void> beginAutoBootstrap(final String countryCode) {
|
|
504 | + final GeckoBundle bundle = new GeckoBundle(1);
|
|
505 | + bundle.putString("countryCode", countryCode);
|
|
506 | + return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN_AUTO, bundle);
|
|
507 | + }
|
|
508 | + |
|
509 | + public @NonNull GeckoResult<Void> beginAutoBootstrap() {
|
|
510 | + return beginAutoBootstrap(null);
|
|
511 | + }
|
|
512 | + |
|
513 | + public @NonNull GeckoResult<Void> cancelBootstrap() {
|
|
514 | + return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
|
|
515 | + }
|
|
516 | + |
|
517 | + public @NonNull GeckoResult<BootstrapState> getBootstrapState() {
|
|
518 | + return EventDispatcher.getInstance().queryBundle(EVENT_BOOTSTRAP_GET_STATE).map(new GeckoResult.OnValueMapper<>() {
|
|
519 | + @AnyThread
|
|
520 | + @Nullable
|
|
521 | + public BootstrapState onValue(@Nullable GeckoBundle value) throws Throwable {
|
|
522 | + return new BootstrapState(value);
|
|
523 | + }
|
|
524 | + });
|
|
525 | + }
|
|
526 | + |
|
527 | + public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
|
|
528 | + mBootstrapStateListeners.add(listener);
|
|
529 | + }
|
|
530 | + |
|
531 | + public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
|
|
532 | + mBootstrapStateListeners.remove(listener);
|
|
533 | + }
|
|
534 | + |
|
535 | + private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
|
|
435 | 536 | } |
1 | +package org.mozilla.geckoview;
|
|
2 | + |
|
3 | +import android.util.Log;
|
|
4 | + |
|
5 | +import org.json.JSONArray;
|
|
6 | +import org.json.JSONObject;
|
|
7 | +import org.mozilla.gecko.util.GeckoBundle;
|
|
8 | + |
|
9 | +import java.io.ByteArrayInputStream;
|
|
10 | +import java.io.File;
|
|
11 | +import java.io.FileOutputStream;
|
|
12 | +import java.io.IOException;
|
|
13 | +import java.io.InputStream;
|
|
14 | +import java.io.PrintStream;
|
|
15 | +import java.io.SequenceInputStream;
|
|
16 | +import java.io.UnsupportedEncodingException;
|
|
17 | +import java.util.ArrayList;
|
|
18 | +import java.util.Arrays;
|
|
19 | +import java.util.List;
|
|
20 | +import java.util.Locale;
|
|
21 | +import java.util.stream.Collectors;
|
|
22 | + |
|
23 | +public class TorSettings {
|
|
24 | + |
|
25 | + public enum BridgeSource {
|
|
26 | + Invalid(-1),
|
|
27 | + BuiltIn(0),
|
|
28 | + BridgeDB(1),
|
|
29 | + UserProvided(2);
|
|
30 | + |
|
31 | + private int source;
|
|
32 | + |
|
33 | + BridgeSource(final int source) {
|
|
34 | + this.source = source;
|
|
35 | + }
|
|
36 | + |
|
37 | + public static BridgeSource fromInt(int i) {
|
|
38 | + switch (i) {
|
|
39 | + case -1: return Invalid;
|
|
40 | + case 0: return BuiltIn;
|
|
41 | + case 1: return BridgeDB;
|
|
42 | + case 2: return UserProvided;
|
|
43 | + }
|
|
44 | + return Invalid;
|
|
45 | + }
|
|
46 | + |
|
47 | + public int toInt() {
|
|
48 | + return this.source;
|
|
49 | + }
|
|
50 | + }
|
|
51 | + |
|
52 | + public enum ProxyType {
|
|
53 | + Invalid(-1),
|
|
54 | + Socks4(0),
|
|
55 | + Socks5(1),
|
|
56 | + HTTPS(2);
|
|
57 | + |
|
58 | + private int type;
|
|
59 | + |
|
60 | + ProxyType(final int type) {
|
|
61 | + this.type = type;
|
|
62 | + }
|
|
63 | + |
|
64 | + public int toInt() {
|
|
65 | + return type;
|
|
66 | + }
|
|
67 | + |
|
68 | + public static ProxyType fromInt(int i) {
|
|
69 | + switch (i) {
|
|
70 | + case -1: return Invalid;
|
|
71 | + case 0: return Socks4;
|
|
72 | + case 1: return Socks5;
|
|
73 | + case 2: return HTTPS;
|
|
74 | + }
|
|
75 | + return Invalid;
|
|
76 | + }
|
|
77 | + }
|
|
78 | + |
|
79 | + private boolean loaded = false;
|
|
80 | + |
|
81 | + public boolean enabled = true;
|
|
82 | + |
|
83 | + public boolean quickstart = false;
|
|
84 | + |
|
85 | + // bridges section
|
|
86 | + public boolean bridgesEnabled = false;
|
|
87 | + public BridgeSource bridgesSource = BridgeSource.Invalid;
|
|
88 | + public String bridgesBuiltinType = "";
|
|
89 | + public String[] bridgeBridgeStrings;
|
|
90 | + |
|
91 | + // proxy section
|
|
92 | + public boolean proxyEnabled = false;
|
|
93 | + public ProxyType proxyType = ProxyType.Invalid;
|
|
94 | + public String proxyAddress = "";
|
|
95 | + public int proxyPort = 0;
|
|
96 | + public String proxyUsername = "";
|
|
97 | + public String proxyPassword = "";
|
|
98 | + |
|
99 | + // firewall section
|
|
100 | + public boolean firewallEnabled = false;
|
|
101 | + public int[] firewallAllowedPorts;
|
|
102 | + |
|
103 | + public TorSettings() {
|
|
104 | + }
|
|
105 | + |
|
106 | + public TorSettings(GeckoBundle bundle) {
|
|
107 | + try {
|
|
108 | + GeckoBundle qs = bundle.getBundle("quickstart");
|
|
109 | + GeckoBundle bridges = bundle.getBundle("bridges");
|
|
110 | + GeckoBundle proxy = bundle.getBundle("proxy");
|
|
111 | + GeckoBundle firewall = bundle.getBundle("firewall");
|
|
112 | + |
|
113 | + bridgesEnabled = bridges.getBoolean("enabled");
|
|
114 | + bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
|
|
115 | + bridgesBuiltinType = bridges.getString("builtin_type");
|
|
116 | + bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
|
|
117 | + |
|
118 | + quickstart = qs.getBoolean("enabled");
|
|
119 | + |
|
120 | + firewallEnabled = firewall.getBoolean("enabled");
|
|
121 | + firewallAllowedPorts = firewall.getIntArray("allowed_ports");
|
|
122 | + |
|
123 | + proxyEnabled = proxy.getBoolean("enabled");
|
|
124 | + proxyAddress = proxy.getString("address");
|
|
125 | + proxyUsername = proxy.getString("username");
|
|
126 | + proxyPassword = proxy.getString("password");
|
|
127 | + proxyPort = proxy.getInt("port");
|
|
128 | + proxyType = ProxyType.fromInt(proxy.getInt("type"));
|
|
129 | + |
|
130 | + loaded = true;
|
|
131 | + } catch (Exception e) {
|
|
132 | + Log.e("TorSettings", "bundle access error: " + e.toString(), e);
|
|
133 | + }
|
|
134 | + }
|
|
135 | + |
|
136 | + public GeckoBundle asGeckoBundle() {
|
|
137 | + GeckoBundle bundle = new GeckoBundle();
|
|
138 | + |
|
139 | + GeckoBundle qs = new GeckoBundle();
|
|
140 | + GeckoBundle bridges = new GeckoBundle();
|
|
141 | + GeckoBundle proxy = new GeckoBundle();
|
|
142 | + GeckoBundle firewall = new GeckoBundle();
|
|
143 | + |
|
144 | + bridges.putBoolean("enabled", bridgesEnabled);
|
|
145 | + bridges.putInt("source", bridgesSource.toInt());
|
|
146 | + bridges.putString("builtin_type", bridgesBuiltinType);
|
|
147 | + bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
|
|
148 | + |
|
149 | + qs.putBoolean("enabled", quickstart);
|
|
150 | + |
|
151 | + firewall.putBoolean("enabled", firewallEnabled);
|
|
152 | + firewall.putIntArray("allowed_ports", firewallAllowedPorts);
|
|
153 | + |
|
154 | + proxy.putBoolean("enabled", proxyEnabled);
|
|
155 | + proxy.putString("address", proxyAddress);
|
|
156 | + proxy.putString("username", proxyUsername);
|
|
157 | + proxy.putString("password", proxyPassword);
|
|
158 | + proxy.putInt("port", proxyPort);
|
|
159 | + proxy.putInt("type", proxyType.toInt());
|
|
160 | + |
|
161 | + bundle.putBundle("quickstart", qs);
|
|
162 | + bundle.putBundle("bridges", bridges);
|
|
163 | + bundle.putBundle("proxy", proxy);
|
|
164 | + bundle.putBundle("firewall", firewall);
|
|
165 | + |
|
166 | + return bundle;
|
|
167 | + }
|
|
168 | + |
|
169 | + public boolean isLoaded() {
|
|
170 | + return this.loaded;
|
|
171 | + }
|
|
172 | +} |
1 | +package org.mozilla.geckoview.androidlegacysettings;
|
|
2 | + |
|
3 | +import android.content.Context;
|
|
4 | +import android.content.SharedPreferences;
|
|
5 | +import org.mozilla.gecko.GeckoAppShell;
|
|
6 | + |
|
7 | +import java.util.Locale;
|
|
8 | + |
|
9 | +// tor-android-service utils/Prefs.java
|
|
10 | + |
|
11 | +/* 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";
|
|
14 | + |
|
15 | + private static SharedPreferences prefs;
|
|
16 | + |
|
17 | + // OrbotConstants
|
|
18 | + private final static String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences";
|
|
19 | + |
|
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 | + }
|
|
28 | + }
|
|
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();
|
|
43 | + }
|
|
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 | + return prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
|
|
53 | + }
|
|
54 | + |
|
55 | + public static String getBridgesList() {
|
|
56 | + setContext();
|
|
57 | + // was "meek" for (Locale.getDefault().getLanguage().equals("fa")) and "obfs4" for the rest from a 2019 commit
|
|
58 | + // but that has stopped representing a good default sometime since so not importing for new users
|
|
59 | + String list = prefs.getString(PREF_BRIDGES_LIST, "");
|
|
60 | + return list;
|
|
61 | + }
|
|
62 | + |
|
63 | + |
|
64 | +} |
1 | +package org.mozilla.geckoview.androidlegacysettings;
|
|
2 | + |
|
3 | +import java.io.IOException;
|
|
4 | + |
|
5 | +import android.content.SharedPreferences;
|
|
6 | + |
|
7 | +import org.mozilla.gecko.GeckoAppShell;
|
|
8 | + |
|
9 | +import org.mozilla.geckoview.TorSettings;
|
|
10 | + |
|
11 | +public class TorLegacyAndroidSettings {
|
|
12 | + |
|
13 | + private static String PREF_USE_MOZ_PREFS = "tor_use_moz_prefs";
|
|
14 | + |
|
15 | + public static boolean unmigrated() {
|
|
16 | + return !Prefs.getBoolean(PREF_USE_MOZ_PREFS, false);
|
|
17 | + }
|
|
18 | + |
|
19 | + public static void setUnmigrated() {
|
|
20 | + Prefs.putBoolean(PREF_USE_MOZ_PREFS, false);
|
|
21 | + }
|
|
22 | + |
|
23 | + public static void setMigrated() {
|
|
24 | + Prefs.putBoolean(PREF_USE_MOZ_PREFS, true);
|
|
25 | + }
|
|
26 | + |
|
27 | + public static TorSettings loadTorSettings() {
|
|
28 | + TorSettings settings = new TorSettings();
|
|
29 | + |
|
30 | + // always true, tor is enabled in TB
|
|
31 | + settings.enabled = true;
|
|
32 | + |
|
33 | + // firefox-android disconnected quick start a while ago so it's untracked
|
|
34 | + settings.quickstart = false;
|
|
35 | + |
|
36 | + settings.bridgesEnabled = Prefs.bridgesEnabled();
|
|
37 | + |
|
38 | + // tor-android-service CustomTorInstaller.java
|
|
39 | +/*
|
|
40 | + BridgesList is an overloaded field, which can cause some confusion.
|
|
41 | + The list can be:
|
|
42 | + 1) a filter like obfs4, meek, or snowflake OR
|
|
43 | + 2) it can be a custom bridge
|
|
44 | + For (1), we just pass back all bridges, the filter will occur
|
|
45 | + elsewhere in the library.
|
|
46 | + For (2) we return the bridge list as a raw stream.
|
|
47 | + If length is greater than 9, then we know this is a custom bridge
|
|
48 | + */
|
|
49 | + String userDefinedBridgeList = Prefs.getBridgesList();
|
|
50 | + boolean userDefinedBridge = userDefinedBridgeList.length() > 9;
|
|
51 | + // Terrible hack. Must keep in sync with topl::addBridgesFromResources.
|
|
52 | + if (!userDefinedBridge) {
|
|
53 | + settings.bridgesSource = TorSettings.BridgeSource.BuiltIn;
|
|
54 | + switch (userDefinedBridgeList) {
|
|
55 | + case "obfs4":
|
|
56 | + settings.bridgesBuiltinType = "objs4";
|
|
57 | + break;
|
|
58 | + case "meek":
|
|
59 | + settings.bridgesBuiltinType = "meek_azure";
|
|
60 | + break;
|
|
61 | + case "snowflake":
|
|
62 | + settings.bridgesBuiltinType = "snowflake";
|
|
63 | + break;
|
|
64 | + default:
|
|
65 | + settings.bridgesSource = TorSettings.BridgeSource.Invalid;
|
|
66 | + break;
|
|
67 | + }
|
|
68 | + } else {
|
|
69 | + settings.bridgesSource = TorSettings.BridgeSource.UserProvided; // user provided
|
|
70 | + settings.bridgeBridgeStrings = userDefinedBridgeList.split("\r\n");
|
|
71 | + }
|
|
72 | + |
|
73 | + // Tor Browser Android doesn't take proxy and firewall settings
|
|
74 | + settings.proxyEnabled = false;
|
|
75 | + |
|
76 | + settings.firewallEnabled = false;
|
|
77 | + settings.firewallAllowedPorts = new int[0];
|
|
78 | + |
|
79 | + return settings;
|
|
80 | + }
|
|
81 | +}
|
|
82 | + |
|
83 | + |
|
84 | + |
... | ... | @@ -8,6 +8,8 @@ const lazy = {}; |
8 | 8 | ChromeUtils.defineESModuleGetters(lazy, {
|
9 | 9 | EventDispatcher: "resource://gre/modules/Messaging.sys.mjs",
|
10 | 10 | TorConnect: "resource://gre/modules/TorConnect.sys.mjs",
|
11 | + TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs",
|
|
12 | + TorSettingsTopics: "resource://gre/modules/TorSettings.sys.mjs",
|
|
11 | 13 | TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
12 | 14 | TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
|
13 | 15 | });
|
... | ... | @@ -23,11 +25,22 @@ const logger = new ConsoleAPI({ |
23 | 25 | prefix: "TorAndroidIntegration",
|
24 | 26 | });
|
25 | 27 | |
28 | +const EmittedEvents = Object.freeze( {
|
|
29 | + settingsReady: "GeckoView:Tor:SettingsReady",
|
|
30 | + settingsChanged: "GeckoView:Tor:SettingsChanged",
|
|
31 | +});
|
|
32 | + |
|
26 | 33 | const ListenedEvents = Object.freeze({
|
27 | 34 | settingsGet: "GeckoView:Tor:SettingsGet",
|
35 | + // The data is passed directly to TorSettings.
|
|
28 | 36 | settingsSet: "GeckoView:Tor:SettingsSet",
|
29 | 37 | settingsApply: "GeckoView:Tor:SettingsApply",
|
30 | 38 | settingsSave: "GeckoView:Tor:SettingsSave",
|
39 | + bootstrapBegin: "GeckoView:Tor:BootstrapBegin",
|
|
40 | + // Optionally takes a countryCode, as data.countryCode.
|
|
41 | + bootstrapBeginAuto: "GeckoView:Tor:BootstrapBeginAuto",
|
|
42 | + bootstrapCancel: "GeckoView:Tor:BootstrapCancel",
|
|
43 | + bootstrapGetState: "GeckoView:Tor:BootstrapGetState",
|
|
31 | 44 | });
|
32 | 45 | |
33 | 46 | class TorAndroidIntegrationImpl {
|
... | ... | @@ -41,6 +54,14 @@ class TorAndroidIntegrationImpl { |
41 | 54 | |
42 | 55 | this.#bootstrapMethodReset();
|
43 | 56 | Services.prefs.addObserver(Prefs.useNewBootstrap, this);
|
57 | + |
|
58 | + for (const topic in lazy.TorConnectTopics) {
|
|
59 | + Services.obs.addObserver(this, lazy.TorConnectTopics[topic]);
|
|
60 | + }
|
|
61 | + |
|
62 | + for (const topic in lazy.TorSettingsTopics) {
|
|
63 | + Services.obs.addObserver(this, lazy.TorSettingsTopics[topic]);
|
|
64 | + }
|
|
44 | 65 | }
|
45 | 66 | |
46 | 67 | async #initNewBootstrap() {
|
... | ... | @@ -67,6 +88,14 @@ class TorAndroidIntegrationImpl { |
67 | 88 | this.#bootstrapMethodReset();
|
68 | 89 | }
|
69 | 90 | break;
|
91 | + case lazy.TorConnectTopics.StateChange:
|
|
92 | + break;
|
|
93 | + case lazy.TorSettingsTopics.Ready:
|
|
94 | + lazy.EventDispatcher.instance.sendRequest({
|
|
95 | + type: EmittedEvents.settingsReady,
|
|
96 | + settings: lazy.TorSettings.getSettings(),
|
|
97 | + });
|
|
98 | + break;
|
|
70 | 99 | }
|
71 | 100 | }
|
72 | 101 | |
... | ... | @@ -74,24 +103,36 @@ class TorAndroidIntegrationImpl { |
74 | 103 | logger.debug(`Received event ${event}`, data);
|
75 | 104 | try {
|
76 | 105 | switch (event) {
|
77 | - case settingsGet:
|
|
106 | + case ListenedEvents.settingsGet:
|
|
78 | 107 | callback?.onSuccess(lazy.TorSettings.getSettings());
|
79 | 108 | return;
|
80 | - case settingsSet:
|
|
109 | + case ListenedEvents.settingsSet:
|
|
81 | 110 | // This does not throw, so we do not have any way to report the error!
|
82 | 111 | lazy.TorSettings.setSettings(data);
|
83 | 112 | break;
|
84 | - case settingsApply:
|
|
113 | + case ListenedEvents.settingsApply:
|
|
85 | 114 | await lazy.TorSettings.applySettings();
|
86 | 115 | break;
|
87 | - case settingsSave:
|
|
116 | + case ListenedEvents.settingsSave:
|
|
88 | 117 | await lazy.TorSettings.saveSettings();
|
89 | 118 | break;
|
119 | + case ListenedEvents.bootstrapBegin:
|
|
120 | + lazy.TorConnect.beginBootstrap();
|
|
121 | + break;
|
|
122 | + case ListenedEvents.bootstrapBeginAuto:
|
|
123 | + lazy.TorConnect.beginAutoBootstrap(data.countryCode);
|
|
124 | + break;
|
|
125 | + case ListenedEvents.bootstrapCancel:
|
|
126 | + lazy.TorConnect.cancelBootstrap();
|
|
127 | + break;
|
|
128 | + case ListenedEvents.bootstrapGetState:
|
|
129 | + callback?.onSuccess(lazy.TorConnect.state);
|
|
130 | + return;
|
|
90 | 131 | }
|
91 | 132 | callback?.onSuccess();
|
92 | 133 | } catch (e) {
|
93 | - logger.error();
|
|
94 | - callback?.sendError(e);
|
|
134 | + logger.error(`Error while handling event ${event}`, e);
|
|
135 | + callback?.onError(e);
|
|
95 | 136 | }
|
96 | 137 | }
|
97 | 138 |