-
-
-
-
-
-
-
-
-
-
-
- url
- JAVA
- EXPRESSION
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index dfd2c799..b6ea2b11 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1ddf..94a25f7f 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/README - Copy.md b/README - Copy.md
deleted file mode 100644
index 2ba966f0..00000000
--- a/README - Copy.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# GenesisApp
-
-GenesisApp is search engine with ability to find content on tor network / deepweb / darkweb. the privacy of users is respected there is no cookies and no javascript and there is not third part code or external code.
-
-The app lets you search the sites in the deep web with the keywords and shows you a site tab with title, url and an preview of the content.
-
-You can share the site url with the title via email or via messaging app.
-To view the websites you must use the Tor browser or to be connected to the Tor network by vpn.
-On android phones you can use Orfox Browser with Orbot to connect to the Tor network.
-Anonymous connection to tor network.
diff --git a/README.md b/README.md
deleted file mode 100644
index 2ba966f0..00000000
--- a/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# GenesisApp
-
-GenesisApp is search engine with ability to find content on tor network / deepweb / darkweb. the privacy of users is respected there is no cookies and no javascript and there is not third part code or external code.
-
-The app lets you search the sites in the deep web with the keywords and shows you a site tab with title, url and an preview of the content.
-
-You can share the site url with the title via email or via messaging app.
-To view the websites you must use the Tor browser or to be connected to the Tor network by vpn.
-On android phones you can use Orfox Browser with Orbot to connect to the Tor network.
-Anonymous connection to tor network.
diff --git a/app - Copy/.gitignore b/app - Copy/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/app - Copy/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/app - Copy/build.gradle b/app - Copy/build.gradle
deleted file mode 100644
index e177897a..00000000
--- a/app - Copy/build.gradle
+++ /dev/null
@@ -1,44 +0,0 @@
-apply plugin: 'com.android.application'
-
-apply plugin: 'kotlin-android'
-
-apply plugin: 'kotlin-android-extensions'
-apply plugin: 'maven'
-
-android {
- compileSdkVersion 28
- defaultConfig {
- applicationId "com.example.myapplication"
- minSdkVersion 21
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'com.android.support:appcompat-v7:28.0.0'
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- implementation 'com.google.android.gms:play-services-ads:17.1.1'
- implementation "cz.msebera.android:httpclient:4.4.1.2"
- compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'
- compile 'info.guardianproject.netcipher:netcipher-okhttp3:2.0.0-alpha1'
- compile 'com.squareup.okhttp3:okhttp:3.4.2'
- compile 'org.apache.httpcomponents:httpcore:4.4.1'
-}
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
diff --git a/app - Copy/proguard-rules.pro b/app - Copy/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/app - Copy/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/app - Copy/release/app-release.apk b/app - Copy/release/app-release.apk
deleted file mode 100644
index dad6346e..00000000
Binary files a/app - Copy/release/app-release.apk and /dev/null differ
diff --git a/app - Copy/release/output.json b/app - Copy/release/output.json
deleted file mode 100644
index 9f0c9596..00000000
--- a/app - Copy/release/output.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app - Copy/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt b/app - Copy/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt
deleted file mode 100644
index 7a945382..00000000
--- a/app - Copy/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.example.myapplication
-
-import android.support.test.InstrumentationRegistry
-import android.support.test.runner.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getTargetContext()
- assertEquals("com.example.myapplication", appContext.packageName)
- }
-}
diff --git a/app - Copy/src/main/AndroidManifest.xml b/app - Copy/src/main/AndroidManifest.xml
deleted file mode 100644
index c324e7db..00000000
--- a/app - Copy/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app - Copy/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java b/app - Copy/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java
deleted file mode 100644
index 2a36a26a..00000000
--- a/app - Copy/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java
+++ /dev/null
@@ -1,490 +0,0 @@
-package com.example.myapplication;
-
-import android.os.Build;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.security.auth.x500.X500Principal;
-
-import cz.msebera.android.httpclient.HttpHost;
-import cz.msebera.android.httpclient.conn.socket.LayeredConnectionSocketFactory;
-import cz.msebera.android.httpclient.conn.ssl.DefaultHostnameVerifier;
-import cz.msebera.android.httpclient.conn.ssl.SSLContexts;
-import cz.msebera.android.httpclient.conn.ssl.SSLInitializationException;
-import cz.msebera.android.httpclient.conn.ssl.X509HostnameVerifier;
-import cz.msebera.android.httpclient.conn.util.PublicSuffixMatcherLoader;
-import cz.msebera.android.httpclient.protocol.HttpContext;
-import cz.msebera.android.httpclient.util.Args;
-import cz.msebera.android.httpclient.util.TextUtils;
-
-/*
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.http.HttpHost;
-import org.apache.http.annotation.ThreadSafe;
-import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
-import org.apache.http.conn.util.PublicSuffixMatcherLoader;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.ssl.SSLContexts;
-import org.apache.http.util.Args;
-import org.apache.http.util.TextUtils;
-*/
-
-/**
- * Layered socket factory for TLS/SSL connections.
- *
- * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
- * trusted certificates and to authenticate to the HTTPS server using a private key.
- *
- * SSLSocketFactory will enable server authentication when supplied with
- * a {@link java.security.KeyStore trust-store} file containing one or several trusted certificates. The client
- * secure socket will reject the connection during the SSL session handshake if the target HTTPS
- * server attempts to authenticate itself with a non-trusted certificate.
- *
- * Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
- *
- * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- *
- *
- * In special cases the standard trust verification process can be bypassed by using a custom
- * {@link org.apache.http.conn.ssl.TrustStrategy}. This interface is primarily intended for allowing self-signed
- * certificates to be accepted as trusted without having to add them to the trust-store file.
- *
- * SSLSocketFactory will enable client authentication when supplied with
- * a {@link java.security.KeyStore key-store} file containing a private key/public certificate
- * pair. The client secure socket will use the private key to authenticate
- * itself to the target HTTPS server during the SSL session handshake if
- * requested to do so by the server.
- * The target HTTPS server will in its turn verify the certificate presented
- * by the client in order to establish client's authenticity.
- *
- * Use the following sequence of actions to generate a key-store file
- *
- *
- *
- *
- * Use JDK keytool utility to generate a new key
- *
- * For simplicity use the same password for the key as that of the key-store
- *
- *
- *
- *
- * Issue a certificate signing request (CSR)
- *
- *
keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
- *
- *
- *
- * Send the certificate request to the trusted Certificate Authority for signature.
- * One may choose to act as her own CA and sign the certificate request using a PKI
- * tool, such as OpenSSL.
- *
- *
- *
- *
- * Import the trusted CA root certificate
- *
- *
keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
- *
- *
- *
- * Import the PKCS#7 file containing the complete certificate chain
- *
- *
keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
- *
- *
- *
- * Verify the content of the resultant keystore file
- *
- *
keytool -list -v -keystore my.keystore
- *
- *
- *
- * @since 4.3
- */
-// @ThreadSafe @SuppressWarnings("deprecation")
-public class SSLConnectionSocketFactory implements
- LayeredConnectionSocketFactory {
- private final static String TAG = "HttpClient";
- public static final String TLS = "TLS";
- public static final String SSL = "SSL";
- public static final String SSLV2 = "SSLv2";
-
-/*
- @Deprecated
- public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
- = AllowAllHostnameVerifier.INSTANCE;
- @Deprecated
- public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
- = BrowserCompatHostnameVerifier.INSTANCE;
- @Deprecated
- public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
- = StrictHostnameVerifier.INSTANCE;
-*/
-
-// private final Log log = LogFactory.getLog(getClass());
-
- /**
- * @since 4.4
- */
- public static HostnameVerifier getDefaultHostnameVerifier() {
- return new DefaultHostnameVerifier(
- PublicSuffixMatcherLoader.getDefault());
- }
-
- /**
- * Obtains default SSL socket factory with an SSL context based on the standard JSSE
- * trust material ({@code cacerts} file in the security properties directory).
- * System properties are not taken into consideration.
- *
- * @return default SSL socket factory
- */
- public static SSLConnectionSocketFactory getSocketFactory() throws
- SSLInitializationException {
- return new SSLConnectionSocketFactory(
- SSLContexts.createDefault(), getDefaultHostnameVerifier());
- }
-
- private static String[] split(final String s) {
- if (TextUtils.isBlank(s)) {
- return null;
- }
- return s.split(" *, *");
- }
-
- /**
- * Obtains default SSL socket factory with an SSL context based on system properties
- * as described in
- *
- * Java™ Secure Socket Extension (JSSE) Reference Guide.
- *
- * @return default system SSL socket factory
- */
- public static SSLConnectionSocketFactory getSystemSocketFactory() throws
- SSLInitializationException {
- return new SSLConnectionSocketFactory(
- (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
- split(System.getProperty("https.protocols")),
- split(System.getProperty("https.cipherSuites")),
- getDefaultHostnameVerifier());
- }
-
- private final javax.net.ssl.SSLSocketFactory socketfactory;
- private final HostnameVerifier hostnameVerifier;
- private final String[] supportedProtocols;
- private final String[] supportedCipherSuites;
-
- public SSLConnectionSocketFactory(final SSLContext sslContext) {
- this(sslContext, getDefaultHostnameVerifier());
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
- * HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- null, null, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
- * String[], String[], HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final SSLContext sslContext,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final X509HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- supportedProtocols, supportedCipherSuites, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
- * HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final X509HostnameVerifier hostnameVerifier) {
- this(socketfactory, null, null, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
- * String[], String[], HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final X509HostnameVerifier hostnameVerifier) {
- this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- null, null, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final SSLContext sslContext,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- supportedProtocols, supportedCipherSuites, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final HostnameVerifier hostnameVerifier) {
- this(socketfactory, null, null, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final HostnameVerifier hostnameVerifier) {
- this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
- this.supportedProtocols = supportedProtocols;
- this.supportedCipherSuites = supportedCipherSuites;
- this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
- }
-
- /**
- * Performs any custom initialization for a newly created SSLSocket
- * (before the SSL handshake happens).
- *
- * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
- * trusted certificates and to authenticate to the HTTPS server using a private key.
- *
- * SSLSocketFactory will enable server authentication when supplied with
- * a {@link java.security.KeyStore trust-store} file containing one or several trusted certificates. The client
- * secure socket will reject the connection during the SSL session handshake if the target HTTPS
- * server attempts to authenticate itself with a non-trusted certificate.
- *
- * Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
- *
- * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- *
- *
- * In special cases the standard trust verification process can be bypassed by using a custom
- * {@link org.apache.http.conn.ssl.TrustStrategy}. This interface is primarily intended for allowing self-signed
- * certificates to be accepted as trusted without having to add them to the trust-store file.
- *
- * SSLSocketFactory will enable client authentication when supplied with
- * a {@link java.security.KeyStore key-store} file containing a private key/public certificate
- * pair. The client secure socket will use the private key to authenticate
- * itself to the target HTTPS server during the SSL session handshake if
- * requested to do so by the server.
- * The target HTTPS server will in its turn verify the certificate presented
- * by the client in order to establish client's authenticity.
- *
- * Use the following sequence of actions to generate a key-store file
- *
- *
- *
- *
- * Use JDK keytool utility to generate a new key
- *
- * For simplicity use the same password for the key as that of the key-store
- *
- *
- *
- *
- * Issue a certificate signing request (CSR)
- *
- *
keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
- *
- *
- *
- * Send the certificate request to the trusted Certificate Authority for signature.
- * One may choose to act as her own CA and sign the certificate request using a PKI
- * tool, such as OpenSSL.
- *
- *
- *
- *
- * Import the trusted CA root certificate
- *
- *
keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
- *
- *
- *
- * Import the PKCS#7 file containing the complete certificate chain
- *
- *
keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
- *
- *
- *
- * Verify the content of the resultant keystore file
- *
- *
keytool -list -v -keystore my.keystore
- *
- *
- *
- * @since 4.3
- */
-// @ThreadSafe @SuppressWarnings("deprecation")
-public class SSLConnectionSocketFactory implements
- LayeredConnectionSocketFactory {
- private final static String TAG = "HttpClient";
- public static final String TLS = "TLS";
- public static final String SSL = "SSL";
- public static final String SSLV2 = "SSLv2";
-
-/*
- @Deprecated
- public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
- = AllowAllHostnameVerifier.INSTANCE;
- @Deprecated
- public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
- = BrowserCompatHostnameVerifier.INSTANCE;
- @Deprecated
- public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
- = StrictHostnameVerifier.INSTANCE;
-*/
-
-// private final Log log = LogFactory.getLog(getClass());
-
- /**
- * @since 4.4
- */
- public static HostnameVerifier getDefaultHostnameVerifier() {
- return new DefaultHostnameVerifier(
- PublicSuffixMatcherLoader.getDefault());
- }
-
- /**
- * Obtains default SSL socket factory with an SSL context based on the standard JSSE
- * trust material ({@code cacerts} file in the security properties directory).
- * System properties are not taken into consideration.
- *
- * @return default SSL socket factory
- */
- public static SSLConnectionSocketFactory getSocketFactory() throws
- SSLInitializationException {
- return new SSLConnectionSocketFactory(
- SSLContexts.createDefault(), getDefaultHostnameVerifier());
- }
-
- private static String[] split(final String s) {
- if (TextUtils.isBlank(s)) {
- return null;
- }
- return s.split(" *, *");
- }
-
- /**
- * Obtains default SSL socket factory with an SSL context based on system properties
- * as described in
- *
- * Java™ Secure Socket Extension (JSSE) Reference Guide.
- *
- * @return default system SSL socket factory
- */
- public static SSLConnectionSocketFactory getSystemSocketFactory() throws
- SSLInitializationException {
- return new SSLConnectionSocketFactory(
- (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
- split(System.getProperty("https.protocols")),
- split(System.getProperty("https.cipherSuites")),
- getDefaultHostnameVerifier());
- }
-
- private final javax.net.ssl.SSLSocketFactory socketfactory;
- private final HostnameVerifier hostnameVerifier;
- private final String[] supportedProtocols;
- private final String[] supportedCipherSuites;
-
- public SSLConnectionSocketFactory(final SSLContext sslContext) {
- this(sslContext, getDefaultHostnameVerifier());
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
- * HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- null, null, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
- * String[], String[], HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final SSLContext sslContext,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final X509HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- supportedProtocols, supportedCipherSuites, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
- * HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final X509HostnameVerifier hostnameVerifier) {
- this(socketfactory, null, null, hostnameVerifier);
- }
-
- /**
- * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
- * String[], String[], HostnameVerifier)}
- */
- @Deprecated
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final X509HostnameVerifier hostnameVerifier) {
- this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- null, null, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final SSLContext sslContext,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final HostnameVerifier hostnameVerifier) {
- this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
- supportedProtocols, supportedCipherSuites, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final HostnameVerifier hostnameVerifier) {
- this(socketfactory, null, null, hostnameVerifier);
- }
-
- /**
- * @since 4.4
- */
- public SSLConnectionSocketFactory(
- final javax.net.ssl.SSLSocketFactory socketfactory,
- final String[] supportedProtocols,
- final String[] supportedCipherSuites,
- final HostnameVerifier hostnameVerifier) {
- this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
- this.supportedProtocols = supportedProtocols;
- this.supportedCipherSuites = supportedCipherSuites;
- this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
- }
-
- /**
- * Performs any custom initialization for a newly created SSLSocket
- * (before the SSL handshake happens).
- *
- * The default implementation is a no-op, but could be overridden to, e.g.,
- * call {@link SSLSocket#setEnabledCipherSuites(String[])}.
- *
- * @throws IOException may be thrown if overridden
- */
- protected void prepareSocket(final SSLSocket socket) throws IOException {
- }
-
- @Override
- public Socket createSocket(final HttpContext context) throws IOException {
- return SocketFactory.getDefault().createSocket();
- }
-
- @Override
- public Socket connectSocket(
- final int connectTimeout,
- final Socket socket,
- final HttpHost host,
- final InetSocketAddress remoteAddress,
- final InetSocketAddress localAddress,
- final HttpContext context) throws IOException {
- Args.notNull(host, "HTTP host");
- Args.notNull(remoteAddress, "Remote address");
- final Socket sock = socket != null ? socket : createSocket(context);
- if (localAddress != null) {
- sock.bind(localAddress);
- }
- try {
- if (connectTimeout > 0 && sock.getSoTimeout() == 0) {
- sock.setSoTimeout(connectTimeout);
- }
-/*
- if (this.log.isDebugEnabled()) {
- this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);
- }
-*/
- sock.connect(remoteAddress, connectTimeout);
- } catch (final IOException ex) {
- try {
- sock.close();
- } catch (final IOException ignore) {
- }
- throw ex;
- }
- // Setup SSL layering if necessary
- if (sock instanceof SSLSocket) {
- final SSLSocket sslsock = (SSLSocket) sock;
-// this.log.debug("Starting handshake");
- sslsock.startHandshake();
- verifyHostname(sslsock, host.getHostName());
- return sock;
- } else {
- return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
- }
- }
-
- @Override
- public Socket createLayeredSocket(
- final Socket socket,
- final String target,
- final int port,
- final HttpContext context) throws IOException {
- final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket(
- socket,
- target,
- port,
- true);
- if (supportedProtocols != null) {
- sslsock.setEnabledProtocols(supportedProtocols);
- } else {
- // If supported protocols are not explicitly set, remove all SSL protocol versions
- final String[] allProtocols = sslsock.getEnabledProtocols();
- final List enabledProtocols = new ArrayList(allProtocols.length);
- for (String protocol : allProtocols) {
- if (!protocol.startsWith("SSL")) {
- enabledProtocols.add(protocol);
- }
- }
- if (!enabledProtocols.isEmpty()) {
- sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
- }
- }
- if (supportedCipherSuites != null) {
- sslsock.setEnabledCipherSuites(supportedCipherSuites);
- }
-
-/*
- if (this.log.isDebugEnabled()) {
- this.log.debug("Enabled protocols: " + Arrays.asList(sslsock.getEnabledProtocols()));
- this.log.debug("Enabled cipher suites:" + Arrays.asList(sslsock.getEnabledCipherSuites()));
- }
-*/
-
- prepareSocket(sslsock);
-
- // Android specific code to enable SNI
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Enabling SNI for " + target);
- }
- try {
- Method method = sslsock.getClass().getMethod("setHostname", String.class);
- method.invoke(sslsock, target);
- } catch (Exception ex) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "SNI configuration failed", ex);
- }
- }
- }
- // End of Android specific code
-
-// this.log.debug("Starting handshake");
- sslsock.startHandshake();
- verifyHostname(sslsock, target);
- return sslsock;
- }
-
- private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
- try {
- SSLSession session = sslsock.getSession();
- if (session == null) {
- // In our experience this only happens under IBM 1.4.x when
- // spurious (unrelated) certificates show up in the server'
- // chain. Hopefully this will unearth the real problem:
- final InputStream in = sslsock.getInputStream();
- in.available();
- // If ssl.getInputStream().available() didn't cause an
- // exception, maybe at least now the session is available?
- session = sslsock.getSession();
- if (session == null) {
- // If it's still null, probably a startHandshake() will
- // unearth the real problem.
- sslsock.startHandshake();
- session = sslsock.getSession();
- }
- }
- if (session == null) {
- throw new SSLHandshakeException("SSL session not available");
- }
-
-/*
- if (this.log.isDebugEnabled()) {
- this.log.debug("Secure session established");
- this.log.debug(" negotiated protocol: " + session.getProtocol());
- this.log.debug(" negotiated cipher suite: " + session.getCipherSuite());
- try {
- final Certificate[] certs = session.getPeerCertificates();
- final X509Certificate x509 = (X509Certificate) certs[0];
- final X500Principal peer = x509.getSubjectX500Principal();
- this.log.debug(" peer principal: " + peer.toString());
- final Collection> altNames1 = x509.getSubjectAlternativeNames();
- if (altNames1 != null) {
- final List altNames = new ArrayList();
- for (final List> aC : altNames1) {
- if (!aC.isEmpty()) {
- altNames.add((String) aC.get(1));
- }
- }
- this.log.debug(" peer alternative names: " + altNames);
- }
- final X500Principal issuer = x509.getIssuerX500Principal();
- this.log.debug(" issuer principal: " + issuer.toString());
- final Collection> altNames2 = x509.getIssuerAlternativeNames();
- if (altNames2 != null) {
- final List altNames = new ArrayList();
- for (final List> aC : altNames2) {
- if (!aC.isEmpty()) {
- altNames.add((String) aC.get(1));
- }
- }
- this.log.debug(" issuer alternative names: " + altNames);
- }
- } catch (Exception ignore) {
- }
- }
-*/
-
- if (!this.hostnameVerifier.verify(hostname, session)) {
- final Certificate[] certs = session.getPeerCertificates();
- final X509Certificate x509 = (X509Certificate) certs[0];
- final X500Principal x500Principal = x509.getSubjectX500Principal();
- throw new SSLPeerUnverifiedException("Host name '" + hostname + "' does not match " +
- "the certificate subject provided by the peer (" + x500Principal.toString() + ")");
- }
- // verifyHostName() didn't blowup - good!
- } catch (final IOException iox) {
- // close the socket before re-throwing the exception
- try {
- sslsock.close();
- } catch (final Exception x) { /*ignore*/ }
- throw iox;
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/StrongBuild.java b/app/src/main/java/com/example/myapplication/StrongBuild.java
deleted file mode 100644
index 9c5b512e..00000000
--- a/app/src/main/java/com/example/myapplication/StrongBuild.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.example.myapplication;
-
-import android.app.Activity;
-import android.content.Context;
-import android.util.Log;
-
-import javax.net.ssl.TrustManager;
-
-import android.webkit.WebView;
-import info.guardianproject.netcipher.client.StrongBuilder;
-import info.guardianproject.netcipher.client.StrongOkHttpClientBuilder;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-
-public class StrongBuild implements StrongBuilder.Callback {
-
- private static final StrongBuild ourInstance = new StrongBuild();
-
- public static StrongBuild getInstance() {
- return ourInstance;
- }
-
- public String url;
- public String htmlCode;
- public WebView view;
-
- public void loadURL(String url, WebView view, Context applicationContext){
- try{
- this.url = url;
- this.view = view;
- StrongOkHttpClientBuilder.
- forMaxSecurity(applicationContext).
- withTorValidation().
- withBestProxy().
- build(StrongBuild.this);
-
- }catch(Exception e){
- e.printStackTrace();
- Log.e("info", "ERROR");
- }
- }
-
- @Override
- public void onConnected(final OkHttpClient okHttpClient){
- Log.e("info" , "CONNECTED Strong Builder");
-
- view.loadDataWithBaseURL(null, "ASD", "text/html", "utf-8", null);
- new Thread(new Runnable(){
- @Override
- public void run(){
- try{
- Request request = new Request.Builder().url(url).build();
- Response response = okHttpClient.newCall(request).execute();
-
- Log.e("info", "RESPONSE: "+response.toString());
- Log.e("info", response.body().string());
- htmlCode = response.body().string();
-
- Log.d("LOADING : " ,"LOADING");
- view.loadDataWithBaseURL(null, htmlCode, "text/html", "utf-8", null);
-
- }catch(Exception e){
- e.printStackTrace();
- Log.e("info", "ERROR - ATTEMPTING CONNECTION TO ONION DOMAIN");
- }
- }
- }).start();
- }
-
- @Override
- public void onConnectionException(Exception e){
- Log.e("info" , "Exception");
- }
-
- @Override
- public void onTimeout(){
- Log.e("info" , "Timeout");
- }
-
- @Override
- public void onInvalid(){
- Log.e("info" , "Invalid");
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/applicationController.java b/app/src/main/java/com/example/myapplication/applicationController.java
index 0f90abb8..c1154258 100644
--- a/app/src/main/java/com/example/myapplication/applicationController.java
+++ b/app/src/main/java/com/example/myapplication/applicationController.java
@@ -1,13 +1,19 @@
package com.example.myapplication;
import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.Color;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
import android.os.Build;
import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
-import android.util.Log;
+import android.text.TextUtils;
import android.util.Patterns;
import android.view.KeyEvent;
import android.view.View;
@@ -17,11 +23,20 @@ import android.webkit.*;
import android.widget.*;
import java.io.IOException;
+import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Stack;
+import com.yarolegovich.lovelydialog.LovelyInfoDialog;
+import com.yarolegovich.lovelydialog.LovelyStandardDialog;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+import org.mozilla.gecko.PrefsHelper;
+import org.mozilla.geckoview.GeckoRuntime;
+import org.mozilla.geckoview.GeckoSession;
+import org.mozilla.geckoview.GeckoView;
+
import static java.lang.Thread.sleep;
public class applicationController extends AppCompatActivity
@@ -30,6 +45,7 @@ public class applicationController extends AppCompatActivity
/*View Objects*/
private WebView webView1;
private WebView webView2;
+ private GeckoView webLoader;
private ProgressBar progressBar;
private ConstraintLayout requestFailure;
private ConstraintLayout splashScreen;
@@ -37,40 +53,59 @@ public class applicationController extends AppCompatActivity
private ImageButton homeButton;
private EditText searchbar;
private LinearLayout topbar;
+ private GeckoSession session1;
+ private GeckoRuntime runtime1;
/*helper Variables*/
String currentURL = "http://boogle.store/";
boolean isRequestError = false;
boolean hasApplicationLoaded = false;
Stack urlList = new Stack();
- int scroll1y=0;
- int scroll2y=0;
+ boolean wasBackPressed = false;
+ boolean isFirstLaunch = true;
/*Initialization*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_application_controller);
- initializeView();
+ setContentView(R.layout.applicationView);
initializeProxy();
+ initializeView();
initializeAds();
}
- public void initializeProxy()
- {
- //torProxyServer.getInstance().initialize(this,this);
- }
-
public void initializeAds()
{
admanager.getInstance().initialize(this);
}
+ public void initializeProxy()
+ {
+ PrefsHelper.setPref("network.proxy.type",1); //manual proxy settings
+ PrefsHelper.setPref("network.proxy.socks","127.0.0.1"); //manual proxy settings
+ PrefsHelper.setPref("network.proxy.socks_port",9050); //manual proxy settings
+ PrefsHelper.setPref("network.proxy.socks_version",5); //manual proxy settings
+ PrefsHelper.setPref("network.proxy.socks_remote_dns",true); //manual proxy settings
+ PrefsHelper.setPref("browser.cache.disk.enable",false);
+ PrefsHelper.setPref("browser.cache.memory.enable",true);
+ PrefsHelper.setPref("browser.cache.disk.capacity",0);
+ PrefsHelper.setPref("general.useragent.override", "Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0");
+ PrefsHelper.setPref("privacy.donottrackheader.enabled",false);
+ PrefsHelper.setPref("privacy.donottrackheader.value",1);
+ }
+
/*Initialization*/
public void initializeView()
{
+ /*if (android.os.Build.VERSION.SDK_INT > 9)
+ {
+ StrictMode.ThreadPolicy policy = new
+ StrictMode.ThreadPolicy.Builder().permitAll().build();
+ StrictMode.setThreadPolicy(policy);
+ }*/
+
webView1 = (WebView) findViewById(R.id.pageLoader1);
webView2 = (WebView) findViewById(R.id.pageLoader2);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
@@ -80,8 +115,19 @@ public class applicationController extends AppCompatActivity
homeButton = (ImageButton) findViewById(R.id.home);
searchbar = (EditText) findViewById(R.id.search);
topbar = (LinearLayout) findViewById(R.id.topbar);
- webRequestHandler.getInstance().initialization(webView1,webView2,progressBar,searchbar,requestFailure);
+ webRequestHandler.getInstance().initialization(webView1,webView2,progressBar,searchbar,requestFailure,this);
webView1.bringToFront();
+ progressBar.animate().alpha(0f);
+
+ Intent orbot = OrbotHelper.getOrbotStartIntent(getApplicationContext());
+ getApplicationContext().registerReceiver(orbotStatusReceiver,new IntentFilter(OrbotHelper.ACTION_STATUS));
+ getApplicationContext().sendBroadcast(orbot);
+
+ session1 = new GeckoSession();
+ webLoader = (GeckoView) findViewById(R.id.webLoader);
+ runtime1 = GeckoRuntime.create(this);
+ session1.open(runtime1);
+ webLoader.setSession(session1);
webView2.animate().setDuration(0).alpha(0f);
progressBar.setVisibility(View.INVISIBLE);
@@ -91,18 +137,31 @@ public class applicationController extends AppCompatActivity
webView1.setBackgroundColor(Color.WHITE);
webView1.setWebViewClient(loadWebViewClient());
webView1.getSettings().setJavaScriptEnabled(true);
- webView1.loadUrl("http://boogle.store/");
+ webView1.getSettings().setUseWideViewPort(true);
+
+ loadURLAnimate("http://boogle.store/");
webView2.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webView2.setBackgroundColor(Color.WHITE);
webView2.setWebViewClient(loadWebViewClient());
webView2.getSettings().setJavaScriptEnabled(true);
+ webView2.getSettings().setUseWideViewPort(true);
requestFailure.animate().setDuration(0).alpha(0.0f);
initializeViewClients();
+ progressBar.animate().alpha(0f);
}
+ public void openSession()
+ {
+ session1 = new GeckoSession();
+ webLoader = (GeckoView) findViewById(R.id.webLoader);
+ GeckoRuntime runtime1 = GeckoRuntime.create(this);
+ session1.open(runtime1);
+ webLoader.setSession(session1);
+ }
+
private void initializeViewClients()
{
homeButton.setOnClickListener(new View.OnClickListener(){
@@ -110,8 +169,14 @@ public class applicationController extends AppCompatActivity
@Override
public void onClick(View v)
{
- webRequestHandler.getInstance().loadURL("http://boogle.store/");
- isRequestError = false;
+ session1.stop();
+ session1.close();
+ session1.stop();
+ progressBar.animate().alpha(0f);
+ progressBar.setVisibility(View.VISIBLE);
+ progressBar.animate().setDuration(300).alpha(1f);
+ loadURLAnimate("http://boogle.store/");
+ isRequestError = false;
}
});
@@ -122,11 +187,13 @@ public class applicationController extends AppCompatActivity
{
try
{
+ session1.stop();
+ session1.close();
String url = v.getText().toString();
- if(!url.startsWith("www.")&& !url.startsWith("http://")){
+ if(!url.startsWith("www.")&& !url.startsWith("http://")&& !url.startsWith("https://")){
url = "www."+url;
}
- if(!url.startsWith("http://")){
+ if(!url.startsWith("http://")&&!url.startsWith("https://")){
url = "http://"+url;
}
@@ -134,45 +201,65 @@ public class applicationController extends AppCompatActivity
boolean isUrlValid = Patterns.WEB_URL.matcher(url).matches();
URL host = new URL(url);
- Log.i("SUPER WOW",host.getHost());
if(isUrlValid && host.getHost().replace("www.","").contains("."))
{
- Log.i("WOW1","WOW1");
- if(host.getHost().contains(".onion")||host.getHost().contains("boogle.store")||host.getHost().contains("genesis.store"))
+ if(host.getHost().contains("boogle.store")||host.getHost().contains("genesis.store"))
{
- webRequestHandler.getInstance().loadURL(v.getText().toString());
+ loadURLAnimate(v.getText().toString());
+ return true;
+ }
+ else if(host.getHost().contains(".onion"))
+ {
+ if(!reinitOrbot())
+ {
+ session1.close();
+ session1 = new GeckoSession();
+ session1.open(runtime1);
+ session1.setProgressDelegate(new ExamplesProgressDelegate());
+ webLoader.releaseSession();
+ webLoader.setSession(session1);
+
+ session1.loadUri(url);
+ }
+ return true;
}
else
{
- Toast.makeText(getApplicationContext(), "Only onion urls allowed", Toast.LENGTH_SHORT).show();
+ baseURLError();
+ return true;
}
}
else
{
- webRequestHandler.getInstance().loadURL("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
+ loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
}
+ reinitOrbot();
+
}
catch (IOException e)
{
- webRequestHandler.getInstance().loadURL("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
+ loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
e.printStackTrace();
}
return false;
}
});
- Log.i("HELL1","HELL1");
reloadButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
- Log.i("HELL2","HELL2");
- webRequestHandler.getInstance().loadURL(currentURL);
+ progressBar.animate().alpha(0f);
+ progressBar.setVisibility(View.VISIBLE);
+ progressBar.animate().setDuration(300).alpha(1f);
+ loadURLAnimate(currentURL);
isRequestError = false;
}
});
+ session1.setProgressDelegate(new ExamplesProgressDelegate());
+
}
public static String getDomainName(String url) throws URISyntaxException
@@ -189,28 +276,116 @@ public class applicationController extends AppCompatActivity
}
+ public void baseURLError()
+ {
+ new LovelyInfoDialog(this)
+ .setTopColorRes(R.color.header)
+ .setIcon(R.drawable.logo)
+ .setTitle("Surface Web URL Not Allowed")
+ .setMessage("This software can only be used to search hidden web such as \"Onion\" and \"I2P\" for searching in Surface Web use \"Google\" or \"Bing\"")
+ .show();
+ }
+
+ public void startingOrbotInfo()
+ {
+ new LovelyInfoDialog(this)
+ .setTopColorRes(R.color.header)
+ .setIcon(R.drawable.logo)
+ .setTitle("Orbot is Starting")
+ .setMessage("Looks Like Orbot is Installed but not Running. Please wait while we Start Orbot for you")
+ .show();
+ }
+
+ public boolean reinitOrbot()
+ {
+ if(!OrbotHelper.isOrbotInstalled(this))
+ {
+ OrbotHelper.getOrbotInstallIntent(this);
+ new LovelyStandardDialog(this)
+ .setTopColorRes(R.color.header)
+ .setIcon(R.drawable.logo)
+ .setTitle("Orbot Proxy Not Installed")
+ .setMessage("Hidden Web can only be access by Special Proxies. Please Install Orbot Proxy from Playstore")
+ .setPositiveButton(android.R.string.ok, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final String appPackageName = "org.torproject.android"; // getPackageName() from Context or Activity object
+ try {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
+ } catch (android.content.ActivityNotFoundException anfe) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .show();
+ return true;
+ }
+ if(!isOrbotRunning)
+ {
+ OrbotHelper.get(this).init();
+ startingOrbotInfo();
+ return true;
+ }
+ return false;
+ }
+
@Override
public void onBackPressed()
{
+ reinitOrbot();
if(urlList.size()>0)
{
- boolean crul = !currentURL.equals("http://boogle.store/");
- boolean peek = !urlList.peek().equals("http://boogle.store/");
-
- Log.i("WOW",urlList.size() + "---" + urlList.peek() + "---" + currentURL + "---" + peek);
- currentURL = urlList.peek().toString();
-
- if(!currentURL.equals(urlList.peek()) && crul)
+ searchbar.setText(urlList.peek().toString().replaceAll("boogle.store","genesis.onion"));
+ if(urlList.peek().toString().contains("boogle.store"))
{
- webRequestHandler.getInstance().loadURL("http://boogle.store/");
+ if(!currentURL.contains("boogle.store"))
+ {
+ currentURL = urlList.pop().toString();
+ progressBar.animate().alpha(0f);
+ webLoader.animate().setDuration(250).alpha(0);
+ webLoader.setVisibility(View.INVISIBLE);
+ }
+ else
+ {
+ loadURLAnimate(urlList.pop().toString());
+ if(urlList.size()<=0)
+ {
+ currentURL = "http://boogle.store/";
+ }
+ else
+ {
+ currentURL = urlList.peek().toString();
+ }
+ }
}
else
{
- webRequestHandler.getInstance().loadURL(urlList.pop().toString());
+ wasBackPressed = true;
+ if(urlList.size()<=0 || urlList.peek().toString().contains("boogle.store"))
+ {
+ currentURL = "http://boogle.store/";
+ webLoader.animate().setDuration(250).alpha(0);
+ }
+ else
+ {
+ webLoader.animate().setDuration(250).alpha(1);
+ currentURL = urlList.peek().toString();
+ }
+ urlList.pop();
+ session1.stop();
+ session1.close();
+ session1.stop();
+ session1.goBack();
+ }
+ if(urlList.size()==0)
+ {
+ searchbar.setText("http://genesis.onion/");
}
}
}
+ private boolean isAnimating = false;
private WebViewClient loadWebViewClient()
{
WebViewClient client = new WebViewClient()
@@ -218,34 +393,67 @@ public class applicationController extends AppCompatActivity
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
- Log.i("OVERRIDING URL 1 : ","SUCCESS : " + view);
- System.out.println(url);
- if(!currentURL.equals(url))
- {
- urlList.add(currentURL);
- currentURL = url;
- }
+ searchbar.setText(url.replaceAll("boogle.store","genesis.onion"));
+
if(!url.toString().contains("boogle"))
{
- Log.i("OVERRIDING URL 2 : ","SUCCESS : " + url);
//admanager.getInstance().showAd();
- //StrongBuild.getInstance().loadURL("https://stackoverflow.com/questions/4543349/load-local-html-in-webview",view,getApplicationContext());
+
+ boolean init_status=reinitOrbot();
+ if(!init_status)
+ {
+ session1.close();
+ session1 = new GeckoSession();
+ session1.open(runtime1);
+ session1.setProgressDelegate(new ExamplesProgressDelegate());
+ webLoader.releaseSession();
+ webLoader.setSession(session1);
+
+ session1.loadUri(url);
+ }
+ return true;
}
else
{
- Log.i("OVERRIDING URL 3 : ","SUCCESS : " + url);
- webRequestHandler.getInstance().loadURL(url);
+ if(urlList.size()==0 || !currentURL.equals(urlList.peek()))
+ {
+ urlList.add(currentURL);
+ currentURL = url;
+ }
+
+ loadURLAnimate(url);
return true;
}
- return false;
}
@Override
public void onPageFinished(WebView view, String url)
{
- Log.i("APPLIED : ","SUCCESS : APPLIED");
super.onPageFinished(view, url);
+
webView1.animate().setDuration(250).alpha(1f);
- webView2.animate().setDuration(250).alpha(1f);
+ webView2.animate().setDuration(250).alpha(1f).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ datamodel.getInstance().setIsLoadingURL(false);
+ requestFailure.animate().alpha(0f).setDuration(300).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ requestFailure.setVisibility(View.INVISIBLE);
+ }
+ }));;
+
+ }
+ }));;
+
+ progressBar.animate().alpha(0f).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ progressBar.setVisibility(View.INVISIBLE);
+ }
+ }));;
if(!hasApplicationLoaded)
{
@@ -258,7 +466,7 @@ public class applicationController extends AppCompatActivity
e.printStackTrace();
}
hasApplicationLoaded = true;
- splashScreen.animate().alpha(0.0f).setDuration(500).setListener(null).withEndAction((new Runnable() {
+ splashScreen.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((new Runnable() {
@Override
public void run()
{
@@ -268,7 +476,7 @@ public class applicationController extends AppCompatActivity
}
if(!isRequestError)
{
- requestFailure.animate().alpha(0.0f).setDuration(500).setListener(null).withEndAction((new Runnable() {
+ requestFailure.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((new Runnable() {
@Override
public void run()
{
@@ -286,7 +494,6 @@ public class applicationController extends AppCompatActivity
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
{
- Log.i("SUPME3 : ","ERROR");
//reloadButton.setEnabled(true);
System.out.println("SUP2");
requestFailure.setVisibility(View.VISIBLE);
@@ -297,7 +504,136 @@ public class applicationController extends AppCompatActivity
}
};
+ if(!isNetworkAvailable())
+ {
+ hasApplicationLoaded = true;
+ splashScreen.animate().setStartDelay(2000).alpha(0.0f).setDuration(300).setListener(null).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ splashScreen.setVisibility(View.GONE);
+ }
+ }));
+
+ requestFailure.setVisibility(View.VISIBLE);
+ requestFailure.animate().alpha(1.0f);
+ isRequestError = true;
+ }
+
return client;
}
+ public void loadURLAnimate(String url)
+ {
+ if(!isAnimating)
+ {
+ webRequestHandler.getInstance().loadURL(url);
+ }
+ }
+boolean isPageLoaded = false;
+class ExamplesProgressDelegate implements GeckoSession.ProgressDelegate
+{
+ @Override
+ public void onPageStart(GeckoSession session, String url)
+ {
+ try
+ {
+ URL host = new URL(url);
+ if(!host.getHost().contains("onion"))
+ {
+ session1.stop();
+ session1.close();
+ session1.stop();
+ baseURLError();
+ }
+ }
+ catch (MalformedURLException e)
+ {
+ e.printStackTrace();
+ }
+
+ isPageLoaded = false;
+ datamodel.getInstance().setIsLoadingURL(true);
+ boolean isBlackPage = url.equals("about:blank");
+ if(!isBlackPage &&!wasBackPressed)
+ {
+ urlList.add(currentURL);
+ currentURL = url;
+ }
+ wasBackPressed = false;
+ if(!isBlackPage)
+ {
+ progressBar.setAlpha(0);
+ progressBar.setVisibility(View.VISIBLE);
+ progressBar.animate().setDuration(300).alpha(1f);
+ }
+ }
+ @Override
+ public void onPageStop(GeckoSession session, boolean success)
+ {
+ progressBar.animate().alpha(0f);
+ datamodel.getInstance().setIsLoadingURL(false);
+ }
+
+ @Override
+ public void onProgressChange(GeckoSession session, int progress)
+ {
+ if(progress>=50 && !isPageLoaded)
+ {
+ isPageLoaded = true;
+ webLoader.bringToFront();
+ webLoader.animate().setDuration(100).alpha(1);
+ webLoader.setVisibility(View.VISIBLE);
+
+ requestFailure.animate().alpha(0f).setDuration(300).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ requestFailure.setVisibility(View.INVISIBLE);
+ }
+ }));;
+ }
+ }
+
+ @Override
+ public void onSecurityChange(GeckoSession session, SecurityInformation securityInfo)
+ {
+ }
+}
+
+ public boolean isNetworkAvailable()
+ {
+ ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ if (networkInfo != null && networkInfo.isConnected())
+ {
+ return true;
+ }
+ return false;
+ }
+
+ boolean isOrbotRunning = false;
+ private BroadcastReceiver orbotStatusReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TextUtils.equals(intent.getAction(),
+ OrbotHelper.ACTION_STATUS)) {
+ String status = intent.getStringExtra(OrbotHelper.EXTRA_STATUS);
+ if (status.equals(OrbotHelper.STATUS_ON))
+ {
+ isOrbotRunning = true;
+ }
+ else if (status.equals(OrbotHelper.STATUS_OFF))
+ {
+ isOrbotRunning = false;
+ }
+ else if (status.equals(OrbotHelper.STATUS_STARTING))
+ {
+ }
+ else if (status.equals(OrbotHelper.STATUS_STOPPING))
+ {
+ }
+ }
+ }
+ };
}
diff --git a/app/src/main/java/com/example/myapplication/datamodel.java b/app/src/main/java/com/example/myapplication/datamodel.java
new file mode 100644
index 00000000..caf77b39
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/datamodel.java
@@ -0,0 +1,27 @@
+package com.example.myapplication;
+
+public class datamodel
+{
+ private static final datamodel ourInstance = new datamodel();
+ private boolean isLoadingURL = false;
+
+ public static datamodel getInstance()
+ {
+ return ourInstance;
+ }
+
+ private datamodel()
+ {
+ }
+
+ public boolean getIsLoadingURL()
+ {
+ return isLoadingURL;
+ }
+
+ public void setIsLoadingURL(boolean status)
+ {
+ isLoadingURL = status;
+ }
+
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/NetCipher.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/NetCipher.java
new file mode 100644
index 00000000..663ba539
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/NetCipher.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2014-2016 Hans-Christoph Steiner
+ * Copyright 2012-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.myapplication.proxy.netcipher;
+
+import android.net.Uri;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URI;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+
+import info.guardianproject.netcipher.client.TlsOnlySocketFactory;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+
+public class NetCipher {
+ private static final String TAG = "NetCipher";
+
+ private NetCipher() {
+ // this is a utility class with only static methods
+ }
+
+ public final static Proxy ORBOT_HTTP_PROXY = new Proxy(Proxy.Type.HTTP,
+ new InetSocketAddress("127.0.0.1", 8118));
+
+ private static Proxy proxy;
+
+ /**
+ * Set the global HTTP proxy for all new {@link HttpURLConnection}s and
+ * {@link HttpsURLConnection}s that are created after this is called.
+ *
+ * {@link #useTor()} will override this setting. Traffic must be directed
+ * to Tor using the proxy settings, and Orbot has its own proxy settings
+ * for connections that need proxies to work. So if "use Tor" is enabled,
+ * as tested by looking for the static instance of Proxy, then no other
+ * proxy settings are allowed to override the current Tor proxy.
+ *
+ * @param host the IP address for the HTTP proxy to use globally
+ * @param port the port number for the HTTP proxy to use globally
+ */
+ public static void setProxy(String host, int port) {
+ if (!TextUtils.isEmpty(host) && port > 0) {
+ InetSocketAddress isa = new InetSocketAddress(host, port);
+ setProxy(new Proxy(Proxy.Type.HTTP, isa));
+ } else if (NetCipher.proxy != ORBOT_HTTP_PROXY) {
+ setProxy(null);
+ }
+ }
+
+ /**
+ * Set the global HTTP proxy for all new {@link HttpURLConnection}s and
+ * {@link HttpsURLConnection}s that are created after this is called.
+ *
+ * {@link #useTor()} will override this setting. Traffic must be directed
+ * to Tor using the proxy settings, and Orbot has its own proxy settings
+ * for connections that need proxies to work. So if "use Tor" is enabled,
+ * as tested by looking for the static instance of Proxy, then no other
+ * proxy settings are allowed to override the current Tor proxy.
+ *
+ * @param proxy the HTTP proxy to use globally
+ */
+ public static void setProxy(Proxy proxy) {
+ if (proxy != null && NetCipher.proxy == ORBOT_HTTP_PROXY) {
+ Log.w(TAG, "useTor is enabled, ignoring new proxy settings!");
+ } else {
+ NetCipher.proxy = proxy;
+ }
+ }
+
+ /**
+ * Get the currently active global HTTP {@link Proxy}.
+ *
+ * @return the active HTTP {@link Proxy}
+ */
+ public static Proxy getProxy() {
+ return proxy;
+ }
+
+ /**
+ * Clear the global HTTP proxy for all new {@link HttpURLConnection}s and
+ * {@link HttpsURLConnection}s that are created after this is called. This
+ * returns things to the default, proxy-less state.
+ */
+ public static void clearProxy() {
+ setProxy(null);
+ }
+
+ /**
+ * Set Orbot as the global HTTP proxy for all new {@link HttpURLConnection}
+ * s and {@link HttpsURLConnection}s that are created after this is called.
+ * This overrides all future calls to {@link #setProxy(Proxy)}, except to
+ * clear the proxy, e.g. {@code #setProxy(null)} or {@link #clearProxy()}.
+ *
+ * Traffic must be directed to Tor using the proxy settings, and Orbot has its
+ * own proxy settings for connections that need proxies to work. So if "use
+ * Tor" is enabled, as tested by looking for the static instance of Proxy,
+ * then no other proxy settings are allowed to override the current Tor proxy.
+ */
+ public static void useTor() {
+ setProxy(ORBOT_HTTP_PROXY);
+ }
+
+ /**
+ * Get a {@link TlsOnlySocketFactory} from NetCipher.
+ *
+ * @see HttpsURLConnection#setDefaultSSLSocketFactory(SSLSocketFactory)
+ */
+ public static TlsOnlySocketFactory getTlsOnlySocketFactory() {
+ return getTlsOnlySocketFactory(false);
+ }
+
+ /**
+ * Get a {@link TlsOnlySocketFactory} from NetCipher, and specify whether
+ * it should use a more compatible, but less strong, suite of ciphers.
+ *
+ * @see HttpsURLConnection#setDefaultSSLSocketFactory(SSLSocketFactory)
+ */
+ public static TlsOnlySocketFactory getTlsOnlySocketFactory(boolean compatible) {
+ SSLContext sslcontext;
+ try {
+ sslcontext = SSLContext.getInstance("TLSv1");
+ sslcontext.init(null, null, null);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(e);
+ } catch (KeyManagementException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return new TlsOnlySocketFactory(sslcontext.getSocketFactory(), compatible);
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a {@link URL}, and specify whether
+ * it should use a more compatible, but less strong, suite of ciphers.
+ *
+ * @param url
+ * @param compatible
+ * @return the {@code url} in an instance of {@link HttpURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getHttpURLConnection(URL url, boolean compatible)
+ throws IOException {
+ // .onion addresses only work via Tor, so force Tor for all of them
+ Proxy proxy = NetCipher.proxy;
+ if (OrbotHelper.isOnionAddress(url))
+ proxy = ORBOT_HTTP_PROXY;
+
+ HttpURLConnection connection;
+ if (proxy != null) {
+ connection = (HttpURLConnection) url.openConnection(proxy);
+ } else {
+ connection = (HttpURLConnection) url.openConnection();
+ }
+
+ if (connection instanceof HttpsURLConnection) {
+ HttpsURLConnection httpsConnection = ((HttpsURLConnection) connection);
+ SSLSocketFactory tlsOnly = getTlsOnlySocketFactory(compatible);
+ httpsConnection.setSSLSocketFactory(tlsOnly);
+ if (Build.VERSION.SDK_INT < 16) {
+ httpsConnection.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
+ }
+ }
+ return connection;
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a URL {@link String} using the best
+ * TLS configuration available on the device.
+ *
+ * @param urlString
+ * @return the URL in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getHttpsURLConnection(String urlString) throws IOException {
+ URL url = new URL(urlString.replaceFirst("^[Hh][Tt][Tt][Pp]:", "https:"));
+ return getHttpsURLConnection(url, false);
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a {@link Uri} using the best TLS
+ * configuration available on the device.
+ *
+ * @param uri
+ * @return the {@code uri} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getHttpsURLConnection(Uri uri) throws IOException {
+ return getHttpsURLConnection(uri.toString());
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a {@link URI} using the best TLS
+ * configuration available on the device.
+ *
+ * @param uri
+ * @return the {@code uri} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getHttpsURLConnection(URI uri) throws IOException {
+ if (TextUtils.equals(uri.getScheme(), "https"))
+ return getHttpsURLConnection(uri.toURL(), false);
+ else
+ // otherwise force scheme to https
+ return getHttpsURLConnection(uri.toString());
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a {@link URL} using the best TLS
+ * configuration available on the device.
+ *
+ * @param url
+ * @return the {@code url} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getHttpsURLConnection(URL url) throws IOException {
+ return getHttpsURLConnection(url, false);
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a {@link URL} using a more
+ * compatible, but less strong, suite of ciphers.
+ *
+ * @param url
+ * @return the {@code url} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getCompatibleHttpsURLConnection(URL url) throws IOException {
+ return getHttpsURLConnection(url, true);
+ }
+
+ /**
+ * Get a {@link HttpsURLConnection} from a {@link URL}, and specify whether
+ * it should use a more compatible, but less strong, suite of ciphers.
+ *
+ * @param url
+ * @param compatible
+ * @return the {@code url} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect,
+ * or if an HTTP URL is given that does not support HTTPS
+ */
+ public static HttpsURLConnection getHttpsURLConnection(URL url, boolean compatible)
+ throws IOException {
+ // use default method, but enforce a HttpsURLConnection
+ HttpURLConnection connection = getHttpURLConnection(url, compatible);
+ if (connection instanceof HttpsURLConnection) {
+ return (HttpsURLConnection) connection;
+ } else {
+ throw new IllegalArgumentException("not an HTTPS connection!");
+ }
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a {@link URL}. If the connection is
+ * {@code https://}, it will use a more compatible, but less strong, TLS
+ * configuration.
+ *
+ * @param url
+ * @return the {@code url} in an instance of {@link HttpsURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getCompatibleHttpURLConnection(URL url) throws IOException {
+ return getHttpURLConnection(url, true);
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a URL {@link String}. If it is an
+ * {@code https://} link, then this will use the best TLS configuration
+ * available on the device.
+ *
+ * @param urlString
+ * @return the URL in an instance of {@link HttpURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getHttpURLConnection(String urlString) throws IOException {
+ return getHttpURLConnection(new URL(urlString));
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a {@link Uri}. If it is an
+ * {@code https://} link, then this will use the best TLS configuration
+ * available on the device.
+ *
+ * @param uri
+ * @return the {@code uri} in an instance of {@link HttpURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getHttpURLConnection(Uri uri) throws IOException {
+ return getHttpURLConnection(uri.toString());
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a {@link URI}. If it is an
+ * {@code https://} link, then this will use the best TLS configuration
+ * available on the device.
+ *
+ * @param uri
+ * @return the {@code uri} in an instance of {@link HttpURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getHttpURLConnection(URI uri) throws IOException {
+ return getHttpURLConnection(uri.toURL());
+ }
+
+ /**
+ * Get a {@link HttpURLConnection} from a {@link URL}. If it is an
+ * {@code https://} link, then this will use the best TLS configuration
+ * available on the device.
+ *
+ * @param url
+ * @return the {@code url} in an instance of {@link HttpURLConnection}
+ * @throws IOException
+ * @throws IllegalArgumentException if the proxy or TLS setup is incorrect
+ */
+ public static HttpURLConnection getHttpURLConnection(URL url) throws IOException {
+ return (HttpURLConnection) getHttpURLConnection(url, false);
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/WebkitProxy.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/WebkitProxy.java
new file mode 100644
index 00000000..c081039b
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/WebkitProxy.java
@@ -0,0 +1,754 @@
+package com.example.myapplication.proxy.netcipher;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Proxy;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.webkit.WebView;
+
+import org.apache.http.HttpHost;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+public class WebkitProxy {
+
+ private final static String DEFAULT_HOST = "localhost";//"127.0.0.1";
+ private final static int DEFAULT_PORT = 8118;
+ private final static int DEFAULT_SOCKS_PORT = 9050;
+
+ private final static int REQUEST_CODE = 0;
+
+ private final static String TAG = "OrbotHelpher";
+
+ public static boolean setProxy(String appClass, Context ctx, WebView wView, String host, int port) throws Exception {
+
+ setSystemProperties(host, port);
+
+ boolean worked = false;
+
+ if (Build.VERSION.SDK_INT < 13) {
+// worked = setWebkitProxyGingerbread(ctx, host, port);
+ setProxyUpToHC(wView, host, port);
+ } else if (Build.VERSION.SDK_INT < 19) {
+ worked = setWebkitProxyICS(ctx, host, port);
+ } else if (Build.VERSION.SDK_INT < 20) {
+ worked = setKitKatProxy(appClass, ctx, host, port);
+
+ if (!worked) //some kitkat's still use ICS browser component (like Cyanogen 11)
+ worked = setWebkitProxyICS(ctx, host, port);
+
+ } else if (Build.VERSION.SDK_INT >= 21) {
+ worked = setWebkitProxyLollipop(ctx, host, port);
+
+ }
+
+ return worked;
+ }
+
+ private static void setSystemProperties(String host, int port) {
+
+ System.setProperty("proxyHost", host);
+ System.setProperty("proxyPort", Integer.toString(port));
+
+ System.setProperty("http.proxyHost", host);
+ System.setProperty("http.proxyPort", Integer.toString(port));
+
+ System.setProperty("https.proxyHost", host);
+ System.setProperty("https.proxyPort", Integer.toString(port));
+
+
+ System.setProperty("socks.proxyHost", host);
+ System.setProperty("socks.proxyPort", Integer.toString(DEFAULT_SOCKS_PORT));
+
+ System.setProperty("socksProxyHost", host);
+ System.setProperty("socksProxyPort", Integer.toString(DEFAULT_SOCKS_PORT));
+
+
+ /*
+ ProxySelector pSelect = new ProxySelector();
+ pSelect.addProxy(Proxy.Type.HTTP, host, port);
+ ProxySelector.setDefault(pSelect);
+ */
+ /*
+ System.setProperty("http_proxy", "http://" + host + ":" + port);
+ System.setProperty("proxy-server", "http://" + host + ":" + port);
+ System.setProperty("host-resolver-rules","MAP * 0.0.0.0 , EXCLUDE myproxy");
+ System.getProperty("networkaddress.cache.ttl", "-1");
+ */
+
+ }
+
+ private static void resetSystemProperties() {
+
+ System.setProperty("proxyHost", "");
+ System.setProperty("proxyPort", "");
+
+ System.setProperty("http.proxyHost", "");
+ System.setProperty("http.proxyPort", "");
+
+ System.setProperty("https.proxyHost", "");
+ System.setProperty("https.proxyPort", "");
+
+
+ System.setProperty("socks.proxyHost", "");
+ System.setProperty("socks.proxyPort", Integer.toString(DEFAULT_SOCKS_PORT));
+
+ System.setProperty("socksProxyHost", "");
+ System.setProperty("socksProxyPort", Integer.toString(DEFAULT_SOCKS_PORT));
+
+ }
+
+ /**
+ * Override WebKit Proxy settings
+ *
+ * @param ctx Android ApplicationContext
+ * @param host
+ * @param port
+ * @return true if Proxy was successfully set
+ */
+ private static boolean setWebkitProxyGingerbread(Context ctx, String host, int port)
+ throws Exception {
+
+ boolean ret = false;
+
+ Object requestQueueObject = getRequestQueue(ctx);
+ if (requestQueueObject != null) {
+ // Create Proxy config object and set it into request Q
+ HttpHost httpHost = new HttpHost(host, port, "http");
+ setDeclaredField(requestQueueObject, "mProxyHost", httpHost);
+ return true;
+ }
+ return false;
+
+ }
+
+
+ /**
+ * Set Proxy for Android 3.2 and below.
+ */
+ @SuppressWarnings("all")
+ private static boolean setProxyUpToHC(WebView webview, String host, int port) {
+ Log.d(TAG, "Setting proxy with <= 3.2 API.");
+
+ HttpHost proxyServer = new HttpHost(host, port);
+ // Getting network
+ Class networkClass = null;
+ Object network = null;
+ try {
+ networkClass = Class.forName("android.webkit.Network");
+ if (networkClass == null) {
+ Log.e(TAG, "failed to get class for android.webkit.Network");
+ return false;
+ }
+ Method getInstanceMethod = networkClass.getMethod("getInstance", Context.class);
+ if (getInstanceMethod == null) {
+ Log.e(TAG, "failed to get getInstance method");
+ }
+ network = getInstanceMethod.invoke(networkClass, new Object[]{webview.getContext()});
+ } catch (Exception ex) {
+ Log.e(TAG, "error getting network: " + ex);
+ return false;
+ }
+ if (network == null) {
+ Log.e(TAG, "error getting network: network is null");
+ return false;
+ }
+ Object requestQueue = null;
+ try {
+ Field requestQueueField = networkClass
+ .getDeclaredField("mRequestQueue");
+ requestQueue = getFieldValueSafely(requestQueueField, network);
+ } catch (Exception ex) {
+ Log.e(TAG, "error getting field value");
+ return false;
+ }
+ if (requestQueue == null) {
+ Log.e(TAG, "Request queue is null");
+ return false;
+ }
+ Field proxyHostField = null;
+ try {
+ Class requestQueueClass = Class.forName("android.net.http.RequestQueue");
+ proxyHostField = requestQueueClass
+ .getDeclaredField("mProxyHost");
+ } catch (Exception ex) {
+ Log.e(TAG, "error getting proxy host field");
+ return false;
+ }
+
+ boolean temp = proxyHostField.isAccessible();
+ try {
+ proxyHostField.setAccessible(true);
+ proxyHostField.set(requestQueue, proxyServer);
+ } catch (Exception ex) {
+ Log.e(TAG, "error setting proxy host");
+ } finally {
+ proxyHostField.setAccessible(temp);
+ }
+
+ Log.d(TAG, "Setting proxy with <= 3.2 API successful!");
+ return true;
+ }
+
+
+ private static Object getFieldValueSafely(Field field, Object classInstance) throws IllegalArgumentException, IllegalAccessException {
+ boolean oldAccessibleValue = field.isAccessible();
+ field.setAccessible(true);
+ Object result = field.get(classInstance);
+ field.setAccessible(oldAccessibleValue);
+ return result;
+ }
+
+ private static boolean setWebkitProxyICS(Context ctx, String host, int port) {
+
+ // PSIPHON: added support for Android 4.x WebView proxy
+ try {
+ Class webViewCoreClass = Class.forName("android.webkit.WebViewCore");
+
+ Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
+ if (webViewCoreClass != null && proxyPropertiesClass != null) {
+ Method m = webViewCoreClass.getDeclaredMethod("sendStaticMessage", Integer.TYPE,
+ Object.class);
+ Constructor c = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE,
+ String.class);
+
+ if (m != null && c != null) {
+ m.setAccessible(true);
+ c.setAccessible(true);
+ Object properties = c.newInstance(host, port, null);
+
+ // android.webkit.WebViewCore.EventHub.PROXY_CHANGED = 193;
+ m.invoke(null, 193, properties);
+
+
+ return true;
+ }
+
+
+ }
+ } catch (Exception e) {
+ Log.e("ProxySettings",
+ "Exception setting WebKit proxy through android.net.ProxyProperties: "
+ + e.toString());
+ } catch (Error e) {
+ Log.e("ProxySettings",
+ "Exception setting WebKit proxy through android.webkit.Network: "
+ + e.toString());
+ }
+
+ return false;
+
+ }
+
+ @TargetApi(19)
+ public static boolean resetKitKatProxy(String appClass, Context appContext) {
+
+ return setKitKatProxy(appClass, appContext, null, 0);
+ }
+
+ @TargetApi(19)
+ private static boolean setKitKatProxy(String appClass, Context appContext, String host, int port) {
+ //Context appContext = webView.getContext().getApplicationContext();
+
+ try {
+ Class applictionCls = Class.forName(appClass);
+ Field loadedApkField = applictionCls.getField("mLoadedApk");
+ loadedApkField.setAccessible(true);
+ Object loadedApk = loadedApkField.get(appContext);
+ Class loadedApkCls = Class.forName("android.app.LoadedApk");
+ Field receiversField = loadedApkCls.getDeclaredField("mReceivers");
+ receiversField.setAccessible(true);
+ ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
+ for (Object receiverMap : receivers.values()) {
+ for (Object rec : ((ArrayMap) receiverMap).keySet()) {
+ Class clazz = rec.getClass();
+ if (clazz.getName().contains("ProxyChangeListener")) {
+ Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
+ Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+
+ if (host != null) {
+ /*********** optional, may be need in future *************/
+ final String CLASS_NAME = "android.net.ProxyProperties";
+ Class cls = Class.forName(CLASS_NAME);
+ Constructor constructor = cls.getConstructor(String.class, Integer.TYPE, String.class);
+ constructor.setAccessible(true);
+ Object proxyProperties = constructor.newInstance(host, port, null);
+ intent.putExtra("proxy", (Parcelable) proxyProperties);
+ /*********** optional, may be need in future *************/
+ }
+
+ onReceiveMethod.invoke(rec, appContext, intent);
+ }
+ }
+ }
+ return true;
+ } catch (ClassNotFoundException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (NoSuchFieldException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (IllegalAccessException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (IllegalArgumentException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (NoSuchMethodException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (InvocationTargetException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ } catch (InstantiationException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ String exceptionAsString = sw.toString();
+ Log.v(TAG, e.getMessage());
+ Log.v(TAG, exceptionAsString);
+ }
+ return false;
+ }
+
+ @TargetApi(21)
+ public static boolean resetLollipopProxy(String appClass, Context appContext) {
+
+ return setWebkitProxyLollipop(appContext, null, 0);
+ }
+
+ // http://stackanswers.com/questions/25272393/android-webview-set-proxy-programmatically-on-android-l
+ @TargetApi(21) // for android.util.ArrayMap methods
+ @SuppressWarnings("rawtypes")
+ private static boolean setWebkitProxyLollipop(Context appContext, String host, int port) {
+
+ try {
+ Class applictionClass = Class.forName("android.app.Application");
+ Field mLoadedApkField = applictionClass.getDeclaredField("mLoadedApk");
+ mLoadedApkField.setAccessible(true);
+ Object mloadedApk = mLoadedApkField.get(appContext);
+ Class loadedApkClass = Class.forName("android.app.LoadedApk");
+ Field mReceiversField = loadedApkClass.getDeclaredField("mReceivers");
+ mReceiversField.setAccessible(true);
+ ArrayMap receivers = (ArrayMap) mReceiversField.get(mloadedApk);
+ for (Object receiverMap : receivers.values()) {
+ for (Object receiver : ((ArrayMap) receiverMap).keySet()) {
+ Class clazz = receiver.getClass();
+ if (clazz.getName().contains("ProxyChangeListener")) {
+ Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
+ Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+ Object proxyInfo = null;
+ if (host != null) {
+ final String CLASS_NAME = "android.net.ProxyInfo";
+ Class cls = Class.forName(CLASS_NAME);
+ Method buildDirectProxyMethod = cls.getMethod("buildDirectProxy", String.class, Integer.TYPE);
+ proxyInfo = buildDirectProxyMethod.invoke(cls, host, port);
+ }
+ intent.putExtra("proxy", (Parcelable) proxyInfo);
+ onReceiveMethod.invoke(receiver, appContext, intent);
+ }
+ }
+ }
+ return true;
+ } catch (ClassNotFoundException e) {
+ Log.d("ProxySettings", "Exception setting WebKit proxy on Lollipop through ProxyChangeListener: " + e.toString());
+ } catch (NoSuchFieldException e) {
+ Log.d("ProxySettings", "Exception setting WebKit proxy on Lollipop through ProxyChangeListener: " + e.toString());
+ } catch (IllegalAccessException e) {
+ Log.d("ProxySettings", "Exception setting WebKit proxy on Lollipop through ProxyChangeListener: " + e.toString());
+ } catch (NoSuchMethodException e) {
+ Log.d("ProxySettings", "Exception setting WebKit proxy on Lollipop through ProxyChangeListener: " + e.toString());
+ } catch (InvocationTargetException e) {
+ Log.d("ProxySettings", "Exception setting WebKit proxy on Lollipop through ProxyChangeListener: " + e.toString());
+ }
+ return false;
+ }
+
+ private static boolean sendProxyChangedIntent(Context ctx, String host, int port) {
+
+ try {
+ Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
+ if (proxyPropertiesClass != null) {
+ Constructor c = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE,
+ String.class);
+
+ if (c != null) {
+ c.setAccessible(true);
+ Object properties = c.newInstance(host, port, null);
+
+ Intent intent = new Intent(android.net.Proxy.PROXY_CHANGE_ACTION);
+ intent.putExtra("proxy", (Parcelable) properties);
+ ctx.sendBroadcast(intent);
+
+ }
+
+ }
+ } catch (Exception e) {
+ Log.e("ProxySettings",
+ "Exception sending Intent ", e);
+ } catch (Error e) {
+ Log.e("ProxySettings",
+ "Exception sending Intent ", e);
+ }
+
+ return false;
+
+ }
+
+ /**
+ private static boolean setKitKatProxy0(Context ctx, String host, int port)
+ {
+ try
+ {
+ Class cmClass = Class.forName("android.net.ConnectivityManager");
+ Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
+ if (cmClass != null && proxyPropertiesClass != null)
+ {
+ Constructor c = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE,
+ String.class);
+ if (c != null)
+ {
+ c.setAccessible(true);
+ Object proxyProps = c.newInstance(host, port, null);
+ ConnectivityManager cm =
+ (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
+ Method mSetGlobalProxy = cmClass.getDeclaredMethod("setGlobalProxy", proxyPropertiesClass);
+ mSetGlobalProxy.invoke(cm, proxyProps);
+ return true;
+ }
+ }
+ } catch (Exception e)
+ {
+ Log.e("ProxySettings",
+ "ConnectivityManager.setGlobalProxy ",e);
+ }
+ return false;
+ }
+ */
+ //CommandLine.initFromFile(COMMAND_LINE_FILE);
+
+ /**
+ * private static boolean setKitKatProxy2 (Context ctx, String host, int port)
+ * {
+ *
+ * return false;
+ * }
+ **/
+
+ public static void resetProxy(String appClass, Context ctx) throws Exception {
+
+ resetSystemProperties();
+
+ if (Build.VERSION.SDK_INT < 14) {
+ resetProxyForGingerBread(ctx);
+ } else if (Build.VERSION.SDK_INT < 19) {
+ resetProxyForICS();
+ } else if (Build.VERSION.SDK_INT < 20) {
+ resetKitKatProxy(appClass, ctx);
+ } else if (Build.VERSION.SDK_INT >= 21) {
+ resetLollipopProxy(appClass, ctx);
+ }
+
+ }
+
+ private static void resetProxyForICS() throws Exception {
+ try {
+ Class webViewCoreClass = Class.forName("android.webkit.WebViewCore");
+ Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
+ if (webViewCoreClass != null && proxyPropertiesClass != null) {
+ Method m = webViewCoreClass.getDeclaredMethod("sendStaticMessage", Integer.TYPE,
+ Object.class);
+
+ if (m != null) {
+ m.setAccessible(true);
+
+ // android.webkit.WebViewCore.EventHub.PROXY_CHANGED = 193;
+ m.invoke(null, 193, null);
+ }
+ }
+ } catch (Exception e) {
+ Log.e("ProxySettings",
+ "Exception setting WebKit proxy through android.net.ProxyProperties: "
+ + e.toString());
+ throw e;
+ } catch (Error e) {
+ Log.e("ProxySettings",
+ "Exception setting WebKit proxy through android.webkit.Network: "
+ + e.toString());
+ throw e;
+ }
+ }
+
+ private static void resetProxyForGingerBread(Context ctx) throws Exception {
+ Object requestQueueObject = getRequestQueue(ctx);
+ if (requestQueueObject != null) {
+ setDeclaredField(requestQueueObject, "mProxyHost", null);
+ }
+ }
+
+ public static Object getRequestQueue(Context ctx) throws Exception {
+ Object ret = null;
+ Class networkClass = Class.forName("android.webkit.Network");
+ if (networkClass != null) {
+ Object networkObj = invokeMethod(networkClass, "getInstance", new Object[]{
+ ctx
+ }, Context.class);
+ if (networkObj != null) {
+ ret = getDeclaredField(networkObj, "mRequestQueue");
+ }
+ }
+ return ret;
+ }
+
+ private static Object getDeclaredField(Object obj, String name)
+ throws SecurityException, NoSuchFieldException,
+ IllegalArgumentException, IllegalAccessException {
+ Field f = obj.getClass().getDeclaredField(name);
+ f.setAccessible(true);
+ Object out = f.get(obj);
+ // System.out.println(obj.getClass().getName() + "." + name + " = "+
+ // out);
+ return out;
+ }
+
+ private static void setDeclaredField(Object obj, String name, Object value)
+ throws SecurityException, NoSuchFieldException,
+ IllegalArgumentException, IllegalAccessException {
+ Field f = obj.getClass().getDeclaredField(name);
+ f.setAccessible(true);
+ f.set(obj, value);
+ }
+
+ private static Object invokeMethod(Object object, String methodName, Object[] params,
+ Class... types) throws Exception {
+ Object out = null;
+ Class c = object instanceof Class ? (Class) object : object.getClass();
+ if (types != null) {
+ Method method = c.getMethod(methodName, types);
+ out = method.invoke(object, params);
+ } else {
+ Method method = c.getMethod(methodName);
+ out = method.invoke(object);
+ }
+ // System.out.println(object.getClass().getName() + "." + methodName +
+ // "() = "+ out);
+ return out;
+ }
+
+ public static Socket getSocket(Context context, String proxyHost, int proxyPort)
+ throws IOException {
+ Socket sock = new Socket();
+
+ sock.connect(new InetSocketAddress(proxyHost, proxyPort), 10000);
+
+ return sock;
+ }
+
+ public static Socket getSocket(Context context) throws IOException {
+ return getSocket(context, DEFAULT_HOST, DEFAULT_SOCKS_PORT);
+
+ }
+
+ public static AlertDialog initOrbot(Activity activity,
+ CharSequence stringTitle,
+ CharSequence stringMessage,
+ CharSequence stringButtonYes,
+ CharSequence stringButtonNo,
+ CharSequence stringDesiredBarcodeFormats) {
+ Intent intentScan = new Intent("org.torproject.android.START_TOR");
+ intentScan.addCategory(Intent.CATEGORY_DEFAULT);
+
+ try {
+ activity.startActivityForResult(intentScan, REQUEST_CODE);
+ return null;
+ } catch (ActivityNotFoundException e) {
+ return showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes,
+ stringButtonNo);
+ }
+ }
+
+ private static AlertDialog showDownloadDialog(final Activity activity,
+ CharSequence stringTitle,
+ CharSequence stringMessage,
+ CharSequence stringButtonYes,
+ CharSequence stringButtonNo) {
+ AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
+ downloadDialog.setTitle(stringTitle);
+ downloadDialog.setMessage(stringMessage);
+ downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ Uri uri = Uri.parse("market://search?q=pname:org.torproject.android");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ activity.startActivity(intent);
+ }
+ });
+ downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ }
+ });
+ return downloadDialog.show();
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongBuilder.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongBuilder.java
new file mode 100644
index 00000000..6693700f
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongBuilder.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 CommonsWare, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.client;
+
+import android.content.Intent;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.TrustManager;
+
+public interface StrongBuilder {
+ /**
+ * Callback to get a connection handed to you for use,
+ * already set up for NetCipher.
+ *
+ * @param the type of connection created by this builder
+ */
+ interface Callback {
+ /**
+ * Called when the NetCipher-enhanced connection is ready
+ * for use.
+ *
+ * @param connection the connection
+ */
+ void onConnected(C connection);
+
+ /**
+ * Called if we tried to connect through to Orbot but failed
+ * for some reason
+ *
+ * @param e the reason
+ */
+ void onConnectionException(Exception e);
+
+ /**
+ * Called if our attempt to get a status from Orbot failed
+ * after a defined period of time. See statusTimeout() on
+ * OrbotInitializer.
+ */
+ void onTimeout();
+
+ /**
+ * Called if you requested validation that we are connecting
+ * through Tor, and while we were able to connect to Orbot, that
+ * validation failed.
+ */
+ void onInvalid();
+ }
+
+ /**
+ * Call this to configure the Tor proxy from the results
+ * returned by Orbot, using the best available proxy
+ * (SOCKS if possible, else HTTP)
+ *
+ * @return the builder
+ */
+ T withBestProxy();
+
+ /**
+ * @return true if this builder supports HTTP proxies, false
+ * otherwise
+ */
+ boolean supportsHttpProxy();
+
+ /**
+ * Call this to configure the Tor proxy from the results
+ * returned by Orbot, using the HTTP proxy.
+ *
+ * @return the builder
+ */
+ T withHttpProxy();
+
+ /**
+ * @return true if this builder supports SOCKS proxies, false
+ * otherwise
+ */
+ boolean supportsSocksProxy();
+
+ /**
+ * Call this to configure the Tor proxy from the results
+ * returned by Orbot, using the SOCKS proxy.
+ *
+ * @return the builder
+ */
+ T withSocksProxy();
+
+ /**
+ * Applies your own custom TrustManagers, such as for
+ * replacing the stock keystore support with a custom
+ * keystore.
+ *
+ * @param trustManagers the TrustManagers to use
+ * @return the builder
+ */
+ T withTrustManagers(TrustManager[] trustManagers)
+ throws NoSuchAlgorithmException, KeyManagementException;
+
+ /**
+ * Call this if you want a weaker set of supported ciphers,
+ * because you are running into compatibility problems with
+ * some server due to a cipher mismatch. The better solution
+ * is to fix the server.
+ *
+ * @return the builder
+ */
+ T withWeakCiphers();
+
+ /**
+ * Call this if you want the builder to confirm that we are
+ * communicating over Tor, by reaching out to a Tor test
+ * server and confirming our connection status. By default,
+ * this is skipped. Adding this check adds security, but it
+ * has the chance of false negatives (e.g., we cannot reach
+ * that Tor server for some reason).
+ *
+ * @return the builder
+ */
+ T withTorValidation();
+
+ /**
+ * Builds a connection, applying the configuration already
+ * specified in the builder.
+ *
+ * @param status status Intent from OrbotInitializer
+ * @return the connection
+ * @throws IOException
+ */
+ C build(Intent status) throws Exception;
+
+ /**
+ * Asynchronous version of build(), one that uses OrbotInitializer
+ * internally to get the status and checks the validity of the Tor
+ * connection (if requested). Note that your callback methods may
+ * be invoked on any thread; do not assume that they will be called
+ * on any particular thread.
+ *
+ * @param callback Callback to get a connection handed to you
+ * for use, already set up for NetCipher
+ */
+ void build(Callback callback);
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConnectionBuilder.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConnectionBuilder.java
new file mode 100644
index 00000000..03425cc2
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConnectionBuilder.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016 CommonsWare, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.client;
+
+import android.content.Context;
+import android.content.Intent;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Builds an HttpUrlConnection that connects via Tor through
+ * Orbot.
+ */
+public class StrongConnectionBuilder
+ extends StrongBuilderBase {
+ private URL url;
+
+ /**
+ * Creates a StrongConnectionBuilder using the strongest set
+ * of options for security. Use this if the strongest set of
+ * options is what you want; otherwise, create a
+ * builder via the constructor and configure it as you see fit.
+ *
+ * @param context any Context will do
+ * @return a configured StrongConnectionBuilder
+ * @throws Exception
+ */
+ static public StrongConnectionBuilder forMaxSecurity(Context context)
+ throws Exception {
+ return (new StrongConnectionBuilder(context)
+ .withBestProxy());
+ }
+
+ /**
+ * Creates a builder instance.
+ *
+ * @param context any Context will do; builder will hold onto
+ * Application context
+ */
+ public StrongConnectionBuilder(Context context) {
+ super(context);
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param original builder to clone
+ */
+ public StrongConnectionBuilder(StrongConnectionBuilder original) {
+ super(original);
+ this.url = original.url;
+ }
+/*
+ public boolean supportsSocksProxy() {
+ return(false);
+ }
+*/
+
+ /**
+ * Sets the URL to build a connection for.
+ *
+ * @param url the URL
+ * @return the builder
+ * @throws MalformedURLException
+ */
+ public StrongConnectionBuilder connectTo(String url)
+ throws MalformedURLException {
+ connectTo(new URL(url));
+
+ return (this);
+ }
+
+ /**
+ * Sets the URL to build a connection for.
+ *
+ * @param url the URL
+ * @return the builder
+ */
+ public StrongConnectionBuilder connectTo(URL url) {
+ this.url = url;
+
+ return (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpURLConnection build(Intent status) throws IOException {
+ return (buildForUrl(status, url));
+ }
+
+ @Override
+ protected String get(Intent status, HttpURLConnection connection,
+ String url) throws Exception {
+ HttpURLConnection realConnection = buildForUrl(status, new URL(url));
+
+ return (slurp(realConnection.getInputStream()));
+ }
+
+ private HttpURLConnection buildForUrl(Intent status, URL urlToUse)
+ throws IOException {
+ URLConnection result;
+ Proxy proxy = buildProxy(status);
+
+ if (proxy == null) {
+ result = urlToUse.openConnection();
+ } else {
+ result = urlToUse.openConnection(proxy);
+ }
+
+ if (result instanceof HttpsURLConnection && sslContext != null) {
+ SSLSocketFactory tlsOnly = buildSocketFactory();
+ HttpsURLConnection https = (HttpsURLConnection) result;
+
+ https.setSSLSocketFactory(tlsOnly);
+ }
+
+ return ((HttpURLConnection) result);
+ }
+
+ // based on http://stackoverflow.com/a/309718/115145
+
+ public static String slurp(final InputStream is)
+ throws IOException {
+ final char[] buffer = new char[128];
+ final StringBuilder out = new StringBuilder();
+ final Reader in = new InputStreamReader(is, "UTF-8");
+
+ for (; ; ) {
+ int rsz = in.read(buffer, 0, buffer.length);
+ if (rsz < 0)
+ break;
+ out.append(buffer, 0, rsz);
+ }
+
+ in.close();
+
+ return out.toString();
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConstants.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConstants.java
new file mode 100644
index 00000000..5fa85ba3
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConstants.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.guardianproject.netcipher.client;
+
+public class StrongConstants {
+
+ /**
+ * Ordered to prefer the stronger cipher suites as noted
+ * http://op-co.de/blog/posts/android_ssl_downgrade/
+ */
+ public static final String ENABLED_CIPHERS[] = {
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+ "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"};
+
+ /**
+ * Ordered to prefer the stronger/newer TLS versions as noted
+ * http://op-co.de/blog/posts/android_ssl_downgrade/
+ */
+ public static final String ENABLED_PROTOCOLS[] = {"TLSv1.2", "TLSv1.1",
+ "TLSv1"};
+
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/TlsOnlySocketFactory.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/TlsOnlySocketFactory.java
new file mode 100644
index 00000000..b75a9342
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/client/TlsOnlySocketFactory.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright 2015 Bhavit Singh Sengar
+ * Copyright 2015-2016 Hans-Christoph Steiner
+ * Copyright 2015-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * From https://stackoverflow.com/a/29946540
+ */
+
+package info.guardianproject.netcipher.client;
+
+import android.net.SSLCertificateSocketFactory;
+import android.os.Build;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * While making a secure connection, Android's {@link HttpsURLConnection} falls
+ * back to SSLv3 from TLSv1. This is a bug in android versions < 4.4. It can be
+ * fixed by removing the SSLv3 protocol from Enabled Protocols list. Use this as
+ * the {@link SSLSocketFactory} for
+ * {@link HttpsURLConnection#setDefaultSSLSocketFactory(SSLSocketFactory)}
+ *
+ * @author Bhavit S. Sengar
+ * @author Hans-Christoph Steiner
+ */
+public class TlsOnlySocketFactory extends SSLSocketFactory {
+ private static final int HANDSHAKE_TIMEOUT = 0;
+ private static final String TAG = "TlsOnlySocketFactory";
+ private final SSLSocketFactory delegate;
+ private final boolean compatible;
+
+ public TlsOnlySocketFactory() {
+ this.delegate = SSLCertificateSocketFactory.getDefault(HANDSHAKE_TIMEOUT, null);
+ this.compatible = false;
+ }
+
+ public TlsOnlySocketFactory(SSLSocketFactory delegate) {
+ this.delegate = delegate;
+ this.compatible = false;
+ }
+
+ /**
+ * Make {@link SSLSocket}s that are compatible with outdated servers.
+ *
+ * @param delegate
+ * @param compatible
+ */
+ public TlsOnlySocketFactory(SSLSocketFactory delegate, boolean compatible) {
+ this.delegate = delegate;
+ this.compatible = compatible;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return delegate.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ /**
+ * @see The sad state of server-side TLS Session Resumption implementations
+ */
+ private Socket makeSocketSafe(Socket socket, String host) {
+ if (socket instanceof SSLSocket) {
+ TlsOnlySSLSocket tempSocket =
+ new TlsOnlySSLSocket((SSLSocket) socket, compatible);
+
+ if (delegate instanceof SSLCertificateSocketFactory &&
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ SSLCertificateSocketFactory factory = (SSLCertificateSocketFactory) delegate;
+ factory.setHostname(socket, host);
+ factory.setUseSessionTickets(socket, false);
+ } else {
+ tempSocket.setHostname(host);
+ }
+
+ socket = tempSocket;
+ }
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ throws IOException {
+ return makeSocketSafe(delegate.createSocket(s, host, port, autoClose), host);
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ return makeSocketSafe(delegate.createSocket(host, port), host);
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException {
+ return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort), host);
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return makeSocketSafe(delegate.createSocket(host, port), host.getHostName());
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort),
+ address.getHostName());
+ }
+
+ private class TlsOnlySSLSocket extends DelegateSSLSocket {
+
+ final boolean compatible;
+
+ private TlsOnlySSLSocket(SSLSocket delegate, boolean compatible) {
+ super(delegate);
+ this.compatible = compatible;
+
+ // badly configured servers can't handle a good config
+ if (compatible) {
+ ArrayList protocols = new ArrayList(Arrays.asList(delegate
+ .getEnabledProtocols()));
+ protocols.remove("SSLv2");
+ protocols.remove("SSLv3");
+ super.setEnabledProtocols(protocols.toArray(new String[protocols.size()]));
+
+ /*
+ * Exclude extremely weak EXPORT ciphers. NULL ciphers should
+ * never even have been an option in TLS.
+ */
+ ArrayList enabled = new ArrayList(10);
+ Pattern exclude = Pattern.compile(".*(EXPORT|NULL).*");
+ for (String cipher : delegate.getEnabledCipherSuites()) {
+ if (!exclude.matcher(cipher).matches()) {
+ enabled.add(cipher);
+ }
+ }
+ super.setEnabledCipherSuites(enabled.toArray(new String[enabled.size()]));
+ return;
+ } // else
+
+ // 16-19 support v1.1 and v1.2 but only by default starting in 20+
+ // https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
+ ArrayList protocols = new ArrayList(Arrays.asList(delegate
+ .getSupportedProtocols()));
+ protocols.remove("SSLv2");
+ protocols.remove("SSLv3");
+ super.setEnabledProtocols(protocols.toArray(new String[protocols.size()]));
+
+ /*
+ * Exclude weak ciphers, like EXPORT, MD5, DES, and DH. NULL ciphers
+ * should never even have been an option in TLS.
+ */
+ ArrayList enabledCiphers = new ArrayList(10);
+ Pattern exclude = Pattern.compile(".*(_DES|DH_|DSS|EXPORT|MD5|NULL|RC4|TLS_FALLBACK_SCSV).*");
+ for (String cipher : delegate.getSupportedCipherSuites()) {
+ if (!exclude.matcher(cipher).matches()) {
+ enabledCiphers.add(cipher);
+ }
+ }
+ super.setEnabledCipherSuites(enabledCiphers.toArray(new String[enabledCiphers.size()]));
+ }
+
+ /**
+ * This works around a bug in Android < 19 where SSLv3 is forced
+ */
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
+ List systemProtocols;
+ if (this.compatible) {
+ systemProtocols = Arrays.asList(delegate.getEnabledProtocols());
+ } else {
+ systemProtocols = Arrays.asList(delegate.getSupportedProtocols());
+ }
+ List enabledProtocols = new ArrayList(systemProtocols);
+ if (enabledProtocols.size() > 1) {
+ enabledProtocols.remove("SSLv2");
+ enabledProtocols.remove("SSLv3");
+ } else {
+ Log.w(TAG, "SSL stuck with protocol available for "
+ + String.valueOf(enabledProtocols));
+ }
+ protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
+ }
+ super.setEnabledProtocols(protocols);
+ }
+ }
+
+ public class DelegateSSLSocket extends SSLSocket {
+
+ protected final SSLSocket delegate;
+
+ DelegateSSLSocket(SSLSocket delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return delegate.getEnabledCipherSuites();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ delegate.setEnabledCipherSuites(suites);
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ return delegate.getSupportedProtocols();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ return delegate.getEnabledProtocols();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ delegate.setEnabledProtocols(protocols);
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return delegate.getSession();
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.addHandshakeCompletedListener(listener);
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.removeHandshakeCompletedListener(listener);
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ delegate.startHandshake();
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ delegate.setUseClientMode(mode);
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ return delegate.getUseClientMode();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ delegate.setNeedClientAuth(need);
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ delegate.setWantClientAuth(want);
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ return delegate.getNeedClientAuth();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ return delegate.getWantClientAuth();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ delegate.setEnableSessionCreation(flag);
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ return delegate.getEnableSessionCreation();
+ }
+
+ @Override
+ public void bind(SocketAddress localAddr) throws IOException {
+ delegate.bind(localAddr);
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public void connect(SocketAddress remoteAddr) throws IOException {
+ delegate.connect(remoteAddr);
+ }
+
+ @Override
+ public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
+ delegate.connect(remoteAddr, timeout);
+ }
+
+ @Override
+ public SocketChannel getChannel() {
+ return delegate.getChannel();
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ return delegate.getInetAddress();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return delegate.getInputStream();
+ }
+
+ @Override
+ public boolean getKeepAlive() throws SocketException {
+ return delegate.getKeepAlive();
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ return delegate.getLocalAddress();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return delegate.getLocalPort();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ return delegate.getLocalSocketAddress();
+ }
+
+ @Override
+ public boolean getOOBInline() throws SocketException {
+ return delegate.getOOBInline();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return delegate.getOutputStream();
+ }
+
+ @Override
+ public int getPort() {
+ return delegate.getPort();
+ }
+
+ @Override
+ public synchronized int getReceiveBufferSize() throws SocketException {
+ return delegate.getReceiveBufferSize();
+ }
+
+ @Override
+ public SocketAddress getRemoteSocketAddress() {
+ return delegate.getRemoteSocketAddress();
+ }
+
+ @Override
+ public boolean getReuseAddress() throws SocketException {
+ return delegate.getReuseAddress();
+ }
+
+ @Override
+ public synchronized int getSendBufferSize() throws SocketException {
+ return delegate.getSendBufferSize();
+ }
+
+ @Override
+ public int getSoLinger() throws SocketException {
+ return delegate.getSoLinger();
+ }
+
+ @Override
+ public synchronized int getSoTimeout() throws SocketException {
+ return delegate.getSoTimeout();
+ }
+
+ @Override
+ public boolean getTcpNoDelay() throws SocketException {
+ return delegate.getTcpNoDelay();
+ }
+
+ @Override
+ public int getTrafficClass() throws SocketException {
+ return delegate.getTrafficClass();
+ }
+
+ @Override
+ public boolean isBound() {
+ return delegate.isBound();
+ }
+
+ @Override
+ public boolean isClosed() {
+ return delegate.isClosed();
+ }
+
+ @Override
+ public boolean isConnected() {
+ return delegate.isConnected();
+ }
+
+ @Override
+ public boolean isInputShutdown() {
+ return delegate.isInputShutdown();
+ }
+
+ @Override
+ public boolean isOutputShutdown() {
+ return delegate.isOutputShutdown();
+ }
+
+ @Override
+ public void sendUrgentData(int value) throws IOException {
+ delegate.sendUrgentData(value);
+ }
+
+ @Override
+ public void setKeepAlive(boolean keepAlive) throws SocketException {
+ delegate.setKeepAlive(keepAlive);
+ }
+
+ @Override
+ public void setOOBInline(boolean oobinline) throws SocketException {
+ delegate.setOOBInline(oobinline);
+ }
+
+ @Override
+ public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
+ delegate.setPerformancePreferences(connectionTime,
+ latency, bandwidth);
+ }
+
+ @Override
+ public synchronized void setReceiveBufferSize(int size) throws SocketException {
+ delegate.setReceiveBufferSize(size);
+ }
+
+ @Override
+ public void setReuseAddress(boolean reuse) throws SocketException {
+ delegate.setReuseAddress(reuse);
+ }
+
+ @Override
+ public synchronized void setSendBufferSize(int size) throws SocketException {
+ delegate.setSendBufferSize(size);
+ }
+
+ @Override
+ public void setSoLinger(boolean on, int timeout) throws SocketException {
+ delegate.setSoLinger(on, timeout);
+ }
+
+ @Override
+ public synchronized void setSoTimeout(int timeout) throws SocketException {
+ delegate.setSoTimeout(timeout);
+ }
+
+ @Override
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ delegate.setTcpNoDelay(on);
+ }
+
+ @Override
+ public void setTrafficClass(int value) throws SocketException {
+ delegate.setTrafficClass(value);
+ }
+
+ @Override
+ public void shutdownInput() throws IOException {
+ delegate.shutdownInput();
+ }
+
+ @Override
+ public void shutdownOutput() throws IOException {
+ delegate.shutdownOutput();
+ }
+
+ // inspired by https://github.com/k9mail/k-9/commit/54f9fd36a77423a55f63fbf9b1bcea055a239768
+
+ public DelegateSSLSocket setHostname(String host) {
+ try {
+ delegate
+ .getClass()
+ .getMethod("setHostname", String.class)
+ .invoke(delegate, host);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not enable SNI", e);
+ }
+
+ return (this);
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return delegate.equals(o);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/OrbotHelper.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/OrbotHelper.java
new file mode 100644
index 00000000..656ff22e
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/OrbotHelper.java
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2014-2016 Hans-Christoph Steiner
+ * Copyright 2012-2016 Nathan Freitas
+ * Portions Copyright (c) 2016 CommonsWare, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.proxy;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * Utility class to simplify setting up a proxy connection
+ * to Orbot.
+ *
+ * If you are using classes in the info.guardianproject.netcipher.client
+ * package, call OrbotHelper.get(this).init(); from onCreate()
+ * of a custom Application subclass, or from some other guaranteed
+ * entry point to your app. At that point, the
+ * info.guardianproject.netcipher.client classes will be ready
+ * for use.
+ */
+public class OrbotHelper implements ProxyHelper {
+
+ private final static int REQUEST_CODE_STATUS = 100;
+
+ public final static String ORBOT_PACKAGE_NAME = "org.torproject.android";
+ public final static String ORBOT_MARKET_URI = "market://details?id=" + ORBOT_PACKAGE_NAME;
+ public final static String ORBOT_FDROID_URI = "https://f-droid.org/repository/browse/?fdid="
+ + ORBOT_PACKAGE_NAME;
+ public final static String ORBOT_PLAY_URI = "https://play.google.com/store/apps/details?id="
+ + ORBOT_PACKAGE_NAME;
+
+ /**
+ * A request to Orbot to transparently start Tor services
+ */
+ public final static String ACTION_START = "org.torproject.android.intent.action.START";
+
+ /**
+ * {@link Intent} send by Orbot with {@code ON/OFF/STARTING/STOPPING} status
+ * included as an {@link #EXTRA_STATUS} {@code String}. Your app should
+ * always receive {@code ACTION_STATUS Intent}s since any other app could
+ * start Orbot. Also, user-triggered starts and stops will also cause
+ * {@code ACTION_STATUS Intent}s to be broadcast.
+ */
+ public final static String ACTION_STATUS = "org.torproject.android.intent.action.STATUS";
+
+ /**
+ * {@code String} that contains a status constant: {@link #STATUS_ON},
+ * {@link #STATUS_OFF}, {@link #STATUS_STARTING}, or
+ * {@link #STATUS_STOPPING}
+ */
+ public final static String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS";
+ /**
+ * A {@link String} {@code packageName} for Orbot to direct its status reply
+ * to, used in {@link #ACTION_START} {@link Intent}s sent to Orbot
+ */
+ public final static String EXTRA_PACKAGE_NAME = "org.torproject.android.intent.extra.PACKAGE_NAME";
+
+ public final static String EXTRA_PROXY_PORT_HTTP = "org.torproject.android.intent.extra.HTTP_PROXY_PORT";
+ public final static String EXTRA_PROXY_PORT_SOCKS = "org.torproject.android.intent.extra.SOCKS_PROXY_PORT";
+
+
+ /**
+ * All tor-related services and daemons are stopped
+ */
+ public final static String STATUS_OFF = "OFF";
+ /**
+ * All tor-related services and daemons have completed starting
+ */
+ public final static String STATUS_ON = "ON";
+ public final static String STATUS_STARTING = "STARTING";
+ public final static String STATUS_STOPPING = "STOPPING";
+ /**
+ * The user has disabled the ability for background starts triggered by
+ * apps. Fallback to the old Intent that brings up Orbot.
+ */
+ public final static String STATUS_STARTS_DISABLED = "STARTS_DISABLED";
+
+ public final static String ACTION_START_TOR = "org.torproject.android.START_TOR";
+ public final static String ACTION_REQUEST_HS = "org.torproject.android.REQUEST_HS_PORT";
+ public final static int START_TOR_RESULT = 0x9234;
+ public final static int HS_REQUEST_CODE = 9999;
+
+
+/*
+ private OrbotHelper() {
+ // only static utility methods, do not instantiate
+ }
+*/
+
+ /**
+ * Test whether a {@link URL} is a Tor Hidden Service host name, also known
+ * as an ".onion address".
+ *
+ * @return whether the host name is a Tor .onion address
+ */
+ public static boolean isOnionAddress(URL url) {
+ return url.getHost().endsWith(".onion");
+ }
+
+ /**
+ * Test whether a URL {@link String} is a Tor Hidden Service host name, also known
+ * as an ".onion address".
+ *
+ * @return whether the host name is a Tor .onion address
+ */
+ public static boolean isOnionAddress(String urlString) {
+ try {
+ return isOnionAddress(new URL(urlString));
+ } catch (MalformedURLException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Test whether a {@link Uri} is a Tor Hidden Service host name, also known
+ * as an ".onion address".
+ *
+ * @return whether the host name is a Tor .onion address
+ */
+ public static boolean isOnionAddress(Uri uri) {
+ return uri.getHost().endsWith(".onion");
+ }
+
+ /**
+ * Check if the tor process is running. This method is very
+ * brittle, and is therefore deprecated in favor of using the
+ * {@link #ACTION_STATUS} {@code Intent} along with the
+ * {@link #requestStartTor(Context)} method.
+ */
+ @Deprecated
+ public static boolean isOrbotRunning(Context context) {
+ int procId = TorServiceUtils.findProcessId(context);
+
+ return (procId != -1);
+ }
+
+ public static boolean isOrbotInstalled(Context context) {
+ return isAppInstalled(context, ORBOT_PACKAGE_NAME);
+ }
+
+ private static boolean isAppInstalled(Context context, String uri) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ public static void requestHiddenServiceOnPort(Activity activity, int port) {
+ Intent intent = new Intent(ACTION_REQUEST_HS);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ intent.putExtra("hs_port", port);
+
+ activity.startActivityForResult(intent, HS_REQUEST_CODE);
+ }
+
+ /**
+ * First, checks whether Orbot is installed. If Orbot is installed, then a
+ * broadcast {@link Intent} is sent to request Orbot to start
+ * transparently in the background. When Orbot receives this {@code
+ * Intent}, it will immediately reply to the app that called this method
+ * with an {@link #ACTION_STATUS} {@code Intent} that is broadcast to the
+ * {@code packageName} of the provided {@link Context} (i.e. {@link
+ * Context#getPackageName()}.
+ *
+ * That reply {@link #ACTION_STATUS} {@code Intent} could say that the user
+ * has disabled background starts with the status
+ * {@link #STATUS_STARTS_DISABLED}. That means that Orbot ignored this
+ * request. To directly prompt the user to start Tor, use
+ * {@link #requestShowOrbotStart(Activity)}, which will bring up
+ * Orbot itself for the user to manually start Tor. Orbot always broadcasts
+ * it's status, so your app will receive those no matter how Tor gets
+ * started.
+ *
+ * @param context the app {@link Context} will receive the reply
+ * @return whether the start request was sent to Orbot
+ * @see #requestShowOrbotStart(Activity activity)
+ */
+ public static boolean requestStartTor(Context context) {
+ if (OrbotHelper.isOrbotInstalled(context)) {
+ Log.i("OrbotHelper", "requestStartTor " + context.getPackageName());
+ Intent intent = getOrbotStartIntent(context);
+ context.sendBroadcast(intent);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets an {@link Intent} for starting Orbot. Orbot will reply with the
+ * current status to the {@code packageName} of the app in the provided
+ * {@link Context} (i.e. {@link Context#getPackageName()}.
+ */
+ public static Intent getOrbotStartIntent(Context context) {
+ Intent intent = new Intent(ACTION_START);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ intent.putExtra(EXTRA_PACKAGE_NAME, context.getPackageName());
+ return intent;
+ }
+
+ /**
+ * Gets a barebones {@link Intent} for starting Orbot. This is deprecated
+ * in favor of {@link #getOrbotStartIntent(Context)}.
+ */
+ @Deprecated
+ public static Intent getOrbotStartIntent() {
+ Intent intent = new Intent(ACTION_START);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ return intent;
+ }
+
+ /**
+ * First, checks whether Orbot is installed, then checks whether Orbot is
+ * running. If Orbot is installed and not running, then an {@link Intent} is
+ * sent to request the user to start Orbot, which will show the main Orbot screen.
+ * The result will be returned in
+ * {@link Activity#onActivityResult(int requestCode, int resultCode, Intent data)}
+ * with a {@code requestCode} of {@code START_TOR_RESULT}
+ *
+ * Orbot will also always broadcast the status of starting Tor via the
+ * {@link #ACTION_STATUS} Intent, no matter how it is started.
+ *
+ * @param activity the {@code Activity} that gets the result of the
+ * {@link #START_TOR_RESULT} request
+ * @return whether the start request was sent to Orbot
+ * @see #requestStartTor(Context context)
+ */
+ public static boolean requestShowOrbotStart(Activity activity) {
+ if (OrbotHelper.isOrbotInstalled(activity)) {
+ if (!OrbotHelper.isOrbotRunning(activity)) {
+ Intent intent = getShowOrbotStartIntent();
+ activity.startActivityForResult(intent, START_TOR_RESULT);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Intent getShowOrbotStartIntent() {
+ Intent intent = new Intent(ACTION_START_TOR);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+
+ public static Intent getOrbotInstallIntent(Context context) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(ORBOT_MARKET_URI));
+
+ PackageManager pm = context.getPackageManager();
+ List resInfos = pm.queryIntentActivities(intent, 0);
+
+ String foundPackageName = null;
+ for (ResolveInfo r : resInfos) {
+ Log.i("OrbotHelper", "market: " + r.activityInfo.packageName);
+ if (TextUtils.equals(r.activityInfo.packageName, FDROID_PACKAGE_NAME)
+ || TextUtils.equals(r.activityInfo.packageName, PLAY_PACKAGE_NAME)) {
+ foundPackageName = r.activityInfo.packageName;
+ break;
+ }
+ }
+
+ if (foundPackageName == null) {
+ intent.setData(Uri.parse(ORBOT_FDROID_URI));
+ } else {
+ intent.setPackage(foundPackageName);
+ }
+ return intent;
+ }
+
+ @Override
+ public boolean isInstalled(Context context) {
+ return isOrbotInstalled(context);
+ }
+
+ @Override
+ public void requestStatus(Context context) {
+ isOrbotRunning(context);
+ }
+
+ @Override
+ public boolean requestStart(Context context) {
+ return requestStartTor(context);
+ }
+
+ @Override
+ public Intent getInstallIntent(Context context) {
+ return getOrbotInstallIntent(context);
+ }
+
+ @Override
+ public Intent getStartIntent(Context context) {
+ return getOrbotStartIntent();
+ }
+
+ @Override
+ public String getName() {
+ return "Orbot";
+ }
+
+ /* MLM additions */
+
+ private final Context context;
+ private final Handler handler;
+ private boolean isInstalled = false;
+ private Intent lastStatusIntent = null;
+ private Set statusCallbacks =
+ newSetFromMap(new WeakHashMap());
+ private Set installCallbacks =
+ newSetFromMap(new WeakHashMap());
+ private long statusTimeoutMs = 30000L;
+ private long installTimeoutMs = 60000L;
+ private boolean validateOrbot = true;
+
+ abstract public static class SimpleStatusCallback
+ implements StatusCallback {
+ @Override
+ public void onEnabled(Intent statusIntent) {
+ // no-op; extend and override if needed
+ }
+
+ @Override
+ public void onStarting() {
+ // no-op; extend and override if needed
+ }
+
+ @Override
+ public void onStopping() {
+ // no-op; extend and override if needed
+ }
+
+ @Override
+ public void onDisabled() {
+ // no-op; extend and override if needed
+ }
+
+ @Override
+ public void onNotYetInstalled() {
+ // no-op; extend and override if needed
+ }
+ }
+
+ /**
+ * Callback interface used for reporting the results of an
+ * attempt to install Orbot
+ */
+ public interface InstallCallback {
+ void onInstalled();
+
+ void onInstallTimeout();
+ }
+
+ private static volatile OrbotHelper INSTANCE;
+
+ /**
+ * Retrieves the singleton, initializing if if needed
+ *
+ * @param context any Context will do, as we will hold onto
+ * the Application
+ * @return the singleton
+ */
+ synchronized public static OrbotHelper get(Context context) {
+ if (INSTANCE == null) {
+ INSTANCE = new OrbotHelper(context);
+ }
+
+ return (INSTANCE);
+ }
+
+ /**
+ * Standard constructor
+ *
+ * @param context any Context will do; OrbotInitializer will hold
+ * onto the Application context
+ */
+ private OrbotHelper(Context context) {
+ this.context = context.getApplicationContext();
+ this.handler = new Handler(Looper.getMainLooper());
+ }
+
+ /**
+ * Adds a StatusCallback to be called when we find out that
+ * Orbot is ready. If Orbot is ready for use, your callback
+ * will be called with onEnabled() immediately, before this
+ * method returns.
+ *
+ * @param cb a callback
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper addStatusCallback(StatusCallback cb) {
+ statusCallbacks.add(cb);
+
+ if (lastStatusIntent != null) {
+ String status =
+ lastStatusIntent.getStringExtra(OrbotHelper.EXTRA_STATUS);
+
+ if (status.equals(OrbotHelper.STATUS_ON)) {
+ cb.onEnabled(lastStatusIntent);
+ }
+ }
+
+ return (this);
+ }
+
+ /**
+ * Removes an existing registered StatusCallback.
+ *
+ * @param cb the callback to remove
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper removeStatusCallback(StatusCallback cb) {
+ statusCallbacks.remove(cb);
+
+ return (this);
+ }
+
+
+ /**
+ * Adds an InstallCallback to be called when we find out that
+ * Orbot is installed
+ *
+ * @param cb a callback
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper addInstallCallback(InstallCallback cb) {
+ installCallbacks.add(cb);
+
+ return (this);
+ }
+
+ /**
+ * Removes an existing registered InstallCallback.
+ *
+ * @param cb the callback to remove
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper removeInstallCallback(InstallCallback cb) {
+ installCallbacks.remove(cb);
+
+ return (this);
+ }
+
+ /**
+ * Sets how long of a delay, in milliseconds, after trying
+ * to get a status from Orbot before we give up.
+ * Defaults to 30000ms = 30 seconds = 0.000347222 days
+ *
+ * @param timeoutMs delay period in milliseconds
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper statusTimeout(long timeoutMs) {
+ statusTimeoutMs = timeoutMs;
+
+ return (this);
+ }
+
+ /**
+ * Sets how long of a delay, in milliseconds, after trying
+ * to install Orbot do we assume that it's not happening.
+ * Defaults to 60000ms = 60 seconds = 1 minute = 1.90259e-6 years
+ *
+ * @param timeoutMs delay period in milliseconds
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper installTimeout(long timeoutMs) {
+ installTimeoutMs = timeoutMs;
+
+ return (this);
+ }
+
+ /**
+ * By default, NetCipher ensures that the Orbot on the
+ * device is one of the official builds. Call this method
+ * to skip that validation. Mostly, this is for developers
+ * who have their own custom Orbot builds (e.g., for
+ * dedicated hardware).
+ *
+ * @return the singleton, for chaining
+ */
+ public OrbotHelper skipOrbotValidation() {
+ validateOrbot = false;
+
+ return (this);
+ }
+
+ /**
+ * @return true if Orbot is installed (the last time we checked),
+ * false otherwise
+ */
+ public boolean isInstalled() {
+ return (isInstalled);
+ }
+
+ /**
+ * Initializes the connection to Orbot, revalidating that it is installed
+ * and requesting fresh status broadcasts. This is best run in your app's
+ * {@link android.app.Application} subclass, in its
+ * {@link android.app.Application#onCreate()} method.
+ *
+ * @return true if initialization is proceeding, false if Orbot is not installed,
+ * or version of Orbot with a unofficial signing key is present.
+ */
+ public boolean init() {
+ Intent orbot = OrbotHelper.getOrbotStartIntent(context);
+
+ if (validateOrbot) {
+ ArrayList hashes = new ArrayList();
+
+ // Tor Project signing key
+ hashes.add("A4:54:B8:7A:18:47:A8:9E:D7:F5:E7:0F:BA:6B:BA:96:F3:EF:29:C2:6E:09:81:20:4F:E3:47:BF:23:1D:FD:5B");
+ // f-droid.org signing key
+ hashes.add("A7:02:07:92:4F:61:FF:09:37:1D:54:84:14:5C:4B:EE:77:2C:55:C1:9E:EE:23:2F:57:70:E1:82:71:F7:CB:AE");
+
+ orbot =
+ SignatureUtils.validateBroadcastIntent(context, orbot,
+ hashes, false);
+ }
+
+ if (orbot != null) {
+ isInstalled = true;
+ handler.postDelayed(onStatusTimeout, statusTimeoutMs);
+ context.registerReceiver(orbotStatusReceiver,
+ new IntentFilter(OrbotHelper.ACTION_STATUS));
+ context.sendBroadcast(orbot);
+ } else {
+ isInstalled = false;
+
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onNotYetInstalled();
+ }
+ }
+
+ return (isInstalled);
+ }
+
+ /**
+ * Given that init() returned false, calling installOrbot()
+ * will trigger an attempt to install Orbot from an available
+ * distribution channel (e.g., the Play Store). Only call this
+ * if the user is expecting it, such as in response to tapping
+ * a dialog button or an action bar item.
+ *
+ * Note that installation may take a long time, even if
+ * the user is proceeding with the installation, due to network
+ * speeds, waiting for user input, and so on. Either specify
+ * a long timeout, or consider the timeout to be merely advisory
+ * and use some other user input to cause you to try
+ * init() again after, presumably, Orbot has been installed
+ * and configured by the user.
+ *
+ * If the user does install Orbot, we will attempt init()
+ * again automatically. Hence, you will probably need user input
+ * to tell you when the user has gotten Orbot up and going.
+ *
+ * @param host the Activity that is triggering this work
+ */
+ public void installOrbot(Activity host) {
+ handler.postDelayed(onInstallTimeout, installTimeoutMs);
+
+ IntentFilter filter =
+ new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+
+ filter.addDataScheme("package");
+
+ context.registerReceiver(orbotInstallReceiver, filter);
+ host.startActivity(OrbotHelper.getOrbotInstallIntent(context));
+ }
+
+ private BroadcastReceiver orbotStatusReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TextUtils.equals(intent.getAction(),
+ OrbotHelper.ACTION_STATUS)) {
+ String status = intent.getStringExtra(OrbotHelper.EXTRA_STATUS);
+
+ if (status.equals(OrbotHelper.STATUS_ON)) {
+ lastStatusIntent = intent;
+ handler.removeCallbacks(onStatusTimeout);
+
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onEnabled(intent);
+ }
+ } else if (status.equals(OrbotHelper.STATUS_OFF)) {
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onDisabled();
+ }
+ } else if (status.equals(OrbotHelper.STATUS_STARTING)) {
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onStarting();
+ }
+ } else if (status.equals(OrbotHelper.STATUS_STOPPING)) {
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onStopping();
+ }
+ }
+ }
+ }
+ };
+
+ private Runnable onStatusTimeout = new Runnable() {
+ @Override
+ public void run() {
+ context.unregisterReceiver(orbotStatusReceiver);
+
+ for (StatusCallback cb : statusCallbacks) {
+ cb.onStatusTimeout();
+ }
+ }
+ };
+
+ private BroadcastReceiver orbotInstallReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TextUtils.equals(intent.getAction(),
+ Intent.ACTION_PACKAGE_ADDED)) {
+ String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+
+ if (OrbotHelper.ORBOT_PACKAGE_NAME.equals(pkgName)) {
+ isInstalled = true;
+ handler.removeCallbacks(onInstallTimeout);
+ context.unregisterReceiver(orbotInstallReceiver);
+
+ for (InstallCallback cb : installCallbacks) {
+ cb.onInstalled();
+ }
+
+ init();
+ }
+ }
+ }
+ };
+
+ private Runnable onInstallTimeout = new Runnable() {
+ @Override
+ public void run() {
+ context.unregisterReceiver(orbotInstallReceiver);
+
+ for (InstallCallback cb : installCallbacks) {
+ cb.onInstallTimeout();
+ }
+ }
+ };
+
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ static Set newSetFromMap(Map map) {
+ if (map.isEmpty()) {
+ return new SetFromMap(map);
+ }
+ throw new IllegalArgumentException("map not empty");
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxyHelper.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxyHelper.java
new file mode 100644
index 00000000..6e295973
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxyHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2016 Nathan Freitas
+
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.guardianproject.netcipher.proxy;
+
+import android.content.Context;
+import android.content.Intent;
+
+public interface ProxyHelper {
+
+ public boolean isInstalled(Context context);
+
+ public void requestStatus(Context context);
+
+ public boolean requestStart(Context context);
+
+ public Intent getInstallIntent(Context context);
+
+ public Intent getStartIntent(Context context);
+
+ public String getName();
+
+ public final static String FDROID_PACKAGE_NAME = "org.fdroid.fdroid";
+ public final static String PLAY_PACKAGE_NAME = "com.android.vending";
+
+ /**
+ * A request to Orbot to transparently start Tor services
+ */
+ public final static String ACTION_START = "android.intent.action.PROXY_START";
+ /**
+ * {@link Intent} send by Orbot with {@code ON/OFF/STARTING/STOPPING} status
+ */
+ public final static String ACTION_STATUS = "android.intent.action.PROXY_STATUS";
+ /**
+ * {@code String} that contains a status constant: {@link #STATUS_ON},
+ * {@link #STATUS_OFF}, {@link #STATUS_STARTING}, or
+ * {@link #STATUS_STOPPING}
+ */
+ public final static String EXTRA_STATUS = "android.intent.extra.PROXY_STATUS";
+
+ public final static String EXTRA_PROXY_PORT_HTTP = "android.intent.extra.PROXY_PORT_HTTP";
+ public final static String EXTRA_PROXY_PORT_SOCKS = "android.intent.extra.PROXY_PORT_SOCKS";
+
+ /**
+ * A {@link String} {@code packageName} for Orbot to direct its status reply
+ * to, used in {@link #ACTION_START} {@link Intent}s sent to Orbot
+ */
+ public final static String EXTRA_PACKAGE_NAME = "android.intent.extra.PROXY_PACKAGE_NAME";
+
+ /**
+ * All tor-related services and daemons are stopped
+ */
+ public final static String STATUS_OFF = "OFF";
+ /**
+ * All tor-related services and daemons have completed starting
+ */
+ public final static String STATUS_ON = "ON";
+ public final static String STATUS_STARTING = "STARTING";
+ public final static String STATUS_STOPPING = "STOPPING";
+ /**
+ * The user has disabled the ability for background starts triggered by
+ * apps. Fallback to the old Intent that brings up Orbot.
+ */
+ public final static String STATUS_STARTS_DISABLED = "STARTS_DISABLED";
+}
+
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxySelector.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxySelector.java
new file mode 100644
index 00000000..86687b28
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxySelector.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.guardianproject.netcipher.proxy;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProxySelector extends java.net.ProxySelector {
+
+ private ArrayList listProxies;
+
+ public ProxySelector() {
+ super();
+
+ listProxies = new ArrayList();
+
+
+ }
+
+ public void addProxy(Proxy.Type type, String host, int port) {
+ Proxy proxy = new Proxy(type, new InetSocketAddress(host, port));
+ listProxies.add(proxy);
+ }
+
+ @Override
+ public void connectFailed(URI uri, SocketAddress address,
+ IOException failure) {
+ Log.w("ProxySelector", "could not connect to " + address.toString() + ": " + failure.getMessage());
+ }
+
+ @Override
+ public List select(URI uri) {
+
+ return listProxies;
+ }
+
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/PsiphonHelper.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/PsiphonHelper.java
new file mode 100644
index 00000000..d14880d8
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/PsiphonHelper.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2012-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.guardianproject.netcipher.proxy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.List;
+
+public class PsiphonHelper implements ProxyHelper {
+
+ public final static String PACKAGE_NAME = "com.psiphon3";
+ public final static String COMPONENT_NAME = "com.psiphon3.StatusActivity";
+
+
+ public final static String MARKET_URI = "market://details?id=" + PACKAGE_NAME;
+ public final static String FDROID_URI = "https://f-droid.org/repository/browse/?fdid="
+ + PACKAGE_NAME;
+ public final static String ORBOT_PLAY_URI = "https://play.google.com/store/apps/details?id="
+ + PACKAGE_NAME;
+
+ public final static int DEFAULT_SOCKS_PORT = 1080;
+ public final static int DEFAULT_HTTP_PORT = 8080;
+
+ @Override
+ public boolean isInstalled(Context context) {
+ return isAppInstalled(context, PACKAGE_NAME);
+ }
+
+
+ private static boolean isAppInstalled(Context context, String uri) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void requestStatus(final Context context) {
+
+ Thread thread = new Thread() {
+ public void run() {
+ //can connect to default HTTP proxy port?
+ boolean isSocksOpen = false;
+ boolean isHttpOpen = false;
+
+ int socksPort = DEFAULT_SOCKS_PORT;
+ int httpPort = DEFAULT_HTTP_PORT;
+
+ for (int i = 0; i < 10 && (!isSocksOpen); i++)
+ isSocksOpen = isPortOpen("127.0.0.1", socksPort++, 100);
+
+ for (int i = 0; i < 10 && (!isHttpOpen); i++)
+ isHttpOpen = isPortOpen("127.0.0.1", httpPort++, 100);
+
+ //any other check?
+
+ Intent intent = new Intent(ProxyHelper.ACTION_STATUS);
+ intent.putExtra(EXTRA_PACKAGE_NAME, PACKAGE_NAME);
+
+ if (isSocksOpen && isHttpOpen) {
+ intent.putExtra(EXTRA_STATUS, STATUS_ON);
+
+ intent.putExtra(EXTRA_PROXY_PORT_HTTP, httpPort - 1);
+ intent.putExtra(EXTRA_PROXY_PORT_SOCKS, socksPort - 1);
+
+
+ } else {
+ intent.putExtra(EXTRA_STATUS, STATUS_OFF);
+ }
+
+ context.sendBroadcast(intent);
+ }
+ };
+
+ thread.start();
+
+ }
+
+ @Override
+ public boolean requestStart(Context context) {
+
+ Intent intent = getStartIntent(context);
+ // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+
+ return true;
+ }
+
+ @Override
+ public Intent getInstallIntent(Context context) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(MARKET_URI));
+
+ PackageManager pm = context.getPackageManager();
+ List resInfos = pm.queryIntentActivities(intent, 0);
+
+ String foundPackageName = null;
+ for (ResolveInfo r : resInfos) {
+ if (TextUtils.equals(r.activityInfo.packageName, FDROID_PACKAGE_NAME)
+ || TextUtils.equals(r.activityInfo.packageName, PLAY_PACKAGE_NAME)) {
+ foundPackageName = r.activityInfo.packageName;
+ break;
+ }
+ }
+
+ if (foundPackageName == null) {
+ intent.setData(Uri.parse(FDROID_URI));
+ } else {
+ intent.setPackage(foundPackageName);
+ }
+ return intent;
+ }
+
+ @Override
+ public Intent getStartIntent(Context context) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(PACKAGE_NAME, COMPONENT_NAME));
+
+ return intent;
+ }
+
+ public static boolean isPortOpen(final String ip, final int port, final int timeout) {
+ try {
+ Socket socket = new Socket();
+ socket.connect(new InetSocketAddress(ip, port), timeout);
+ socket.close();
+ return true;
+ } catch (ConnectException ce) {
+ ce.printStackTrace();
+ return false;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+
+ @Override
+ public String getName() {
+ return PACKAGE_NAME;
+ }
+
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SetFromMap.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SetFromMap.java
new file mode 100644
index 00000000..1a633161
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SetFromMap.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.proxy;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+class SetFromMap extends AbstractSet
+ implements Serializable {
+ private static final long serialVersionUID = 2454657854757543876L;
+ // Must be named as is, to pass serialization compatibility test.
+ private final Map m;
+ private transient Set backingSet;
+
+ SetFromMap(final Map map) {
+ m = map;
+ backingSet = map.keySet();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return backingSet.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return backingSet.hashCode();
+ }
+
+ @Override
+ public boolean add(E object) {
+ return m.put(object, Boolean.TRUE) == null;
+ }
+
+ @Override
+ public void clear() {
+ m.clear();
+ }
+
+ @Override
+ public String toString() {
+ return backingSet.toString();
+ }
+
+ @Override
+ public boolean contains(Object object) {
+ return backingSet.contains(object);
+ }
+
+ @Override
+ public boolean containsAll(Collection> collection) {
+ return backingSet.containsAll(collection);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return m.isEmpty();
+ }
+
+ @Override
+ public boolean remove(Object object) {
+ return m.remove(object) != null;
+ }
+
+ @Override
+ public boolean retainAll(Collection> collection) {
+ return backingSet.retainAll(collection);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return backingSet.toArray();
+ }
+
+ @Override
+ public T[] toArray(T[] contents) {
+ return backingSet.toArray(contents);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return backingSet.iterator();
+ }
+
+ @Override
+ public int size() {
+ return m.size();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ backingSet = m.keySet();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SignatureUtils.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SignatureUtils.java
new file mode 100644
index 00000000..4758f5a2
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SignatureUtils.java
@@ -0,0 +1,468 @@
+/***
+ * Copyright (c) 2014 CommonsWare, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.proxy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SignatureUtils {
+ public static String getOwnSignatureHash(Context context)
+ throws
+ NameNotFoundException,
+ NoSuchAlgorithmException {
+ return (getSignatureHash(context, context.getPackageName()));
+ }
+
+ public static String getSignatureHash(Context context, String packageName)
+ throws
+ NameNotFoundException,
+ NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ Signature sig =
+ context.getPackageManager()
+ .getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
+
+ return (toHexStringWithColons(md.digest(sig.toByteArray())));
+ }
+
+ // based on https://stackoverflow.com/a/2197650/115145
+
+ public static String toHexStringWithColons(byte[] bytes) {
+ char[] hexArray =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F'};
+ char[] hexChars = new char[(bytes.length * 3) - 1];
+ int v;
+
+ for (int j = 0; j < bytes.length; j++) {
+ v = bytes[j] & 0xFF;
+ hexChars[j * 3] = hexArray[v / 16];
+ hexChars[j * 3 + 1] = hexArray[v % 16];
+
+ if (j < bytes.length - 1) {
+ hexChars[j * 3 + 2] = ':';
+ }
+ }
+
+ return new String(hexChars);
+ }
+
+ /**
+ * Confirms that the broadcast receiver for a given Intent
+ * has the desired signature hash.
+ *
+ * If you know the package name of the receiver, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has the proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some receiver whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * receiver was found that matches the Intent. If failIfHack
+ * is false, this means that no receiver was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching receiver
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching receiver, so the "broadcast" will only go to this
+ * one component.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to broadcast
+ * @param sigHash the signature hash of the app that you expect
+ * to handle this broadcast
+ * @param failIfHack true if you want a SecurityException if
+ * a matching receiver is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching receiver with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target receiver added to the Intent
+ */
+ public static Intent validateBroadcastIntent(Context context,
+ Intent toValidate,
+ String sigHash,
+ boolean failIfHack) {
+ ArrayList sigHashes = new ArrayList();
+
+ sigHashes.add(sigHash);
+
+ return (validateBroadcastIntent(context, toValidate, sigHashes,
+ failIfHack));
+ }
+
+ /**
+ * Confirms that the broadcast receiver for a given Intent
+ * has a desired signature hash.
+ *
+ * If you know the package name of the receiver, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has a proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some receiver whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * receiver was found that matches the Intent. If failIfHack
+ * is false, this means that no receiver was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching receiver
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching receiver, so the "broadcast" will only go to this
+ * one component.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to broadcast
+ * @param sigHashes the possible signature hashes of the app
+ * that you expect to handle this broadcast
+ * @param failIfHack true if you want a SecurityException if
+ * a matching receiver is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching receiver with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target receiver added to the Intent
+ */
+ public static Intent validateBroadcastIntent(Context context,
+ Intent toValidate,
+ List sigHashes,
+ boolean failIfHack) {
+ PackageManager pm = context.getPackageManager();
+ Intent result = null;
+ List receivers =
+ pm.queryBroadcastReceivers(toValidate, 0);
+
+ if (receivers != null) {
+ for (ResolveInfo info : receivers) {
+ try {
+ if (sigHashes.contains(getSignatureHash(context,
+ info.activityInfo.packageName))) {
+ ComponentName cn =
+ new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+
+ result = new Intent(toValidate).setComponent(cn);
+ break;
+ } else if (failIfHack) {
+ throw new SecurityException(
+ "Package has signature hash mismatch: " +
+ info.activityInfo.packageName);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ } catch (NameNotFoundException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ }
+ }
+ }
+
+ return (result);
+ }
+
+ /**
+ * Confirms that the activity for a given Intent has the
+ * desired signature hash.
+ *
+ * If you know the package name of the activity, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has the proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some activity whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * activity was found that matches the Intent. If failIfHack
+ * is false, this means that no activity was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching activity
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching activity, so a call to startActivity() for this
+ * Intent is guaranteed to go to this specific activity.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to use with
+ * startActivity()
+ * @param sigHash the signature hash of the app that you expect
+ * to handle this activity
+ * @param failIfHack true if you want a SecurityException if
+ * a matching activity is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching activity with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target activity added to the Intent
+ */
+ public static Intent validateActivityIntent(Context context,
+ Intent toValidate,
+ String sigHash,
+ boolean failIfHack) {
+ ArrayList sigHashes = new ArrayList();
+
+ sigHashes.add(sigHash);
+
+ return (validateActivityIntent(context, toValidate, sigHashes,
+ failIfHack));
+ }
+
+ /**
+ * Confirms that the activity for a given Intent has the
+ * desired signature hash.
+ *
+ * If you know the package name of the activity, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has the proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some activity whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * activity was found that matches the Intent. If failIfHack
+ * is false, this means that no activity was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching activity
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching activity, so a call to startActivity() for this
+ * Intent is guaranteed to go to this specific activity.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to use with
+ * startActivity()
+ * @param sigHashes the signature hashes of the app that you expect
+ * to handle this activity
+ * @param failIfHack true if you want a SecurityException if
+ * a matching activity is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching activity with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target activity added to the Intent
+ */
+ public static Intent validateActivityIntent(Context context,
+ Intent toValidate,
+ List sigHashes,
+ boolean failIfHack) {
+ PackageManager pm = context.getPackageManager();
+ Intent result = null;
+ List activities =
+ pm.queryIntentActivities(toValidate, 0);
+
+ if (activities != null) {
+ for (ResolveInfo info : activities) {
+ try {
+ if (sigHashes.contains(getSignatureHash(context,
+ info.activityInfo.packageName))) {
+ ComponentName cn =
+ new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+
+ result = new Intent(toValidate).setComponent(cn);
+ break;
+ } else if (failIfHack) {
+ throw new SecurityException(
+ "Package has signature hash mismatch: " +
+ info.activityInfo.packageName);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ } catch (NameNotFoundException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ }
+ }
+ }
+
+ return (result);
+ }
+
+ /**
+ * Confirms that the service for a given Intent has the
+ * desired signature hash.
+ *
+ * If you know the package name of the service, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has the proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some service whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * service was found that matches the Intent. If failIfHack
+ * is false, this means that no service was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching service
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching service, so a call to startService() or
+ * bindService() for this Intent is guaranteed to go to this
+ * specific service.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to use with
+ * startService() or bindService()
+ * @param sigHash the signature hash of the app that you expect
+ * to handle this service
+ * @param failIfHack true if you want a SecurityException if
+ * a matching service is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching service with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target service added to the Intent
+ */
+ public static Intent validateServiceIntent(Context context,
+ Intent toValidate,
+ String sigHash,
+ boolean failIfHack) {
+ ArrayList sigHashes = new ArrayList();
+
+ sigHashes.add(sigHash);
+
+ return (validateServiceIntent(context, toValidate, sigHashes,
+ failIfHack));
+ }
+
+ /**
+ * Confirms that the service for a given Intent has the
+ * desired signature hash.
+ *
+ * If you know the package name of the service, call
+ * setPackage() on the Intent before passing into this method.
+ * That will validate whether the package is installed and whether
+ * it has the proper signature hash. You can distinguish between
+ * these cases by passing true for the failIfHack parameter.
+ *
+ * In general, there are three possible outcomes of calling
+ * this method:
+ *
+ * 1. You get a SecurityException, because failIfHack is true,
+ * and we found some service whose app does not match the
+ * desired hash. The user may have installed a repackaged
+ * version of this app that is signed by the wrong key.
+ *
+ * 2. You get null. If failIfHack is true, this means that no
+ * service was found that matches the Intent. If failIfHack
+ * is false, this means that no service was found that matches
+ * the Intent and has a valid matching signature.
+ *
+ * 3. You get an Intent. This means we found a matching service
+ * that has a matching signature. The Intent will be a copy of
+ * the passed-in Intent, with the component name set to the
+ * matching service, so a call to startService() or
+ * bindService() for this Intent is guaranteed to go to this
+ * specific service.
+ *
+ * @param context any Context will do; the value is not retained
+ * @param toValidate the Intent that you intend to use with
+ * startService() or bindService()
+ * @param sigHashes the signature hash of the app that you expect
+ * to handle this service
+ * @param failIfHack true if you want a SecurityException if
+ * a matching service is found but it has
+ * the wrong signature hash, false otherwise
+ * @return null if there is no matching service with the correct
+ * hash, or a copy of the toValidate parameter with the full component
+ * name of the target service added to the Intent
+ */
+ public static Intent validateServiceIntent(Context context,
+ Intent toValidate,
+ List sigHashes,
+ boolean failIfHack) {
+ PackageManager pm = context.getPackageManager();
+ Intent result = null;
+ List services =
+ pm.queryIntentServices(toValidate, 0);
+
+ if (services != null) {
+ for (ResolveInfo info : services) {
+ try {
+ if (sigHashes.contains(getSignatureHash(context,
+ info.serviceInfo.packageName))) {
+ ComponentName cn =
+ new ComponentName(info.serviceInfo.packageName,
+ info.serviceInfo.name);
+
+ result = new Intent(toValidate).setComponent(cn);
+ break;
+ } else if (failIfHack) {
+ throw new SecurityException(
+ "Package has signature hash mismatch: " +
+ info.activityInfo.packageName);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ } catch (NameNotFoundException e) {
+ Log.w("SignatureUtils",
+ "Exception when computing signature hash", e);
+ }
+ }
+ }
+
+ return (result);
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/StatusCallback.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/StatusCallback.java
new file mode 100644
index 00000000..0616a498
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/StatusCallback.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 CommonsWare, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.proxy;
+
+import android.content.Intent;
+
+/**
+ * Callback interface used for reporting Orbot status
+ */
+public interface StatusCallback {
+ /**
+ * Called when Orbot is operational
+ *
+ * @param statusIntent an Intent containing information about
+ * Orbot, including proxy ports
+ */
+ void onEnabled(Intent statusIntent);
+
+ /**
+ * Called when Orbot reports that it is starting up
+ */
+ void onStarting();
+
+ /**
+ * Called when Orbot reports that it is shutting down
+ */
+ void onStopping();
+
+ /**
+ * Called when Orbot reports that it is no longer running
+ */
+ void onDisabled();
+
+ /**
+ * Called if our attempt to get a status from Orbot failed
+ * after a defined period of time. See statusTimeout() on
+ * OrbotInitializer.
+ */
+ void onStatusTimeout();
+
+ /**
+ * Called if Orbot is not yet installed. Usually, you handle
+ * this by checking the return value from init() on OrbotInitializer
+ * or calling isInstalled() on OrbotInitializer. However, if
+ * you have need for it, if a callback is registered before
+ * an init() call determines that Orbot is not installed, your
+ * callback will be called with onNotYetInstalled().
+ */
+ void onNotYetInstalled();
+}
diff --git a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/TorServiceUtils.java b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/TorServiceUtils.java
new file mode 100644
index 00000000..7fcd6236
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/TorServiceUtils.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2009-2016 Nathan Freitas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.guardianproject.netcipher.proxy;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.URLEncoder;
+import java.util.StringTokenizer;
+
+public class TorServiceUtils {
+
+ private final static String TAG = "TorUtils";
+ // various console cmds
+ public final static String SHELL_CMD_CHMOD = "chmod";
+ public final static String SHELL_CMD_KILL = "kill -9";
+ public final static String SHELL_CMD_RM = "rm";
+ public final static String SHELL_CMD_PS = "ps";
+ public final static String SHELL_CMD_PIDOF = "pidof";
+
+ public final static String CHMOD_EXE_VALUE = "700";
+
+ public static boolean isRootPossible() {
+
+ StringBuilder log = new StringBuilder();
+
+ try {
+
+ // Check if Superuser.apk exists
+ File fileSU = new File("/system/app/Superuser.apk");
+ if (fileSU.exists())
+ return true;
+
+ fileSU = new File("/system/app/superuser.apk");
+ if (fileSU.exists())
+ return true;
+
+ fileSU = new File("/system/bin/su");
+ if (fileSU.exists()) {
+ String[] cmd = {
+ "su"
+ };
+ int exitCode = TorServiceUtils.doShellCommand(cmd, log, false, true);
+ if (exitCode != 0)
+ return false;
+ else
+ return true;
+ }
+
+ // Check for 'su' binary
+ String[] cmd = {
+ "which su"
+ };
+ int exitCode = TorServiceUtils.doShellCommand(cmd, log, false, true);
+
+ if (exitCode == 0) {
+ Log.d(TAG, "root exists, but not sure about permissions");
+ return true;
+
+ }
+
+ } catch (IOException e) {
+ // this means that there is no root to be had (normally) so we won't
+ // log anything
+ Log.e(TAG, "Error checking for root access", e);
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error checking for root access", e);
+ // this means that there is no root to be had (normally)
+ }
+
+ Log.e(TAG, "Could not acquire root permissions");
+
+ return false;
+ }
+
+ public static int findProcessId(Context context) {
+ String dataPath = context.getFilesDir().getParentFile().getParentFile().getAbsolutePath();
+ String command = dataPath + "/" + OrbotHelper.ORBOT_PACKAGE_NAME + "/app_bin/tor";
+ int procId = -1;
+
+ try {
+ procId = findProcessIdWithPidOf(command);
+
+ if (procId == -1)
+ procId = findProcessIdWithPS(command);
+ } catch (Exception e) {
+ try {
+ procId = findProcessIdWithPS(command);
+ } catch (Exception e2) {
+ Log.e(TAG, "Unable to get proc id for command: " + URLEncoder.encode(command), e2);
+ }
+ }
+
+ return procId;
+ }
+
+ // use 'pidof' command
+ public static int findProcessIdWithPidOf(String command) throws Exception {
+
+ int procId = -1;
+
+ Runtime r = Runtime.getRuntime();
+
+ Process procPs = null;
+
+ String baseName = new File(command).getName();
+ // fix contributed my mikos on 2010.12.10
+ procPs = r.exec(new String[]{
+ SHELL_CMD_PIDOF, baseName
+ });
+ // procPs = r.exec(SHELL_CMD_PIDOF);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
+ String line = null;
+
+ while ((line = reader.readLine()) != null) {
+
+ try {
+ // this line should just be the process id
+ procId = Integer.parseInt(line.trim());
+ break;
+ } catch (NumberFormatException e) {
+ Log.e("TorServiceUtils", "unable to parse process pid: " + line, e);
+ }
+ }
+
+ return procId;
+
+ }
+
+ // use 'ps' command
+ public static int findProcessIdWithPS(String command) throws Exception {
+
+ int procId = -1;
+
+ Runtime r = Runtime.getRuntime();
+
+ Process procPs = null;
+
+ procPs = r.exec(SHELL_CMD_PS);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
+ String line = null;
+
+ while ((line = reader.readLine()) != null) {
+ if (line.indexOf(' ' + command) != -1) {
+
+ StringTokenizer st = new StringTokenizer(line, " ");
+ st.nextToken(); // proc owner
+
+ procId = Integer.parseInt(st.nextToken().trim());
+
+ break;
+ }
+ }
+
+ return procId;
+
+ }
+
+ public static int doShellCommand(String[] cmds, StringBuilder log, boolean runAsRoot,
+ boolean waitFor) throws Exception {
+
+ Process proc = null;
+ int exitCode = -1;
+
+ if (runAsRoot)
+ proc = Runtime.getRuntime().exec("su");
+ else
+ proc = Runtime.getRuntime().exec("sh");
+
+ OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
+
+ for (int i = 0; i < cmds.length; i++) {
+ // TorService.logMessage("executing shell cmd: " + cmds[i] +
+ // "; runAsRoot=" + runAsRoot + ";waitFor=" + waitFor);
+
+ out.write(cmds[i]);
+ out.write("\n");
+ }
+
+ out.flush();
+ out.write("exit\n");
+ out.flush();
+
+ if (waitFor) {
+
+ final char buf[] = new char[10];
+
+ // Consume the "stdout"
+ InputStreamReader reader = new InputStreamReader(proc.getInputStream());
+ int read = 0;
+ while ((read = reader.read(buf)) != -1) {
+ if (log != null)
+ log.append(buf, 0, read);
+ }
+
+ // Consume the "stderr"
+ reader = new InputStreamReader(proc.getErrorStream());
+ read = 0;
+ while ((read = reader.read(buf)) != -1) {
+ if (log != null)
+ log.append(buf, 0, read);
+ }
+
+ exitCode = proc.waitFor();
+
+ }
+
+ return exitCode;
+
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/torProxyServer.java b/app/src/main/java/com/example/myapplication/torProxyServer.java
deleted file mode 100644
index ff99eab3..00000000
--- a/app/src/main/java/com/example/myapplication/torProxyServer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.example.myapplication;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import info.guardianproject.netcipher.NetCipher;
-import info.guardianproject.netcipher.proxy.OrbotHelper;
-import android.util.Log;
-import info.guardianproject.netcipher.proxy.StatusCallback;
-
-public class torProxyServer {
- private static final torProxyServer ourInstance = new torProxyServer();
-
- public static torProxyServer getInstance() {
- return ourInstance;
- }
-
- private torProxyServer() {
- }
-
- public void initialize(Context applicationContext, final Activity activity)
- {
- if (OrbotHelper.isOrbotInstalled(activity))
- {
- NetCipher.useTor();
- OrbotHelper.get(activity).statusTimeout(60000).addStatusCallback(new StatusCallback(){
- @Override
- public void onEnabled(Intent intent){ Log.d("Log Started","Log Started"); }
-
- @Override
- public void onStarting() { }
-
- @Override
- public void onStopping(){ }
-
- @Override
- public void onDisabled(){ }
-
- @Override
- public void onStatusTimeout(){ }
-
- @Override
- public void onNotYetInstalled(){ }
- }).init();
- }
- else
- {
- Intent intent = OrbotHelper.getOrbotInstallIntent(activity);
- activity.startActivityForResult(intent,0);
- }
- }
-}
diff --git a/app/src/main/java/com/example/myapplication/webRequestHandler.java b/app/src/main/java/com/example/myapplication/webRequestHandler.java
index e467c781..1b15c5e2 100644
--- a/app/src/main/java/com/example/myapplication/webRequestHandler.java
+++ b/app/src/main/java/com/example/myapplication/webRequestHandler.java
@@ -1,5 +1,6 @@
package com.example.myapplication;
+import android.content.Context;
import android.os.Message;
import android.support.constraint.ConstraintLayout;
import android.util.Log;
@@ -7,18 +8,29 @@ import android.view.View;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.ProgressBar;
-import cz.msebera.android.httpclient.HttpResponse;
-import cz.msebera.android.httpclient.client.HttpClient;
-import cz.msebera.android.httpclient.client.methods.HttpGet;
-import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
+import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import android.os.Handler;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
-public class webRequestHandler
+import android.os.Handler;
+import cz.msebera.android.httpclient.HttpHost;
+import cz.msebera.android.httpclient.HttpResponse;
+import cz.msebera.android.httpclient.client.HttpClient;
+import cz.msebera.android.httpclient.client.methods.HttpGet;
+import cz.msebera.android.httpclient.conn.params.ConnRoutePNames;
+import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
+import info.guardianproject.netcipher.NetCipher;
+import info.guardianproject.netcipher.client.StrongBuilder;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+
+import javax.net.ssl.HttpsURLConnection;
+
+public class webRequestHandler implements StrongBuilder.Callback
{
private static final webRequestHandler ourInstance = new webRequestHandler();
private WebView[] view = new WebView[2];;
@@ -29,10 +41,15 @@ public class webRequestHandler
private Boolean isLoading = false;
private ProgressBar progressBar;
private EditText searchbar;
- private HttpClient client = null;
private Thread clientThread = null;
- private Boolean isRendering = false;
private ConstraintLayout requestFailure;
+ HttpGet request = null;
+
+ // test the local device proxy provided by Orbot/Tor
+ private final static String PROXY_HOST = "127.0.0.1";
+ private final static int PROXY_HTTP_PORT = 8118; // default for Orbot/Tor
+ private final static int PROXY_SOCKS_PORT = 9050; // default for Orbot/Tor
+ private Proxy.Type mProxyType = null;
public static webRequestHandler getInstance() {
return ourInstance;
@@ -42,44 +59,42 @@ public class webRequestHandler
{
}
- public void initialization(WebView view1,WebView view2,ProgressBar progressBar,EditText searchbar,ConstraintLayout requestFailure)
+ public void initialization(WebView view1, WebView view2, ProgressBar progressBar, EditText searchbar, ConstraintLayout requestFailure, Context applicationContext)
{
this.view[0] = view1;
this.view[1] = view2;
this.progressBar = progressBar;
this.searchbar = searchbar;
this.requestFailure = requestFailure;
+ OrbotHelper.get(applicationContext).init();
createUpdateUiHandler();
}
+ public boolean isReloadedUrl = false;
public void loadURL(final String url)
{
+ Log.d("ME HERE 1 : ","SUPER WOW");
try
{
- progressBar.setVisibility(View.VISIBLE);
- if(isRendering)
+ if(!datamodel.getInstance().getIsLoadingURL())
{
- return;
+ datamodel.getInstance().setIsLoadingURL(true);
}
-
- if(!isLoading)
+ else
{
+ request.abort();
+ isReloadedUrl = true;
+ clientThread.stop();
searchbar.setText(url.replace("http://boogle.store","http://genesis.onion"));
}
- else if(client!=null)
- {
- client.getConnectionManager().shutdown();
- isLoading = false;
- }
- if(clientThread!=null)
- {
- clientThread.interrupt();
- }
- client = new DefaultHttpClient();
+ progressBar.animate().alpha(0f);
+ progressBar.setVisibility(View.VISIBLE);
+ progressBar.animate().setDuration(300).alpha(1f);
+
}
catch (Exception ex)
{
- Log.d("SUPER WOW1","SUPER WOW");
+ Log.d("ERROR : ","SUPER WOW");
}
clientThread = new Thread(new Runnable() {
@@ -87,8 +102,10 @@ public class webRequestHandler
public void run() {
try
{
- isLoading = true;
- HttpGet request = new HttpGet(url);
+ if(url.contains("boogle.store"))
+ {
+ HttpClient client = new DefaultHttpClient();
+ request = new HttpGet(url);
baseURL = url;
HttpResponse response = client.execute(request);
InputStream in = response.getEntity().getContent();
@@ -98,31 +115,67 @@ public class webRequestHandler
while((line = reader.readLine()) != null)
{
- if(!isLoading)
- {
- return;
- }
str.append(line);
}
in.close();
+
html = str.toString();
Message message = new Message();
message.what = MESSAGE_UPDATE_TEXT_CHILD_THREAD;
updateUIHandler.sendMessage(message);
+ }
+ else
+ {
+ proxyConnection(url);
+ }
}
catch (Exception e)
{
- Message message = new Message();
- message.what = INTERNET_ERROR;
- updateUIHandler.sendMessage(message);
- Log.d("SUPER WOW2","SUPER WOW");
- e.printStackTrace();
+ if(!isReloadedUrl)
+ {
+ Message message = new Message();
+ message.what = INTERNET_ERROR;
+ updateUIHandler.sendMessage(message);
+ Log.d("ERROR : ","SUPER WOW");
+ e.printStackTrace();
+ }
+ isReloadedUrl = false;
}
}
});
clientThread.start();
}
+ public void proxyConnection(String url) throws Exception {
+ NetCipher.useTor();
+ HttpURLConnection connection = NetCipher.getHttpURLConnection(url);
+ connection.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
+ connection.setRequestProperty("Accept","*/*");
+ connection.connect();
+ int status = connection.getResponseCode();
+
+ int responseCode = connection.getResponseCode(); //can call this instead of con.connect()
+ InputStream in;
+ if (responseCode >= 400 && responseCode <= 499) {
+ throw new Exception("Bad authentication status: " + responseCode); //provide a more meaningful exception message
+ }
+ else {
+ in = connection.getInputStream();
+ }
+
+ BufferedReader br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
+ StringBuilder sb = new StringBuilder();
+ String output;
+ while ((output = br.readLine()) != null) {
+ sb.append(output);
+ }
+ html = sb.toString();
+
+ Message message = new Message();
+ message.what = MESSAGE_UPDATE_TEXT_CHILD_THREAD;
+ updateUIHandler.sendMessage(message);
+ }
+
private Handler updateUIHandler = null;
private final static int MESSAGE_UPDATE_TEXT_CHILD_THREAD =1;
private final static int INTERNET_ERROR =2;
@@ -142,9 +195,8 @@ public class webRequestHandler
@Override
public void handleMessage(Message msg) {
Log.i("APPLYING : ","SUCCESS : APPLYING");
- if(msg.what == MESSAGE_UPDATE_TEXT_CHILD_THREAD && isLoading &&!isRendering)
+ if(msg.what == MESSAGE_UPDATE_TEXT_CHILD_THREAD)
{
- isRendering = true;
view[viewIndex].animate().setDuration(0).alpha(0f);
view[viewIndex].bringToFront();
view[viewIndex].loadDataWithBaseURL(baseURL,html, "text/html", "utf-8", null);
@@ -163,22 +215,42 @@ public class webRequestHandler
@Override
public void run()
{
- isLoading = false;
- progressBar.setVisibility(View.INVISIBLE);
- isRendering = false;
}
}));
}
else if (msg.what == INTERNET_ERROR)
{
- isRendering = false;
- isLoading = false;
- progressBar.setVisibility(View.INVISIBLE);
+ datamodel.getInstance().setIsLoadingURL(false);
+ progressBar.animate().alpha(0f);
requestFailure.setVisibility(View.VISIBLE);
- requestFailure.animate().alpha(1f).setDuration(500);
+ requestFailure.animate().alpha(1f).setDuration(300).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ }
+ }));;
}
}
};
}
}
+
+ @Override
+ public void onConnected(HttpClient httpClient) {
+
+ }
+
+ @Override
+ public void onConnectionException(Exception e) {
+
+ }
+
+ @Override
+ public void onTimeout() {
+ }
+
+ @Override
+ public void onInvalid() {
+
+ }
}
diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png
new file mode 100644
index 00000000..b989bc39
Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ
diff --git a/app/src/main/res/drawable/logolarge.png b/app/src/main/res/drawable/logolarge.png
index 50585dfb..6d774873 100644
Binary files a/app/src/main/res/drawable/logolarge.png and b/app/src/main/res/drawable/logolarge.png differ
diff --git a/app - Copy/src/main/res/drawable/logolarge.png b/app/src/main/res/drawable/logolarges.png
similarity index 100%
rename from app - Copy/src/main/res/drawable/logolarge.png
rename to app/src/main/res/drawable/logolarges.png
diff --git a/app/src/main/res/layout/activity_application_controller.xml b/app/src/main/res/layout/activity_application_controller.xml
deleted file mode 100644
index 0bbdbf9d..00000000
--- a/app/src/main/res/layout/activity_application_controller.xml
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app - Copy/src/main/res/layout/activity_application_controller.xml b/app/src/main/res/layout/applicationView.xml
similarity index 89%
rename from app - Copy/src/main/res/layout/activity_application_controller.xml
rename to app/src/main/res/layout/applicationView.xml
index 0bbdbf9d..8d984575 100644
--- a/app - Copy/src/main/res/layout/activity_application_controller.xml
+++ b/app/src/main/res/layout/applicationView.xml
@@ -14,15 +14,23 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="55dp"
- tools:layout_editor_absoluteY="8dp" tools:layout_editor_absoluteX="8dp">
+ tools:layout_editor_absoluteY="0dp" tools:layout_editor_absoluteX="0dp">
+ tools:layout_editor_absoluteY="0dp" tools:layout_editor_absoluteX="0dp">
+
+
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png
index 44ce853e..0f65ff40 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png
index 44ce853e..e8300e72 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png
index 44ce853e..60f9d447 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png
index 44ce853e..ed9909b7 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png
index 44ce853e..93f7637b 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png
index 44ce853e..d55836b5 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png
index 44ce853e..2125b208 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png
index 44ce853e..f7079b29 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png
index 44ce853e..f34591cf 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png
index 44ce853e..bea017c1 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index b8379b69..24b5566a 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -5,4 +5,5 @@
#000000#0066ff#b3b3b3
+ #009933
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..79e4f406
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build - Copy.gradle b/build - Copy.gradle
deleted file mode 100644
index a65bf842..00000000
--- a/build - Copy.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- ext.kotlin_version = '1.3.20'
- repositories {
- google()
- jcenter()
- maven { url 'https://jitpack.io' }
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.3.1'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- maven { url 'https://jitpack.io' }
- }
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/constraint/group-index.xml b/build - Copy/intermediates/lint-cache/maven.google/com/android/support/constraint/group-index.xml
deleted file mode 100644
index 88c2c420..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/constraint/group-index.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/group-index.xml b/build - Copy/intermediates/lint-cache/maven.google/com/android/support/group-index.xml
deleted file mode 100644
index c2e0c79c..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/group-index.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/espresso/group-index.xml b/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/espresso/group-index.xml
deleted file mode 100644
index 36d0dd61..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/espresso/group-index.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/group-index.xml b/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/group-index.xml
deleted file mode 100644
index 9571ff3c..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/com/android/support/test/group-index.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/maven.google/com/google/android/gms/group-index.xml b/build - Copy/intermediates/lint-cache/maven.google/com/google/android/gms/group-index.xml
deleted file mode 100644
index 639ab7e3..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/com/google/android/gms/group-index.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/maven.google/master-index.xml b/build - Copy/intermediates/lint-cache/maven.google/master-index.xml
deleted file mode 100644
index 43f59df9..00000000
--- a/build - Copy/intermediates/lint-cache/maven.google/master-index.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build - Copy/intermediates/lint-cache/sdk-registry.xml/sdk-registry.xml b/build - Copy/intermediates/lint-cache/sdk-registry.xml/sdk-registry.xml
deleted file mode 100644
index 2cedebf6..00000000
--- a/build - Copy/intermediates/lint-cache/sdk-registry.xml/sdk-registry.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
index a35aa10b..323897d6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,7 +8,7 @@ buildscript {
maven { url 'https://jitpack.io' }
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.3.2'
+ classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -18,6 +18,7 @@ allprojects {
google()
jcenter()
maven { url 'https://jitpack.io' }
+ maven { url 'https://maven.mozilla.org/maven2/' }
}
}
diff --git a/gradle - Copy.properties b/gradle - Copy.properties
deleted file mode 100644
index 85be9ead..00000000
--- a/gradle - Copy.properties
+++ /dev/null
@@ -1,15 +0,0 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-# Kotlin code style for this project: "official" or "obsolete":
-kotlin.code.style=official
diff --git a/gradle - Copy/wrapper/gradle-wrapper.jar b/gradle - Copy/wrapper/gradle-wrapper.jar
deleted file mode 100644
index f6b961fd..00000000
Binary files a/gradle - Copy/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/gradle - Copy/wrapper/gradle-wrapper.properties b/gradle - Copy/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 981d2c42..00000000
--- a/gradle - Copy/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Sat Feb 23 18:52:38 PKT 2019
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew - Copy b/gradlew - Copy
deleted file mode 100644
index cccdd3d5..00000000
--- a/gradlew - Copy
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env sh
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/gradlew - Copy.bat b/gradlew - Copy.bat
deleted file mode 100644
index f9553162..00000000
--- a/gradlew - Copy.bat
+++ /dev/null
@@ -1,84 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/local - Copy.properties b/local - Copy.properties
deleted file mode 100644
index bc6258cf..00000000
--- a/local - Copy.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-## This file is automatically generated by Android Studio.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file should *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-#
-# Location of the SDK. This is only used by Gradle.
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=E\:\\Program Files\\Android Sdk\\Android\\Sdk
diff --git a/settings - Copy.gradle b/settings - Copy.gradle
deleted file mode 100644
index e7b4def4..00000000
--- a/settings - Copy.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':app'