diff --git a/.idea/misc.xml b/.idea/misc.xml index b6ea2b11..7bfef59d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle b/app/build.gradle index b54657f2..acf110f1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,5 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -apply plugin: 'kotlin-android-extensions' apply plugin: 'maven' ext { @@ -44,25 +41,15 @@ android { 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" implementation 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1' implementation 'info.guardianproject.netcipher:netcipher-okhttp3:2.0.0-alpha1' - implementation 'com.squareup.okhttp3:okhttp:3.4.2' - implementation 'org.apache.httpcomponents:httpcore:4.4.1' - x86Implementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}-x86:${geckoviewVersion}" - x86_64Implementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}-x86_64:${geckoviewVersion}" armImplementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}-armeabi-v7a:${geckoviewVersion}" aarch64Implementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}-arm64-v8a:${geckoviewVersion}" implementation 'com.yarolegovich:lovely-dialog:1.1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'com.android.application' \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0835199a..976ef8b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ - diff --git a/app/src/main/java/com/example/myapplication/applicationController.java b/app/src/main/java/com/example/myapplication/applicationController.java deleted file mode 100644 index c1154258..00000000 --- a/app/src/main/java/com/example/myapplication/applicationController.java +++ /dev/null @@ -1,639 +0,0 @@ -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.text.TextUtils; -import android.util.Patterns; -import android.view.KeyEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; -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 -{ - - /*View Objects*/ - private WebView webView1; - private WebView webView2; - private GeckoView webLoader; - private ProgressBar progressBar; - private ConstraintLayout requestFailure; - private ConstraintLayout splashScreen; - private Button reloadButton; - 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(); - boolean wasBackPressed = false; - boolean isFirstLaunch = true; - - /*Initialization*/ - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - setContentView(R.layout.applicationView); - initializeProxy(); - initializeView(); - initializeAds(); - } - - 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); - requestFailure = (ConstraintLayout) findViewById(R.id.requestFailure); - splashScreen = (ConstraintLayout) findViewById(R.id.splashScreen); - reloadButton = (Button) findViewById(R.id.reloadButton); - 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,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); - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); - - webView1.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); - webView1.setBackgroundColor(Color.WHITE); - webView1.setWebViewClient(loadWebViewClient()); - webView1.getSettings().setJavaScriptEnabled(true); - 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(){ - - @Override - public void onClick(View v) - { - 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; - } - }); - - searchbar.setOnEditorActionListener(new EditText.OnEditorActionListener() - { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) - { - try - { - session1.stop(); - session1.close(); - String url = v.getText().toString(); - if(!url.startsWith("www.")&& !url.startsWith("http://")&& !url.startsWith("https://")){ - url = "www."+url; - } - if(!url.startsWith("http://")&&!url.startsWith("https://")){ - url = "http://"+url; - } - - - boolean isUrlValid = Patterns.WEB_URL.matcher(url).matches(); - - URL host = new URL(url); - if(isUrlValid && host.getHost().replace("www.","").contains(".")) - { - if(host.getHost().contains("boogle.store")||host.getHost().contains("genesis.store")) - { - 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 - { - baseURLError(); - return true; - } - } - else - { - loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all"); - } - reinitOrbot(); - - } - catch (IOException e) - { - loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all"); - e.printStackTrace(); - } - return false; - } - }); - - reloadButton.setOnClickListener(new View.OnClickListener(){ - - @Override - public void onClick(View v) - { - 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 - { - URI uri = new URI(url); - String domain = uri.getHost(); - return domain.startsWith("www.") ? domain.substring(4) : domain; - } - - - @TargetApi(Build.VERSION_CODES.M) - private void onChromeClientProgressChanged(int newProgress) - { - - } - - 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) - { - searchbar.setText(urlList.peek().toString().replaceAll("boogle.store","genesis.onion")); - if(urlList.peek().toString().contains("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 - { - 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() - { - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) - { - searchbar.setText(url.replaceAll("boogle.store","genesis.onion")); - - if(!url.toString().contains("boogle")) - { - //admanager.getInstance().showAd(); - - 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 - { - if(urlList.size()==0 || !currentURL.equals(urlList.peek())) - { - urlList.add(currentURL); - currentURL = url; - } - - loadURLAnimate(url); - return true; - } - } - @Override - public void onPageFinished(WebView view, String url) - { - super.onPageFinished(view, url); - - webView1.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) - { - try - { - sleep(2000); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - hasApplicationLoaded = true; - splashScreen.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((new Runnable() { - @Override - public void run() - { - splashScreen.setVisibility(View.GONE); - } - })); - } - if(!isRequestError) - { - requestFailure.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((new Runnable() { - @Override - public void run() - { - requestFailure.setVisibility(View.GONE); - //reloadButton.setEnabled(false); - } - })); - } - isRequestError = false; - - InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(searchbar.getWindowToken(), 0); - } - - @Override - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) - { - //reloadButton.setEnabled(true); - System.out.println("SUP2"); - requestFailure.setVisibility(View.VISIBLE); - requestFailure.animate().alpha(1.0f); - isRequestError = true; - - super.onReceivedError(view, errorCode, description, failingUrl); - } - }; - - 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/application_controller.java b/app/src/main/java/com/example/myapplication/application_controller.java new file mode 100644 index 00000000..e0f81061 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/application_controller.java @@ -0,0 +1,481 @@ +package com.example.myapplication; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Color; +import android.support.constraint.ConstraintLayout; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Patterns; +import android.view.KeyEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.webkit.*; +import android.widget.*; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Stack; + +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 application_controller extends AppCompatActivity +{ + + /*View Objects*/ + private WebView webView1; + private WebView webView2; + private GeckoView webLoader; + private ProgressBar progressBar; + private ConstraintLayout requestFailure; + private ConstraintLayout splashScreen; + private Button reloadButton; + private ImageButton homeButton; + private EditText searchbar; + private LinearLayout topbar; + private GeckoSession session1; + private GeckoRuntime runtime1; + private String version_code = "1.0"; + + /*helper Variables*/ + Stack traceUrlList = new Stack(); + + /*-------------------------------------------------------INITIALIZATION-------------------------------------------------------*/ + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.application_view); + initializeProxy(); + initializeConnections(); + initializeOrbot(); + initializeWebViews(); + initializeView(); + initializeAds(); + } + + public void versionChecker() + { + String version = preference_manager.getInstance().getString("version","none",this); + if(!version.equals(version_code) && !version.equals("none")) + { + message_manager.getInstance().versionWarning(this); + } + if(version.equals("none")) + { + webRequestHandler.getInstance().getVersion(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); + } + + public void initializeConnections() + { + webView1 = findViewById(R.id.pageLoader1); + webView2 = findViewById(R.id.pageLoader2); + progressBar = findViewById(R.id.progressBar); + requestFailure = findViewById(R.id.requestFailure); + splashScreen = findViewById(R.id.splashScreen); + reloadButton = findViewById(R.id.reloadButton); + homeButton = findViewById(R.id.home); + searchbar = findViewById(R.id.search); + topbar = findViewById(R.id.topbar); + webLoader = findViewById(R.id.webLoader); + } + + public void initializeOrbot() + { + Intent orbot = OrbotHelper.getOrbotStartIntent(getApplicationContext()); + getApplicationContext().registerReceiver(orbot_manager.getInstance().orbotStatusReceiver,new IntentFilter(OrbotHelper.ACTION_STATUS)); + getApplicationContext().sendBroadcast(orbot); + } + + public void initializeWebViews() + { + webRequestHandler.getInstance().initialization(webView1,webView2,progressBar,searchbar,requestFailure,this); + webView1.bringToFront(); + progressBar.animate().alpha(0f); + + session1 = new GeckoSession(); + runtime1 = GeckoRuntime.create(this); + session1.open(runtime1); + webLoader.setSession(session1); + session1.setProgressDelegate(new progressDelegate()); + webLoader.setVisibility(View.INVISIBLE); + } + + /*Initialization*/ + public void initializeView() + { + webView1.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); + webView1.setBackgroundColor(Color.WHITE); + webView1.setWebViewClient(loadWebViewClient()); + webView1.getSettings().setJavaScriptEnabled(true); + webView1.getSettings().setUseWideViewPort(true); + + webView2.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); + webView2.setBackgroundColor(Color.WHITE); + webView2.setWebViewClient(loadWebViewClient()); + webView2.getSettings().setJavaScriptEnabled(true); + webView2.getSettings().setUseWideViewPort(true); + + webView2.animate().setDuration(0).alpha(0f); + progressBar.setVisibility(View.INVISIBLE); + requestFailure.animate().setDuration(0).alpha(0.0f); + progressBar.animate().alpha(0f); + + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + loadURLAnimate(constants.backendUrl); + initializeViewClients(); + } + + private void initializeViewClients() + { + searchbar.setOnEditorActionListener((v, actionId, event) -> { + return onEditorClicked(v, actionId, event); + }); + } + + /*-------------------------------------------------------WEBVIEW LISTENERS-------------------------------------------------------*/ + + private WebViewClient loadWebViewClient() + { + WebViewClient client = new WebViewClient() + { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) + { + searchbar.setText(url.replaceAll("boogle.store","genesis.onion")); + + if(!url.toString().contains("boogle")) + { + //admanager.getInstance().showAd(); + + boolean init_status=orbot_manager.getInstance().reinitOrbot(application_controller.this); + if(!init_status) + { + session1.close(); + session1 = new GeckoSession(); + session1.open(runtime1); + session1.setProgressDelegate(new progressDelegate()); + webLoader.releaseSession(); + webLoader.setSession(session1); + + session1.loadUri(url); + } + return true; + } + else + { + if(traceUrlList.size()==0 || !status.currentURL.equals(traceUrlList.peek())) + { + traceUrlList.add(status.currentURL); + status.currentURL = url; + } + + loadURLAnimate(url); + return true; + } + } + @Override + public void onPageFinished(WebView view, String url) + { + super.onPageFinished(view, url); + + webView1.animate().setDuration(250).alpha(1f); + webView2.animate().setDuration(250).alpha(1f).withEndAction((() -> { + datamodel.getInstance().setIsLoadingURL(false); + requestFailure.animate().alpha(0f).setDuration(300).withEndAction((() -> requestFailure.setVisibility(View.INVISIBLE)));; + + }));; + + progressBar.animate().alpha(0f).withEndAction((() -> progressBar.setVisibility(View.INVISIBLE)));; + + if(!status.hasApplicationLoaded) + { + try + { + sleep(2000); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + status.hasApplicationLoaded = true; + splashScreen.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((() -> splashScreen.setVisibility(View.GONE))); + versionChecker(); + } + + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(searchbar.getWindowToken(), 0); + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) + { + System.out.println("SUP2"); + requestFailure.setVisibility(View.VISIBLE); + requestFailure.animate().alpha(1.0f); + loadErrorPage(); + super.onReceivedError(view, errorCode, description, failingUrl); + } + }; + + if(!helperMethod.isNetworkAvailable(this)) + { + status.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); + loadErrorPage(); + } + + return client; + } + +class progressDelegate 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(); + message_manager.getInstance().baseURLError(application_controller.this); + } + } + catch (MalformedURLException e) + { + e.printStackTrace(); + } + + datamodel.getInstance().setIsLoadingURL(true); + boolean isBlackPage = url.equals("about:blank"); + if(!isBlackPage) + { + traceUrlList.add(status.currentURL); + status.currentURL = url; + } + 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 && webLoader.getVisibility()==View.INVISIBLE) + { + webLoader.bringToFront(); + webLoader.animate().setDuration(100).alpha(1); + webLoader.setVisibility(View.VISIBLE); + + requestFailure.animate().alpha(0f).setDuration(300).withEndAction((() -> requestFailure.setVisibility(View.INVISIBLE)));; + } + } + + @Override + public void onSecurityChange(GeckoSession session, SecurityInformation securityInfo) + { + } +} + /*-------------------------------------------------------Helper Method-------------------------------------------------------*/ + + public void loadErrorPage() + { + requestFailure.animate().alpha(0.0f).setDuration(300).setListener(null).withEndAction((() -> { + requestFailure.setVisibility(View.GONE); + })); + } + + public void loadURLAnimate(String url) + { + webRequestHandler.getInstance().loadURL(url); + } + + /*-------------------------------------------------------EVENT LISTENERS-------------------------------------------------------*/ + + public void onHomeButtonPressed(View view) + { + session1.stop(); + session1.close(); + session1.stop(); + progressBar.animate().alpha(0f); + progressBar.setVisibility(View.VISIBLE); + progressBar.animate().setDuration(300).alpha(1f); + loadURLAnimate("http://boogle.store/"); + } + + public void onReloadButtonPressed(View view) + { + progressBar.animate().alpha(0f); + progressBar.setVisibility(View.VISIBLE); + progressBar.animate().setDuration(300).alpha(1f); + loadURLAnimate(status.currentURL); + } + + @Override + public void onBackPressed() + { + orbot_manager.getInstance().reinitOrbot(this); + if(traceUrlList.size()>0) + { + searchbar.setText(traceUrlList.peek().toString().replaceAll("boogle.store","genesis.onion")); + if(traceUrlList.peek().toString().contains("boogle.store")) + { + if(!status.currentURL.contains("boogle.store")) + { + status.currentURL = traceUrlList.pop().toString(); + progressBar.animate().alpha(0f); + webLoader.animate().setDuration(250).alpha(0); + webLoader.setVisibility(View.INVISIBLE); + } + else + { + loadURLAnimate(traceUrlList.pop().toString()); + if(traceUrlList.size()<=0) + { + status.currentURL = "http://boogle.store/"; + } + else + { + status.currentURL = traceUrlList.peek().toString(); + } + } + } + else + { + if(traceUrlList.size()<=0 || traceUrlList.peek().toString().contains("boogle.store")) + { + status.currentURL = "http://boogle.store/"; + webLoader.animate().setDuration(250).alpha(0); + } + else + { + webLoader.animate().setDuration(250).alpha(1); + status.currentURL = traceUrlList.peek().toString(); + } + traceUrlList.pop(); + session1.stop(); + session1.close(); + session1.stop(); + session1.goBack(); + } + if(traceUrlList.size()==0) + { + searchbar.setText("http://genesis.onion/"); + } + } + } + + public boolean onEditorClicked(TextView v, int actionId, KeyEvent event) + { + try + { + session1.stop(); + session1.close(); + String url = v.getText().toString(); + if(!url.startsWith("www.")&& !url.startsWith("http://")&& !url.startsWith("https://")){ + url = "www."+url; + } + if(!url.startsWith("http://")&&!url.startsWith("https://")){ + url = "http://"+url; + } + + + boolean isUrlValid = Patterns.WEB_URL.matcher(url).matches(); + + URL host = new URL(url); + if(isUrlValid && host.getHost().replace("www.","").contains(".")) + { + if(host.getHost().contains(constants.backendUrlHost)||host.getHost().contains(constants.frontEndUrlHost)) + { + loadURLAnimate(v.getText().toString()); + return true; + } + else if(host.getHost().contains(constants.allowedHost)) + { + if(!orbot_manager.getInstance().reinitOrbot(this.getApplicationContext())) + { + session1.close(); + session1 = new GeckoSession(); + session1.open(runtime1); + session1.setProgressDelegate(new application_controller.progressDelegate()); + webLoader.releaseSession(); + webLoader.setSession(session1); + + session1.loadUri(url); + } + return true; + } + else + { + message_manager.getInstance().baseURLError(this); + return true; + } + } + else + { + loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all"); + } + orbot_manager.getInstance().reinitOrbot(this.getApplicationContext()); + + } + catch (IOException e) + { + loadURLAnimate("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all"); + e.printStackTrace(); + } + return false; + } + +} diff --git a/app/src/main/java/com/example/myapplication/constants.java b/app/src/main/java/com/example/myapplication/constants.java new file mode 100644 index 00000000..c3876d39 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/constants.java @@ -0,0 +1,9 @@ +package com.example.myapplication; + +public class constants +{ + public static String backendUrl = "http://boogle.store"; + public static String backendUrlHost = "boogle.store"; + public static String frontEndUrlHost = "genesis.store"; + public static String allowedHost = ".onion"; +} diff --git a/app/src/main/java/com/example/myapplication/helperMethod.java b/app/src/main/java/com/example/myapplication/helperMethod.java new file mode 100644 index 00000000..db8ee21c --- /dev/null +++ b/app/src/main/java/com/example/myapplication/helperMethod.java @@ -0,0 +1,20 @@ +package com.example.myapplication; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +public class helperMethod +{ + public static boolean isNetworkAvailable(Context application_context) + { + ConnectivityManager cm = (ConnectivityManager) application_context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + if (networkInfo != null && networkInfo.isConnected()) + { + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/example/myapplication/message_manager.java b/app/src/main/java/com/example/myapplication/message_manager.java new file mode 100644 index 00000000..f380fa88 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/message_manager.java @@ -0,0 +1,62 @@ +package com.example.myapplication; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.view.View; +import com.yarolegovich.lovelydialog.LovelyInfoDialog; +import com.yarolegovich.lovelydialog.LovelyStandardDialog; + +public class message_manager { + private static final message_manager ourInstance = new message_manager(); + + public static message_manager getInstance() { + return ourInstance; + } + + private message_manager() { + } + + public void baseURLError(Context application_context) + { + new LovelyInfoDialog(application_context) + .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(Context application_context) + { + new LovelyInfoDialog(application_context) + .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 void versionWarning(Context application_context) + { + new LovelyStandardDialog(application_context) + .setTopColorRes(R.color.header) + .setIcon(R.drawable.logo) + .setTitle("Update Application") + .setMessage("A newer version is availabe please install to get better experience") + .setPositiveButton(android.R.string.ok, new View.OnClickListener() { + @Override + public void onClick(View v) + { + String url = "http://boogle.store/android"; + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + application_context.startActivity(i); + } + }) + .setNegativeButton(android.R.string.no, null) + .show(); + + } + +} diff --git a/app/src/main/java/com/example/myapplication/orbot_manager.java b/app/src/main/java/com/example/myapplication/orbot_manager.java new file mode 100644 index 00000000..f5406e67 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/orbot_manager.java @@ -0,0 +1,81 @@ +package com.example.myapplication; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; +import android.view.View; +import com.yarolegovich.lovelydialog.LovelyStandardDialog; +import info.guardianproject.netcipher.proxy.OrbotHelper; + +public class orbot_manager { + private static final orbot_manager ourInstance = new orbot_manager(); + boolean isOrbotRunning = false; + + public static orbot_manager getInstance() { + return ourInstance; + } + + private orbot_manager() { + } + + public 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)) + { + } + } + } + }; + + public boolean reinitOrbot(Context application_context) + { + if(!OrbotHelper.isOrbotInstalled(application_context)) + { + OrbotHelper.getOrbotInstallIntent(application_context); + new LovelyStandardDialog(application_context) + .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 { + application_context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName))); + } catch (android.content.ActivityNotFoundException anfe) { + application_context.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(application_context).init(); + message_manager.getInstance().startingOrbotInfo(application_context); + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/example/myapplication/preference_manager.java b/app/src/main/java/com/example/myapplication/preference_manager.java new file mode 100644 index 00000000..48d2a85c --- /dev/null +++ b/app/src/main/java/com/example/myapplication/preference_manager.java @@ -0,0 +1,29 @@ +package com.example.myapplication; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class preference_manager { + private static final preference_manager ourInstance = new preference_manager(); + + public static preference_manager getInstance() { + return ourInstance; + } + + private preference_manager() { + } + + public void saveString(String valueKey, String value, Context applicationContext) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext); + SharedPreferences.Editor edit = prefs.edit(); + edit.putString(valueKey, value); + edit.commit(); + } + + public String getString(String valueKey, String valueDefault,Context applicationContext) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext); + return prefs.getString(valueKey, valueDefault); + } + +} 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 deleted file mode 100644 index 663ba539..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/NetCipher.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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 deleted file mode 100644 index c081039b..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/WebkitProxy.java +++ /dev/null @@ -1,754 +0,0 @@ -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) - * { - *

