bridges) {
+ for (String bridge : bridges) {
+ if (!isNullOrEmpty(bridge)) {
+ writeLine("Bridge " + bridge);
+ }
+ }
return this;
}
+ @SettingsConfig
+ public TorConfigBuilder customBridgesFromSettings() {
+ if (!settings.hasBridges() || !hasCustomBridges()) {
+ return this;
+ }
+ return customBridges(settings.getCustomBridges());
+ }
+
+ public TorConfigBuilder debugLogs() {
+ writeLine("Log debug syslog");
+ writeLine("Log info syslog");
+ return writeFalseProperty("SafeLogging");
+ }
+
@SettingsConfig
public TorConfigBuilder debugLogsFromSettings() {
return settings.hasDebugLogs() ? debugLogs() : this;
}
public TorConfigBuilder disableNetwork() {
- buffer.append("DisableNetwork 1").append('\n');
- return this;
+ return writeTrueProperty("DisableNetwork");
}
@SettingsConfig
@@ -175,75 +182,64 @@ public TorConfigBuilder disableNetworkFromSettings() {
return settings.disableNetwork() ? disableNetwork() : this;
}
- public TorConfigBuilder dnsPort(String dnsPort) {
- if (!isNullOrEmpty(dnsPort)) buffer.append("DNSPort ").append(dnsPort).append('\n');
- return this;
+ public TorConfigBuilder dnsPort(String dnsHost, Integer dnsPort) {
+ return writeAddress("DNSPort", dnsHost, dnsPort, null);
}
@SettingsConfig
public TorConfigBuilder dnsPortFromSettings() {
- return dnsPort(settings.dnsPort());
+ return dnsPort(settings.getDnsHost(), settings.getDnsPort());
}
public TorConfigBuilder dontUseBridges() {
- buffer.append("UseBridges 0").append('\n');
- return this;
+ return writeFalseProperty("UseBridges");
}
public TorConfigBuilder entryNodes(String entryNodes) {
if (!isNullOrEmpty(entryNodes))
- buffer.append("EntryNodes ").append(entryNodes).append('\n');
+ writeLine("EntryNodes", entryNodes);
return this;
}
public TorConfigBuilder excludeNodes(String excludeNodes) {
if (!isNullOrEmpty(excludeNodes))
- buffer.append("ExcludeNodes ").append(excludeNodes).append('\n');
+ writeLine("ExcludeNodes", excludeNodes);
return this;
}
public TorConfigBuilder exitNodes(String exitNodes) {
if (!isNullOrEmpty(exitNodes))
- buffer.append("ExitNodes ").append(exitNodes).append('\n');
+ writeLine("ExitNodes", exitNodes);
return this;
}
public TorConfigBuilder geoIpFile(String path) {
- if (!isNullOrEmpty(path)) buffer.append("GeoIPFile ").append(path).append('\n');
+ if (!isNullOrEmpty(path))
+ writeLine("GeoIPFile", path);
return this;
}
public TorConfigBuilder geoIpV6File(String path) {
- if (!isNullOrEmpty(path)) buffer.append("GeoIPv6File ").append(path).append('\n');
+ if (!isNullOrEmpty(path))
+ writeLine("GeoIPv6File", path);
return this;
}
- public TorConfigBuilder httpTunnelPort(int port, String isolationFlags) {
- buffer.append("HTTPTunnelPort ").append(port);
- if (!isNullOrEmpty(isolationFlags)) {
- buffer.append(" ").append(isolationFlags);
- }
- buffer.append('\n');
- return this;
+ public TorConfigBuilder httpTunnelPort(String host, Integer port, String isolationFlags) {
+ return writeAddress("HTTPTunnelPort", host, port, isolationFlags);
}
@SettingsConfig
public TorConfigBuilder httpTunnelPortFromSettings() {
- return httpTunnelPort(settings.getHttpTunnelPort(),
+ return httpTunnelPort(settings.getHttpTunnelHost(), settings.getHttpTunnelPort(),
settings.hasIsolationAddressFlagForTunnel() ? "IsolateDestAddr" : null);
}
- public TorConfigBuilder line(String value) {
- if (!isNullOrEmpty(value)) buffer.append(value).append("\n");
- return this;
- }
-
public TorConfigBuilder makeNonExitRelay(String dnsFile, int orPort, String nickname) {
- buffer.append("ServerDNSResolvConfFile ").append(dnsFile).append('\n');
- buffer.append("ORPort ").append(orPort).append('\n');
- buffer.append("Nickname ").append(nickname).append('\n');
- buffer.append("ExitPolicy reject *:*").append('\n');
- return this;
+ writeLine("ServerDNSResolvConfFile", dnsFile);
+ writeLine("ORPort", String.valueOf(orPort));
+ writeLine("Nickname", nickname);
+ return writeLine("ExitPolicy reject *:*");
}
/**
@@ -273,9 +269,18 @@ public TorConfigBuilder nonExitRelayFromSettings() {
return this;
}
+ /**
+ * Write bridges from packaged bridge list if bridges option is enabled and if user has set desired bridge types.
+ *
+ * If the user has also defined custom bridges, these take precedence and default bridges will not be written.
+ */
+ @SettingsConfig
+ public TorConfigBuilder defaultBridgesFromSettings() {
+ return defaultBridgesFromResources(settings.getBridgeTypes());
+ }
+
public TorConfigBuilder proxyOnAllInterfaces() {
- buffer.append("SocksListenAddress 0.0.0.0").append('\n');
- return this;
+ return writeLine("SocksListenAddress 0.0.0.0");
}
@SettingsConfig
@@ -284,9 +289,9 @@ public TorConfigBuilder proxyOnAllInterfacesFromSettings() {
}
/**
- * Set socks5 proxy with no authentication. This can be set if yo uare using a VPN.
+ * Set socks5 proxy with no authentication. This can be set if you are using a VPN.
*/
- public TorConfigBuilder proxySocks5(String host, String port) {
+ public TorConfigBuilder proxySocks5(String host, Integer port) {
buffer.append("socks5Proxy ").append(host).append(':').append(port).append('\n');
return this;
}
@@ -302,16 +307,16 @@ public TorConfigBuilder proxySocks5FromSettings() {
* Sets proxyWithAuthentication information. If proxyType, proxyHost or proxyPort is empty,
* then this method does nothing.
*/
- public TorConfigBuilder proxyWithAuthentication(String proxyType, String proxyHost, String
+ public TorConfigBuilder proxyWithAuthentication(String proxyType, String proxyHost, Integer
proxyPort, String proxyUser, String proxyPass) {
- if (!isNullOrEmpty(proxyType) && !isNullOrEmpty(proxyHost) && !isNullOrEmpty(proxyPort)) {
+ if (!isNullOrEmpty(proxyType) && !isNullOrEmpty(proxyHost) && proxyPort != null) {
buffer.append(proxyType).append("Proxy ").append(proxyHost).append(':').append
(proxyPort).append('\n');
if (proxyUser != null && proxyPass != null) {
if (proxyType.equalsIgnoreCase("socks5")) {
- buffer.append("Socks5ProxyUsername ").append(proxyUser).append('\n');
- buffer.append("Socks5ProxyPassword ").append(proxyPass).append('\n');
+ writeLine("Socks5ProxyUsername", proxyUser);
+ writeLine("Socks5ProxyPassword", proxyPass);
} else {
buffer.append(proxyType).append("ProxyAuthenticator ").append(proxyUser)
.append(':').append(proxyPort).append('\n');
@@ -335,7 +340,7 @@ public TorConfigBuilder proxyWithAuthenticationFromSettings() {
public TorConfigBuilder reachableAddressPorts(String reachableAddressesPorts) {
if (!isNullOrEmpty(reachableAddressesPorts))
- buffer.append("ReachableAddresses ").append(reachableAddressesPorts).append('\n');
+ writeLine("ReachableAddresses", reachableAddressesPorts);
return this;
}
@@ -347,8 +352,7 @@ public TorConfigBuilder reachableAddressesFromSettings() {
}
public TorConfigBuilder reducedConnectionPadding() {
- buffer.append("ReducedConnectionPadding 1").append('\n');
- return this;
+ return writeTrueProperty("ReducedConnectionPadding");
}
@SettingsConfig
@@ -366,23 +370,20 @@ public TorConfigBuilder runAsDaemonFromSettings() {
}
public TorConfigBuilder runAsDaemon() {
- buffer.append("RunAsDaemon 1").append('\n');
- return this;
+ return writeTrueProperty("RunAsDaemon");
}
public TorConfigBuilder safeSocksDisable() {
- buffer.append("SafeSocks 0").append('\n');
- return this;
+ return writeFalseProperty("SafeSocks");
}
public TorConfigBuilder safeSocksEnable() {
- buffer.append("SafeSocks 1").append('\n');
- return this;
+ return writeTrueProperty("SafeSocks");
}
@SettingsConfig
public TorConfigBuilder safeSocksFromSettings() {
- return !settings.hasSafeSocks() ? safeSocksDisable() : safeSocksEnable();
+ return settings.hasSafeSocks() ? safeSocksEnable() : this;
}
public TorConfigBuilder setGeoIpFiles() throws IOException {
@@ -413,6 +414,9 @@ public TorConfigBuilder socksPort(String socksPort, String isolationFlag) {
@SettingsConfig
public TorConfigBuilder socksPortFromSettings() {
String socksPort = settings.getSocksPort();
+ if (isNullOrEmpty(socksPort)) {
+ return this;
+ }
if (socksPort.indexOf(':') != -1) {
socksPort = socksPort.split(":")[1];
}
@@ -425,76 +429,71 @@ public TorConfigBuilder socksPortFromSettings() {
}
public TorConfigBuilder strictNodesDisable() {
- buffer.append("StrictNodes 0\n");
- return this;
+ return writeFalseProperty("StrictNodes");
}
public TorConfigBuilder strictNodesEnable() {
- buffer.append("StrictNodes 1\n");
- return this;
+ return writeTrueProperty("StrictNodes");
}
@SettingsConfig
public TorConfigBuilder strictNodesFromSettings() {
- return settings.hasStrictNodes() ? strictNodesEnable() : strictNodesDisable();
+ return settings.hasStrictNodes() ? strictNodesEnable() : this;
}
public TorConfigBuilder testSocksDisable() {
- buffer.append("TestSocks 0").append('\n');
- return this;
+ return writeFalseProperty("TestSocks");
}
public TorConfigBuilder testSocksEnable() {
- buffer.append("TestSocks 0").append('\n');
- return this;
+ return writeTrueProperty("TestSocks");
}
@SettingsConfig
public TorConfigBuilder testSocksFromSettings() {
- return !settings.hasTestSocks() ? testSocksDisable() : this;
+ return settings.hasTestSocks() ? testSocksEnable() : this;
}
@SettingsConfig
public TorConfigBuilder torrcCustomFromSettings() throws UnsupportedEncodingException {
return settings.getCustomTorrc() != null ?
- line(new String(settings.getCustomTorrc().getBytes("US-ASCII"))) : this;
+ writeLine(new String(settings.getCustomTorrc().getBytes("US-ASCII"))) : this;
}
- public TorConfigBuilder transPort(String transPort) {
- if (!isNullOrEmpty(transPort))
- buffer.append("TransPort ").append(transPort).append('\n');
- return this;
+ public TorConfigBuilder transparentProxyPort(String address, Integer transPort) {
+ return writeAddress("TransPort", address, transPort, null);
}
@SettingsConfig
public TorConfigBuilder transPortFromSettings() {
- return transPort(settings.transPort());
+ return transparentProxyPort(settings.getTransparentProxyAddress(), settings.getTransparentProxyPort());
}
public TorConfigBuilder transportPluginMeek(String clientPath) {
- buffer.append("ClientTransportPlugin meek_lite exec ").append(clientPath).append('\n');
- return this;
+ return writeLine("ClientTransportPlugin meek_lite exec", clientPath);
}
public TorConfigBuilder transportPluginObfs(String clientPath) {
- buffer.append("ClientTransportPlugin obfs3 exec ").append(clientPath).append('\n');
- buffer.append("ClientTransportPlugin obfs4 exec ").append(clientPath).append('\n');
- return this;
+ return writeLine("ClientTransportPlugin obfs3 exec", clientPath)
+ .writeLine("ClientTransportPlugin obfs4 exec", clientPath);
}
public TorConfigBuilder useBridges() {
- buffer.append("UseBridges 1").append('\n');
+ writeTrueProperty("UseBridges");
return this;
}
@SettingsConfig
public TorConfigBuilder useBridgesFromSettings() {
- return !settings.hasBridges() ? dontUseBridges() : this;
+ if (settings.hasBridges() && (hasCustomBridges() || hasUserDefinedBridges())) {
+ useBridges();
+ }
+ return this;
}
public TorConfigBuilder virtualAddressNetwork(String address) {
if (!isNullOrEmpty(address))
- buffer.append("VirtualAddrNetwork ").append(address).append('\n');
+ writeLine("VirtualAddrNetwork", address);
return this;
}
@@ -508,70 +507,51 @@ public TorConfigBuilder virtualAddressNetworkFromSettings() {
* These entries may be type-specified like:
*
*
- * obfs3 169.229.59.74:31493 AF9F66B7B04F8FF6F32D455F05135250A16543C9
- *
- *
- * Or it may just be a custom entry like
- *
- *
- * 69.163.45.129:443 9F090DE98CA6F67DEEB1F87EFE7C1BFD884E6E2F
+ * obfs3 169.229.59.74:31493 AF9F66B7B04F8FF6F32D455F05135250A16543C9
*
- *
+ *
*/
- TorConfigBuilder addBridgesFromResources(String type, int maxBridges) throws IOException {
- if(settings.hasBridges()) {
- InputStream bridgesStream = context.getInstaller().openBridgesStream();
- int formatType = bridgesStream.read();
- if(formatType == 0) {
- addBridges(bridgesStream, type, maxBridges);
- } else {
- addCustomBridges(bridgesStream);
+ TorConfigBuilder defaultBridgesFromResources(List userDefinedBridgeTypes) {
+ if (!settings.hasBridges() || !hasUserDefinedBridges() || hasCustomBridges()) {
+ return this;
+ }
+ ArrayList bridgeTypes = new ArrayList<>();
+ for (BridgeType bridgeType : userDefinedBridgeTypes) {
+ bridgeTypes.add(bridgeType.name().toLowerCase());
+ }
+ InputStream bridgesStream = null;
+ try {
+ bridgesStream = context.getInstaller().openDefaultBridgesStream();
+ writeDefaultBridgesFromStream(bridgesStream, bridgeTypes);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (bridgesStream != null) {
+ try {
+ bridgesStream.close();
+ } catch (IOException e) {
+ }
}
}
return this;
}
- /**
- * Add bridges from bridges.txt file.
- */
- private void addBridges(InputStream input, String bridgeType, int maxBridges) {
- if (input == null || isNullOrEmpty(bridgeType) || maxBridges < 1) {
- return;
- }
- boolean hasAddedBridge = false;
- List bridges = readBridgesFromStream(input);
- Collections.shuffle(bridges, new Random(System.nanoTime()));
- int bridgeCount = 0;
- for (Bridge b : bridges) {
- if (b.type.equals(bridgeType)) {
- bridge(b.type, b.config);
- hasAddedBridge = true;
- if (++bridgeCount > maxBridges)
- break;
- }
- }
- if(hasAddedBridge) useBridges();
+ private boolean hasCustomBridges() {
+ return !settings.getCustomBridges().isEmpty();
}
/**
- * Add custom bridges defined by the user. These will have a bridgeType of 'custom' as the first field.
+ * Returns true if user has specified bridge types and if bridges.txt file is found.
*/
- private void addCustomBridges(InputStream input) {
- if (input == null) {
- return;
- }
- boolean hasAddedBridge = false;
- List bridges = readCustomBridgesFromStream(input);
- for (Bridge b : bridges) {
- if (b.type.equals("custom")) {
- bridgeCustom(b.config);
- hasAddedBridge = true;
- }
- }
- if(hasAddedBridge) useBridges();
+ private boolean hasUserDefinedBridges() {
+ return !settings.getBridgeTypes().isEmpty() && context.getInstaller().hasDefaultBridgesStream();
}
- private static List readBridgesFromStream(InputStream input) {
+ /**
+ * Reads bridges from specified input
. If the file doesn't contain any valid bridge entries,
+ * then this method returns an empty bridge list.
+ */
+ private static List readDefaultBridgesFromStream(InputStream input) {
List bridges = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(input, "UTF-8"));
@@ -589,21 +569,71 @@ private static List readBridgesFromStream(InputStream input) {
return bridges;
}
- private static List readCustomBridgesFromStream(InputStream input) {
- List bridges = new ArrayList<>();
- try {
- BufferedReader br = new BufferedReader(new InputStreamReader(input, "UTF-8"));
- for (String line = br.readLine(); line != null; line = br.readLine()) {
- if(line.isEmpty()) {
- continue;
- }
- bridges.add(new Bridge("custom", line));
+ TorConfigBuilder writeAddress(String fieldName, String address, Integer port, String flags) {
+ if (isNullOrEmpty(address) && port == null) {
+ return this;
+ }
+ buffer.append(fieldName).append(" ");
+ if (!isNullOrEmpty(address)) {
+ buffer.append(address).append(":");
+ }
+ if (port != null) {
+ buffer.append(port <= 0 ? "auto" : port);
+ } else {
+ buffer.append("auto");
+ }
+ if (!isNullOrEmpty(flags)) {
+ buffer.append(" ").append(flags);
+ }
+ buffer.append('\n');
+ return this;
+ }
+
+ private void writeBridgeTransport(File pluggableTransportClient, BridgeType bridgeType) throws IOException {
+ switch (bridgeType) {
+ case MEEK_LITE:
+ transportPluginMeek(pluggableTransportClient.getCanonicalPath());
+ break;
+ case OBFS3:
+ case OBFS4:
+ transportPluginObfs(pluggableTransportClient.getCanonicalPath());
+ }
+ }
+
+ /**
+ * Writes bridges from bridges.txt file to the config. Only bridges of the specified bridgeTypes
will be written.
+ *
+ * If the input file doesn't contain any valid bridge entries, this method writes nothing to the config.
+ */
+ private void writeDefaultBridgesFromStream(InputStream input, List userDefinedBridgeTypes) {
+ if (input == null || userDefinedBridgeTypes.isEmpty()) {
+ return;
+ }
+ List bridges = readDefaultBridgesFromStream(input);
+ for (Bridge b : bridges) {
+ if (userDefinedBridgeTypes.contains(b.type)) {
+ bridge(b.type, b.config);
}
- br.close();
- } catch (Exception e) {
- e.printStackTrace();
}
- return bridges;
+ }
+
+ private TorConfigBuilder writeFalseProperty(String name) {
+ buffer.append(name).append(" 0").append('\n');
+ return this;
+ }
+
+ public TorConfigBuilder writeLine(String value) {
+ if (!isNullOrEmpty(value)) buffer.append(value).append("\n");
+ return this;
+ }
+
+ public TorConfigBuilder writeLine(String value, String value2) {
+ return writeLine(value + " " + value2);
+ }
+
+ private TorConfigBuilder writeTrueProperty(String name) {
+ buffer.append(name).append(" 1").append('\n');
+ return this;
}
private static class Bridge {
diff --git a/universal/src/main/java/com/msopentech/thali/toronionproxy/TorInstaller.java b/universal/src/main/java/com/msopentech/thali/toronionproxy/TorInstaller.java
index 308cd837..c97bf3ec 100644
--- a/universal/src/main/java/com/msopentech/thali/toronionproxy/TorInstaller.java
+++ b/universal/src/main/java/com/msopentech/thali/toronionproxy/TorInstaller.java
@@ -29,20 +29,7 @@ public final InputStream getAssetOrResourceByName(String fileName) {
return getClass().getResourceAsStream("/" + fileName);
}
- /**
- * If first byte of stream is 0, then the following stream will have the form
- *
- *
- * ($bridge_type $bridge_info \r\n)*
- *
- *
- * if first byte is 1, the the stream will have the form
- *
- * ($bridge_info \r\n)*
- *
- *
- * The second form is used for custom bridges from the user.
- *
- */
- public abstract InputStream openBridgesStream() throws IOException;
+ public abstract InputStream openDefaultBridgesStream() throws IOException;
+
+ public abstract boolean hasDefaultBridgesStream();
}
diff --git a/universal/src/main/java/com/msopentech/thali/toronionproxy/TorSettings.java b/universal/src/main/java/com/msopentech/thali/toronionproxy/TorSettings.java
index 2d515d10..eee81fd8 100644
--- a/universal/src/main/java/com/msopentech/thali/toronionproxy/TorSettings.java
+++ b/universal/src/main/java/com/msopentech/thali/toronionproxy/TorSettings.java
@@ -5,32 +5,35 @@
public interface TorSettings {
boolean disableNetwork();
- String dnsPort();
+ List getCustomBridges();
String getCustomTorrc();
+ String getDnsHost();
+
+ Integer getDnsPort();
+
String getEntryNodes();
String getExcludeNodes();
String getExitNodes();
- int getHttpTunnelPort();
+ String getHttpTunnelHost();
+
+ Integer getHttpTunnelPort();
- /**
- * Returns a list of supported bridges. The string value will include the name: meek_lite, obfs4
- */
- List getListOfSupportedBridges();
+ List getBridgeTypes();
String getProxyHost();
String getProxyPassword();
- String getProxyPort();
+ Integer getProxyPort();
String getProxySocks5Host();
- String getProxySocks5ServerPort();
+ Integer getProxySocks5ServerPort();
String getProxyType();
@@ -40,10 +43,14 @@ public interface TorSettings {
String getRelayNickname();
- int getRelayPort();
+ Integer getRelayPort();
String getSocksPort();
+ String getTransparentProxyAddress();
+
+ Integer getTransparentProxyPort();
+
String getVirtualAddressNetwork();
boolean hasBridges();
@@ -74,7 +81,5 @@ public interface TorSettings {
boolean runAsDaemon();
- String transPort();
-
boolean useSocks5();
}
diff --git a/universal/src/test/java/com/msopentech/thali/toronionproxy/TorConfigBuilderTest.java b/universal/src/test/java/com/msopentech/thali/toronionproxy/TorConfigBuilderTest.java
new file mode 100644
index 00000000..4be997a3
--- /dev/null
+++ b/universal/src/test/java/com/msopentech/thali/toronionproxy/TorConfigBuilderTest.java
@@ -0,0 +1,325 @@
+package com.msopentech.thali.toronionproxy;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class TorConfigBuilderTest {
+
+ /**
+ * Bridges are added in random order
+ */
+ @Test
+ public void testAddCustomBridges() throws Exception {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getCustomBridges()).thenReturn(Arrays.asList("b1", "b2"));
+
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.customBridgesFromSettings();
+ String result = builder.asString();
+ assertTrue("Bridge b2\nBridge b1\n".equals(result) || "Bridge b1\nBridge b2\n".equals(result));
+ }
+
+ @Test
+ public void testNoCustomBridgesIfBridgesAreDisabled() throws Exception {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(false);
+ when(torSettings.getCustomBridges()).thenReturn(Arrays.asList("b1", "b2"));
+
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.customBridgesFromSettings();
+ String result = builder.asString();
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testNoCustomBridges() throws Exception {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getCustomBridges()).thenReturn(Collections.emptyList());
+
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.customBridgesFromSettings();
+ String result = builder.asString();
+ assertTrue(result.isEmpty());
+ }
+
+ /**
+ * Should be empty
+ */
+ @Test
+ public void testUseBridgesFromSettingsFalse() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(false);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testUseBridgesFromSettingsTrueNoDefaultBridgeStream() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testUseBridgesFromSettingsNoBridgeStreamAvailable() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getBridgeTypes()).thenReturn(Collections.singletonList(BridgeType.OBFS4));
+
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorInstaller torInstaller = mock(TorInstaller.class);
+ when(context.getInstaller()).thenReturn(torInstaller);
+ when(torInstaller.hasDefaultBridgesStream()).thenReturn(false);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testUseBridgesFromSettingsWithCustomBridges() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getCustomBridges()).thenReturn(Arrays.asList("b1", "b2"));
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("UseBridges 1\n", result);
+ }
+
+ @Test
+ public void testUseBridgesFromSettingsWithDefaultBridges() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getBridgeTypes()).thenReturn(Collections.singletonList(BridgeType.OBFS4));
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+
+ TorInstaller torInstaller = mock(TorInstaller.class);
+ when(context.getInstaller()).thenReturn(torInstaller);
+ when(torInstaller.hasDefaultBridgesStream()).thenReturn(true);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("UseBridges 1\n", result);
+ }
+
+ @Test
+ public void testUseBridgesFromSettingsWithDefaultBridgesButNoBridgesFile() {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getBridgeTypes()).thenReturn(Collections.singletonList(BridgeType.OBFS4));
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+
+ TorInstaller torInstaller = mock(TorInstaller.class);
+ when(context.getInstaller()).thenReturn(torInstaller);
+ when(torInstaller.hasDefaultBridgesStream()).thenReturn(false);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.useBridgesFromSettings();
+ String result = builder.asString();
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testDefaultBridgesFromSettingsFilterOneType() throws IOException {
+ String bridgeList = "obfs4 192\nobfs3 190\nobfs4 189\n,meek 170\n";
+ InputStream bridgeStream = new ByteArrayInputStream(bridgeList.getBytes());
+
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getBridgeTypes()).thenReturn(Collections.singletonList(BridgeType.OBFS4));
+ TorInstaller torInstaller = mock(TorInstaller.class);
+ when(torInstaller.openDefaultBridgesStream()).thenReturn(bridgeStream);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ when(context.getInstaller()).thenReturn(torInstaller);
+ when(torInstaller.hasDefaultBridgesStream()).thenReturn(true);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.defaultBridgesFromSettings();
+ String result = builder.asString();
+ assertTrue("Bridge obfs4 192\nBridge obfs4 189\n".equals(result)
+ || "Bridge obfs4 189\nBridge obfs4 192\n".equals(result));
+
+ }
+
+ @Test
+ public void testDefaultBridgesFromSettingsFilterTwoTypes() throws IOException {
+ String bridgeList = "obfs4 192\nobfs3 190\nobfs3 189\nmeek_lite 170\n";
+ InputStream bridgeStream = new ByteArrayInputStream(bridgeList.getBytes());
+
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(true);
+ when(torSettings.getBridgeTypes()).thenReturn(Arrays.asList(BridgeType.OBFS4, BridgeType.MEEK_LITE));
+ TorInstaller torInstaller = mock(TorInstaller.class);
+ when(torInstaller.openDefaultBridgesStream()).thenReturn(bridgeStream);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ when(context.getInstaller()).thenReturn(torInstaller);
+ when(torInstaller.hasDefaultBridgesStream()).thenReturn(true);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+
+ builder.defaultBridgesFromSettings();
+ String result = builder.asString();
+ assertTrue("Bridge obfs4 192\nBridge meek_lite 170\n".equals(result)
+ || "Bridge meek_lite 170\nBridge obfs4 192\n".equals(result));
+
+ }
+
+ @Test
+ public void testConfigureTransportsAddedWhenNoBridges() throws IOException {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(false);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ File transport = File.createTempFile("transport", ".exe");
+ transport.setExecutable(true);
+
+ builder.configurePluggableTransports(transport, Collections.singletonList(BridgeType.OBFS4));
+ String result = builder.asString();
+ assertTrue(result.contains("ClientTransportPlugin obfs3 exec"));
+ assertTrue(result.contains("ClientTransportPlugin obfs4 exec"));
+
+ }
+
+ @Test
+ public void testConfigureTransportsMeek() throws IOException {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.hasBridges()).thenReturn(false);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ File transport = File.createTempFile("transport", ".exe");
+ transport.setExecutable(true);
+
+ builder.configurePluggableTransports(transport, Arrays.asList(BridgeType.MEEK_LITE));
+ String result = builder.asString();
+ assertTrue(result.contains("ClientTransportPlugin meek_lite exec"));
+ assertFalse(result.contains("ClientTransportPlugin obfs4 exec"));
+ }
+
+ @Test
+ public void testHttpTunnelPort() throws IOException {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.getHttpTunnelHost()).thenReturn("192.1.1.1");
+ when(torSettings.getHttpTunnelPort()).thenReturn(8080);
+ when(torSettings.hasIsolationAddressFlagForTunnel()).thenReturn(true);
+
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.httpTunnelPortFromSettings();
+ String result = builder.asString();
+ assertEquals("HTTPTunnelPort 192.1.1.1:8080 IsolateDestAddr\n", result);
+ }
+
+ @Test
+ public void testTransparentProxy() throws IOException {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.getTransparentProxyAddress()).thenReturn("192.1.1.1");
+ when(torSettings.getTransparentProxyPort()).thenReturn(8080);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.transPortFromSettings();
+ String result = builder.asString();
+ assertEquals("TransPort 192.1.1.1:8080\n", result);
+ }
+
+ @Test
+ public void testDnsPort() throws IOException {
+ TorSettings torSettings = mock(TorSettings.class);
+ when(torSettings.getDnsPort()).thenReturn(5111);
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ when(context.getSettings()).thenReturn(torSettings);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.dnsPortFromSettings();
+ String result = builder.asString();
+ assertEquals("DNSPort 5111\n", result);
+ }
+
+ @Test
+ public void testAddAddress() throws IOException {
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.writeAddress("fieldName", "192.1.1.0", 8080, null);
+ String result = builder.asString();
+ assertEquals("fieldName 192.1.1.0:8080\n", result);
+ }
+
+ @Test
+ public void testAddAddressNoAddress() throws IOException {
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.writeAddress("fieldName", null, 8080, null);
+ String result = builder.asString();
+ assertEquals("fieldName 8080\n", result);
+ }
+
+ @Test
+ public void testAddAddressNoPort() throws IOException {
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.writeAddress("fieldName", "192.1.1.0", null, null);
+ String result = builder.asString();
+ assertEquals("fieldName 192.1.1.0:auto\n", result);
+ }
+
+ @Test
+ public void testAddAddressIllegalPort() throws IOException {
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.writeAddress("fieldName", "192.1.1.0", 0, null);
+ String result = builder.asString();
+ assertEquals("fieldName 192.1.1.0:auto\n", result);
+ }
+
+ @Test
+ public void testAddAddressNull() throws IOException {
+ OnionProxyContext context = mock(OnionProxyContext.class);
+ TorConfigBuilder builder = new TorConfigBuilder(context);
+ builder.writeAddress("fieldName", null, null, null);
+ String result = builder.asString();
+ assertEquals("", result);
+ }
+}
diff --git a/universal/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/universal/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 00000000..ca6ee9ce
--- /dev/null
+++ b/universal/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file