Skip to content

Commit 1f24533

Browse files
committed
feat: support tor and torsf proxies
Unfortunately, because of ooni/probe#2406, we are going to see crashes when using these proxies. This diff is part of ooni/probe#2500. Since we're increasingly being blocked, it makes sense to exposes all the possible proxies we can feature. We're going to touch upon the same files again once we land the ooni/probe-cli#1162 pull request.
1 parent 00e0754 commit 1f24533

File tree

5 files changed

+88
-13
lines changed

5 files changed

+88
-13
lines changed

app/src/main/java/org/openobservatory/ooniprobe/activity/ProxyActivity.java

+52-6
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ public class ProxyActivity extends AbstractActivity {
4848
*
4949
* 1. an empty string means no proxy;
5050
*
51-
* 2. "psiphon://" means that we wanna use psiphon;
51+
* 2. "psiphon:///" means that we want to use psiphon;
5252
*
53-
* 3. "socks5://1.2.3.4:5678" or "socks5://[::1]:5678" or "socks5://d.com:5678"
53+
* 3. "tor:///" means we want to use tor without any proxy (which is possible
54+
* because oonimkall embeds `libtor.a` as a dependency);
55+
*
56+
* 4. "torsf:///" is like "tor:///" but additionally uses the snowflake
57+
* library we also bundle inside of oonimkall;
58+
*
59+
* 5. "socks5://1.2.3.4:5678" or "socks5://[::1]:5678" or "socks5://d.com:5678"
5460
* means that we wanna use the given socks5 proxy.
5561
*
5662
* Future improvements
@@ -67,8 +73,6 @@ public class ProxyActivity extends AbstractActivity {
6773
* This implies we can trivially support a vanilla socks5 proxy with username and
6874
* password by just replacing `psiphon+socks5` with `socks5`.
6975
*
70-
* We also want to support vanilla tor, using `tor://`.
71-
*
7276
* We also want to support vanilla tor with socks5, which is trivially doable
7377
* using as a scheme the `tor+socks5` scheme.
7478
*
@@ -93,15 +97,20 @@ public class ProxyActivity extends AbstractActivity {
9397
* The design and implementation of this class owes to the code contributed
9498
* by and the suggestion from friendly anonymous users. Thank you!
9599
*/
100+
101+
// logger is the injected AppLogger instance.
96102
@Inject
97103
AppLogger logger;
104+
98105
// TAG is the tag used for logging.
99106
private final static String TAG = "ProxyActivity";
100107

108+
// preferenceManager is the injected PreferenceManager instance.
101109
@Inject
102110
PreferenceManager preferenceManager;
103-
// The following radio group describes the top level choice
104-
// in terms of proxying: no proxy, psiphon, or custom.
111+
112+
// The following radio group describes the top level choice in terms of
113+
// proxying: no proxy, psiphon, tor, torsf, or custom.
105114

106115
// proxyRadioGroup is the top-level radio group.
107116
private RadioGroup proxyRadioGroup;
@@ -112,12 +121,21 @@ public class ProxyActivity extends AbstractActivity {
112121
// proxyPsiphonRB is the radio button selecting the "psiphon" proxy.
113122
private RadioButton proxyPsiphonRB;
114123

124+
// proxyTorRB is the radio button selecting the "tor" proxy.
125+
private RadioButton proxyTorRB;
126+
127+
// proxyTorSfRB is the radio button selecting the "torsf" proxy.
128+
private RadioButton proxyTorSfRB;
129+
115130
// proxyCustomRB is the radio button for the "custom" proxy.
116131
private RadioButton proxyCustomRB;
117132

118133
// The following radio group allows users to choose which specific
119134
// custom proxy they would like to use. When writing this documentation,
120135
// only socks5 is available but we will add more options.
136+
//
137+
// TODO(bassosimone): we need to implement support for HTTP proxies
138+
// once https://github.com/ooni/probe-cli/pull/1162 lands.
121139

122140
// customProxyRadioGroup allows you to choose among the different
123141
// kinds of custom proxies that are available.
@@ -153,6 +171,8 @@ public void onCreate(Bundle savedInstanceState) {
153171
proxyRadioGroup = findViewById(R.id.proxyRadioGroup);
154172
proxyNoneRB = findViewById(R.id.proxyNone);
155173
proxyPsiphonRB = findViewById(R.id.proxyPsiphon);
174+
proxyTorRB = findViewById(R.id.proxyTor);
175+
proxyTorSfRB = findViewById(R.id.proxyTorSf);
156176
proxyCustomRB = findViewById(R.id.proxyCustom);
157177
customProxyRadioGroup = findViewById(R.id.customProxyRadioGroup);
158178
customProxySOCKS5 = findViewById(R.id.customProxySOCKS5);
@@ -196,6 +216,10 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
196216
proxyNoneRB.setChecked(true);
197217
} else if (settings.protocol == ProxyProtocol.PSIPHON) {
198218
proxyPsiphonRB.setChecked(true);
219+
} else if (settings.protocol == ProxyProtocol.TOR) {
220+
proxyTorRB.setChecked(true);
221+
} else if (settings.protocol == ProxyProtocol.TORSF) {
222+
proxyTorSfRB.setChecked(true);
199223
} else if (settings.protocol == ProxyProtocol.SOCKS5) {
200224
proxyCustomRB.setChecked(true);
201225
} else {
@@ -226,6 +250,10 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
226250
customProxySetEnabled(false);
227251
} else if (checkedId == R.id.proxyPsiphon) {
228252
customProxySetEnabled(false);
253+
} else if (checkedId == R.id.proxyTor) {
254+
customProxySetEnabled(false);
255+
} else if (checkedId == R.id.proxyTorSf) {
256+
customProxySetEnabled(false);
229257
} else if (checkedId == R.id.proxyCustom) {
230258
customProxySetEnabled(true);
231259
customProxyRadioGroup.clearCheck();
@@ -364,6 +392,24 @@ public void onBackPressed() {
364392
return;
365393
}
366394

395+
// If the tor proxy is checked then write back the right
396+
// proxy configuration for tor and move on.
397+
if (proxyTorRB.isChecked()) {
398+
settings.protocol = ProxyProtocol.TOR;
399+
saveSettings();
400+
super.onBackPressed();
401+
return;
402+
}
403+
404+
// If the torsf proxy is checked then write back the right
405+
// proxy configuration for torsf and move on.
406+
if (proxyTorSfRB.isChecked()) {
407+
settings.protocol = ProxyProtocol.TORSF;
408+
saveSettings();
409+
super.onBackPressed();
410+
return;
411+
}
412+
367413
// validate the hostname for the custom proxy.
368414
if (!isValidHostnameOrIP(hostname)) {
369415
customProxyHostname.setError("not a valid hostname or IP");

app/src/main/java/org/openobservatory/ooniprobe/common/ProxyProtocol.java

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
public enum ProxyProtocol {
55
NONE("none"),
66
PSIPHON("psiphon"),
7+
TOR("tor"),
8+
TORSF("torsf"),
79
SOCKS5("socks5");
810

911
private String protocol;

app/src/main/java/org/openobservatory/ooniprobe/common/ProxySettings.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
* documentation of proxy activity for the design rationale.
1414
*/
1515
public class ProxySettings {
16-
17-
/** scheme is the proxy scheme (e.g., "psiphon", "socks5"). */
16+
/** scheme is the proxy scheme (e.g., "psiphon", "tor", "torsf", "socks5"). */
1817
public ProxyProtocol protocol = ProxyProtocol.NONE;
1918

2019
/** hostname is the hostname for custom proxies. */
@@ -33,10 +32,14 @@ public static ProxySettings newProxySettings(PreferenceManager pm) throws Invali
3332
settings.protocol = ProxyProtocol.NONE;
3433
} else if (protocol.equals(ProxyProtocol.PSIPHON.getProtocol())) {
3534
settings.protocol = ProxyProtocol.PSIPHON;
35+
} else if (protocol.equals(ProxyProtocol.TOR.getProtocol())) {
36+
settings.protocol = ProxyProtocol.TOR;
37+
} else if (protocol.equals(ProxyProtocol.TORSF.getProtocol())) {
38+
settings.protocol = ProxyProtocol.TORSF;
3639
} else if (protocol.equals(ProxyProtocol.SOCKS5.getProtocol())) {
3740
settings.protocol = ProxyProtocol.SOCKS5;
3841
} else {
39-
// This is where we will extend the code to add support for
42+
// This exception indicates that we need to extend the code to support
4043
// more proxies, e.g., HTTP proxies.
4144
throw new InvalidProxyURL("unhandled URL scheme");
4245
}
@@ -72,10 +75,18 @@ private boolean isIPv6(String hostname) {
7275

7376
/** getProxyString returns to you the proxy string you should pass to oonimkall. */
7477
public String getProxyString() throws URISyntaxException {
75-
if (protocol == ProxyProtocol.NONE)
78+
if (protocol == ProxyProtocol.NONE) {
7679
return "";
77-
if (protocol == ProxyProtocol.PSIPHON)
78-
return "psiphon://";
80+
}
81+
if (protocol == ProxyProtocol.PSIPHON) {
82+
return "psiphon:///";
83+
}
84+
if (protocol == ProxyProtocol.TOR) {
85+
return "tor:///";
86+
}
87+
if (protocol == ProxyProtocol.TORSF) {
88+
return "torsf:///";
89+
}
7990
if (protocol == ProxyProtocol.SOCKS5) {
8091
// Alright, we now need to construct a new SOCKS5 URL. We are going to defer
8192
// doing that to the Java standard library (er, the Android stdlib).

app/src/main/res/layout/activity_proxy.xml

+15-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@
3838
android:textColor="@color/color_black"
3939
android:text="@string/Settings_Proxy_Psiphon" />
4040

41+
<RadioButton
42+
android:id="@+id/proxyTor"
43+
android:layout_width="wrap_content"
44+
android:layout_height="wrap_content"
45+
android:textColor="@color/color_black"
46+
android:text="@string/Settings_Proxy_Tor" />
47+
48+
<RadioButton
49+
android:id="@+id/proxyTorSf"
50+
android:layout_width="wrap_content"
51+
android:layout_height="wrap_content"
52+
android:textColor="@color/color_black"
53+
android:text="@string/Settings_Proxy_TorSf" />
54+
4155
<RadioButton
4256
android:id="@+id/proxyCustom"
4357
android:layout_width="wrap_content"
@@ -114,4 +128,4 @@
114128
</LinearLayout>
115129
</ScrollView>
116130

117-
</androidx.constraintlayout.widget.ConstraintLayout>
131+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/values/strings.xml

+2
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@
392392
<string name="Settings_Proxy_Enabled">Proxy</string>
393393
<string name="Settings_Proxy_None">None</string>
394394
<string name="Settings_Proxy_Psiphon">Psiphon</string>
395+
<string name="Settings_Proxy_Tor">Tor (vanilla)</string>
396+
<string name="Settings_Proxy_TorSf">Tor with Snowflake</string>
395397
<string name="Settings_Proxy_Custom">Custom Proxy</string>
396398
<string name="Settings_Proxy_Custom_Value">Custom Proxy URL</string>
397399
<string name="Settings_Proxy_Custom_Protocol">Custom proxy protocol</string>

0 commit comments

Comments
 (0)