- * String commandLinePath = "/data/local/tmp/orweb.conf"; - * try - * { - * Class webViewCoreClass = Class.forName("org.chromium.content.common.CommandLine"); - *

- * if (webViewCoreClass != null) - * { - * for (Method method : webViewCoreClass.getDeclaredMethods()) - * { - * Log.d("Orweb","Proxy methods: " + method.getName()); - * } - *

- * Method m = webViewCoreClass.getDeclaredMethod("initFromFile", - * String.class); - *

- * if (m != null) - * { - * m.setAccessible(true); - * m.invoke(null, commandLinePath); - * return true; - * } - * else - * return false; - * } - * } 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; - * } - *

- * /** - * private static boolean setKitKatProxy (Context ctx, String host, int port) - * { - *

- * try - * { - * Class webViewCoreClass = Class.forName("android.net.Proxy"); - *

- * Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties"); - * if (webViewCoreClass != null && proxyPropertiesClass != null) - * { - * for (Method method : webViewCoreClass.getDeclaredMethods()) - * { - * Log.d("Orweb","Proxy methods: " + method.getName()); - * } - *

- * Method m = webViewCoreClass.getDeclaredMethod("setHttpProxySystemProperty", - * proxyPropertiesClass); - * 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); - *

- * m.invoke(null, properties); - * return true; - * } - * else - * return false; - * } - * } 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; - * } - *

- * private static boolean resetProxyForKitKat () - * { - *

- * try - * { - * Class webViewCoreClass = Class.forName("android.net.Proxy"); - *

- * Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties"); - * if (webViewCoreClass != null && proxyPropertiesClass != null) - * { - * for (Method method : webViewCoreClass.getDeclaredMethods()) - * { - * Log.d("Orweb","Proxy methods: " + method.getName()); - * } - *

- * Method m = webViewCoreClass.getDeclaredMethod("setHttpProxySystemProperty", - * proxyPropertiesClass); - *

- * if (m != null) - * { - * m.setAccessible(true); - *

- * m.invoke(null, null); - * return true; - * } - * else - * return false; - * } - * } 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; - * } - **/ - - 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 deleted file mode 100644 index 6693700f..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongBuilder.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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 deleted file mode 100644 index 03425cc2..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConnectionBuilder.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5fa85ba3..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/StrongConstants.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 deleted file mode 100644 index b75a9342..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/client/TlsOnlySocketFactory.java +++ /dev/null @@ -1,546 +0,0 @@ -/* - * 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 deleted file mode 100644 index 656ff22e..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/OrbotHelper.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6e295973..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxyHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 deleted file mode 100644 index 86687b28..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/ProxySelector.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 deleted file mode 100644 index d14880d8..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/PsiphonHelper.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1a633161..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SetFromMap.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4758f5a2..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/SignatureUtils.java +++ /dev/null @@ -1,468 +0,0 @@ -/*** - * 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 deleted file mode 100644 index 0616a498..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/StatusCallback.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 deleted file mode 100644 index 7fcd6236..00000000 --- a/app/src/main/java/com/example/myapplication/proxy/netcipher/proxy/TorServiceUtils.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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/status.java b/app/src/main/java/com/example/myapplication/status.java new file mode 100644 index 00000000..919f7388 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/status.java @@ -0,0 +1,7 @@ +package com.example.myapplication; + +public class status +{ + public static boolean hasApplicationLoaded = false; + public static String currentURL = "http://boogle.store/"; +} diff --git a/app/src/main/java/com/example/myapplication/webRequestHandler.java b/app/src/main/java/com/example/myapplication/webRequestHandler.java index 1b15c5e2..6c306dd0 100644 --- a/app/src/main/java/com/example/myapplication/webRequestHandler.java +++ b/app/src/main/java/com/example/myapplication/webRequestHandler.java @@ -1,55 +1,50 @@ package com.example.myapplication; +import android.annotation.SuppressLint; import android.content.Context; import android.os.Message; import android.support.constraint.ConstraintLayout; -import android.util.Log; import android.view.View; import android.webkit.WebView; import android.widget.EditText; import android.widget.ProgressBar; -import android.widget.Toast; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; 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];; + private WebView[] view = new WebView[2]; + private ProgressBar progressBar; + private EditText searchbar; + private ConstraintLayout requestFailure; + + public boolean isReloadedUrl = false; private int viewIndex = 1; private int currentViewIndex = 0; private String html = ""; private String baseURL = ""; - private Boolean isLoading = false; - private ProgressBar progressBar; - private EditText searchbar; private Thread clientThread = null; - private ConstraintLayout requestFailure; HttpGet request = null; + private Handler updateUIHandler = 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; + private final static int MESSAGE_UPDATE_TEXT_CHILD_THREAD =1; + private final static int INTERNET_ERROR =2; public static webRequestHandler getInstance() { return ourInstance; @@ -70,98 +65,88 @@ public class webRequestHandler implements StrongBuilder.Callback createUpdateUiHandler(); } - public boolean isReloadedUrl = false; public void loadURL(final String url) { - Log.d("ME HERE 1 : ","SUPER WOW"); + try { - if(!datamodel.getInstance().getIsLoadingURL()) - { - datamodel.getInstance().setIsLoadingURL(true); - } - else - { - request.abort(); - isReloadedUrl = true; - clientThread.stop(); - searchbar.setText(url.replace("http://boogle.store","http://genesis.onion")); - } - progressBar.animate().alpha(0f); - progressBar.setVisibility(View.VISIBLE); - progressBar.animate().setDuration(300).alpha(1f); - + preInitialization(url); } - catch (Exception ex) + catch (Exception e) { - Log.d("ERROR : ","SUPER WOW"); + e.printStackTrace(); } - clientThread = new Thread(new Runnable() { - @Override - public void run() { - try + clientThread = new Thread(() -> { + try + { + if(url.contains("boogle.store")) { - 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(); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - StringBuilder str = new StringBuilder(); - String line = null; - - while((line = reader.readLine()) != null) - { - 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); - } + nonProxyConnection(url); } - catch (Exception e) + else { - if(!isReloadedUrl) - { - Message message = new Message(); - message.what = INTERNET_ERROR; - updateUIHandler.sendMessage(message); - Log.d("ERROR : ","SUPER WOW"); - e.printStackTrace(); - } - isReloadedUrl = false; + proxyConnection(url); } } + catch (Exception e) + { + onError(); + e.printStackTrace(); + } }); clientThread.start(); } + public void preInitialization(String url) + { + if(!datamodel.getInstance().getIsLoadingURL()) + { + datamodel.getInstance().setIsLoadingURL(true); + } + else + { + request.abort(); + isReloadedUrl = true; + if(clientThread!=null) + clientThread.stop(); + clientThread = null; + searchbar.setText(url.replace("http://boogle.store","http://genesis.onion")); + } + progressBar.animate().alpha(0f); + progressBar.setVisibility(View.VISIBLE); + progressBar.animate().setDuration(300).alpha(1f); + + } + + public void nonProxyConnection(String url) throws IOException { + HttpClient client = new DefaultHttpClient(); + request = new HttpGet(url); + baseURL = url; + HttpResponse response = client.execute(request); + InputStream in = response.getEntity().getContent(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder str = new StringBuilder(); + String line = null; + + while((line = reader.readLine()) != null) + { + str.append(line); + } + in.close(); + + html = str.toString(); + Message message = new Message(); + message.what = MESSAGE_UPDATE_TEXT_CHILD_THREAD; + updateUIHandler.sendMessage(message); + } + 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(); @@ -176,15 +161,18 @@ public class webRequestHandler implements StrongBuilder.Callback updateUIHandler.sendMessage(message); } - private Handler updateUIHandler = null; - private final static int MESSAGE_UPDATE_TEXT_CHILD_THREAD =1; - private final static int INTERNET_ERROR =2; - - public WebView getView() + public void onError() { - return view[currentViewIndex]; + if(!isReloadedUrl) + { + Message message = new Message(); + message.what = INTERNET_ERROR; + updateUIHandler.sendMessage(message); + } + isReloadedUrl = false; } + @SuppressLint("HandlerLeak") private void createUpdateUiHandler() { @@ -194,7 +182,6 @@ public class webRequestHandler implements StrongBuilder.Callback { @Override public void handleMessage(Message msg) { - Log.i("APPLYING : ","SUCCESS : APPLYING"); if(msg.what == MESSAGE_UPDATE_TEXT_CHILD_THREAD) { view[viewIndex].animate().setDuration(0).alpha(0f); @@ -211,11 +198,7 @@ public class webRequestHandler implements StrongBuilder.Callback viewIndex = 1; currentViewIndex=0; } - view[currentViewIndex].animate().setDuration(0).alpha(0f).withEndAction((new Runnable() { - @Override - public void run() - { - } + view[currentViewIndex].animate().setDuration(0).alpha(0f).withEndAction((() -> { })); } else if (msg.what == INTERNET_ERROR) @@ -223,12 +206,8 @@ public class webRequestHandler implements StrongBuilder.Callback datamodel.getInstance().setIsLoadingURL(false); progressBar.animate().alpha(0f); requestFailure.setVisibility(View.VISIBLE); - requestFailure.animate().alpha(1f).setDuration(300).withEndAction((new Runnable() { - @Override - public void run() - { - } - }));; + requestFailure.animate().alpha(1f).setDuration(300).withEndAction((() -> { + })); } } }; @@ -253,4 +232,37 @@ public class webRequestHandler implements StrongBuilder.Callback public void onInvalid() { } + + public void getVersion(Context applicationContext) + { + new Thread() + { + public void run() + { + try + { + String webPage = "http://boogle.store/version"; + URL url = new URL(webPage); + URLConnection urlConnection = null; + urlConnection = url.openConnection(); + InputStream is = urlConnection.getInputStream(); + InputStreamReader isr = new InputStreamReader(is); + + int numCharsRead; + char[] charArray = new char[1024]; + StringBuffer sb = new StringBuffer(); + while ((numCharsRead = isr.read(charArray)) > 0) { + sb.append(charArray, 0, numCharsRead); + } + String result = sb.toString(); + preference_manager.getInstance().saveString("version",result,applicationContext); + + } + catch (IOException e) { + e.printStackTrace(); + } + } + + }.start(); + } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 1b4363dc..00000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - -