bug fixes

master
msmannan00 2019-03-27 23:07:03 +05:00
parent f4cd611057
commit 91aab56a7b
36 changed files with 811 additions and 4870 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -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'

View File

@ -17,7 +17,7 @@
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
<activity android:name=".applicationController"
<activity android:name=".application_controller"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

View File

@ -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<String>();
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))
{
}
}
}
};
}

View File

@ -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<String>();
/*-------------------------------------------------------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;
}
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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.
* <p>
* {@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.
* <p>
* {@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()}.
* <p>
* 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);
}
}

View File

@ -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)
* {
* <p>
* String commandLinePath = "/data/local/tmp/orweb.conf";
* try
* {
* Class webViewCoreClass = Class.forName("org.chromium.content.common.CommandLine");
* <p>
* if (webViewCoreClass != null)
* {
* for (Method method : webViewCoreClass.getDeclaredMethods())
* {
* Log.d("Orweb","Proxy methods: " + method.getName());
* }
* <p>
* Method m = webViewCoreClass.getDeclaredMethod("initFromFile",
* String.class);
* <p>
* 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());
* }
* <p>
* return false;
* }
* <p>
* /**
* private static boolean setKitKatProxy (Context ctx, String host, int port)
* {
* <p>
* try
* {
* Class webViewCoreClass = Class.forName("android.net.Proxy");
* <p>
* Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
* if (webViewCoreClass != null && proxyPropertiesClass != null)
* {
* for (Method method : webViewCoreClass.getDeclaredMethods())
* {
* Log.d("Orweb","Proxy methods: " + method.getName());
* }
* <p>
* Method m = webViewCoreClass.getDeclaredMethod("setHttpProxySystemProperty",
* proxyPropertiesClass);
* Constructor c = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE,
* String.class);
* <p>
* if (m != null && c != null)
* {
* m.setAccessible(true);
* c.setAccessible(true);
* Object properties = c.newInstance(host, port, null);
* <p>
* 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());
* }
* <p>
* return false;
* }
* <p>
* private static boolean resetProxyForKitKat ()
* {
* <p>
* try
* {
* Class webViewCoreClass = Class.forName("android.net.Proxy");
* <p>
* Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
* if (webViewCoreClass != null && proxyPropertiesClass != null)
* {
* for (Method method : webViewCoreClass.getDeclaredMethods())
* {
* Log.d("Orweb","Proxy methods: " + method.getName());
* }
* <p>
* Method m = webViewCoreClass.getDeclaredMethod("setHttpProxySystemProperty",
* proxyPropertiesClass);
* <p>
* if (m != null)
* {
* m.setAccessible(true);
* <p>
* 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());
* }
* <p>
* 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();
}
}

View File

@ -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<T extends StrongBuilder, C> {
/**
* Callback to get a connection handed to you for use,
* already set up for NetCipher.
*
* @param <C> the type of connection created by this builder
*/
interface Callback<C> {
/**
* 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<C> callback);
}

View File

@ -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<StrongConnectionBuilder, HttpURLConnection> {
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();
}
}

View File

@ -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"};
}

View File

@ -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 <a href="https://timtaubert.de/blog/2014/11/the-sad-state-of-server-side-tls-session-resumption-implementations/">The sad state of server-side TLS Session Resumption implementations</a>
*/
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<String> protocols = new ArrayList<String>(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<String> enabled = new ArrayList<String>(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<String> protocols = new ArrayList<String>(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<String> enabledCiphers = new ArrayList<String>(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<String> systemProtocols;
if (this.compatible) {
systemProtocols = Arrays.asList(delegate.getEnabledProtocols());
} else {
systemProtocols = Arrays.asList(delegate.getSupportedProtocols());
}
List<String> enabledProtocols = new ArrayList<String>(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);
}
}
}

View File

@ -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.
* <p>
* 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()}.
* <p>
* 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}
* <p>
* 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<ResolveInfo> 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<StatusCallback> statusCallbacks =
newSetFromMap(new WeakHashMap<StatusCallback, Boolean>());
private Set<InstallCallback> installCallbacks =
newSetFromMap(new WeakHashMap<InstallCallback, Boolean>());
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<String> hashes = new ArrayList<String>();
// 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.
* <p>
* 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.
* <p>
* 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 <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
if (map.isEmpty()) {
return new SetFromMap<E>(map);
}
throw new IllegalArgumentException("map not empty");
}
}

View File

@ -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";
}

View File

@ -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<Proxy> listProxies;
public ProxySelector() {
super();
listProxies = new ArrayList<Proxy>();
}
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<Proxy> select(URI uri) {
return listProxies;
}
}

View File

@ -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<ResolveInfo> 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;
}
}

View File

@ -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<E> extends AbstractSet<E>
implements Serializable {
private static final long serialVersionUID = 2454657854757543876L;
// Must be named as is, to pass serialization compatibility test.
private final Map<E, Boolean> m;
private transient Set<E> backingSet;
SetFromMap(final Map<E, Boolean> 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> T[] toArray(T[] contents) {
return backingSet.toArray(contents);
}
@Override
public Iterator<E> 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();
}
}

View File

@ -1,468 +0,0 @@
/***
* Copyright (c) 2014 CommonsWare, LLC
* <p>
* 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.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes = new ArrayList<String>();
sigHashes.add(sigHash);
return (validateBroadcastIntent(context, toValidate, sigHashes,
failIfHack));
}
/**
* Confirms that the broadcast receiver for a given Intent
* has a desired signature hash.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes,
boolean failIfHack) {
PackageManager pm = context.getPackageManager();
Intent result = null;
List<ResolveInfo> 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.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes = new ArrayList<String>();
sigHashes.add(sigHash);
return (validateActivityIntent(context, toValidate, sigHashes,
failIfHack));
}
/**
* Confirms that the activity for a given Intent has the
* desired signature hash.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes,
boolean failIfHack) {
PackageManager pm = context.getPackageManager();
Intent result = null;
List<ResolveInfo> 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.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes = new ArrayList<String>();
sigHashes.add(sigHash);
return (validateServiceIntent(context, toValidate, sigHashes,
failIfHack));
}
/**
* Confirms that the service for a given Intent has the
* desired signature hash.
* <p>
* 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.
* <p>
* In general, there are three possible outcomes of calling
* this method:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String> sigHashes,
boolean failIfHack) {
PackageManager pm = context.getPackageManager();
Intent result = null;
List<ResolveInfo> 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);
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package com.example.myapplication;
public class status
{
public static boolean hasApplicationLoaded = false;
public static String currentURL = "http://boogle.store/";
}

View File

@ -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<HttpClient>
{
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<HttpClient>
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<HttpClient>
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<HttpClient>
{
@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<HttpClient>
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<HttpClient>
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<HttpClient>
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();
}
}

View File

@ -1,151 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="@+id/pageLoader1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="8dp" tools:layout_editor_absoluteX="8dp">
</WebView>
<android.support.constraint.ConstraintLayout
android:id="@+id/requestFailure"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
>
<ImageButton
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f8f8f8"
android:id="@+id/errorBack" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:layout_width="match_parent"
android:textAlignment="viewStart"
android:textStyle="bold"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:text=" Opps! Some Thing Went Wrong"
android:textColor="#4d4d4d"
android:ems="10"
android:id="@+id/editText"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="104dp"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:text="Reload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/reloadButton"
android:background="@drawable/shape"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="parent"
android:radius="1dp"
android:bottomRightRadius="10dp"
android:bottomLeftRadius="10dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:layout_marginBottom="36dp" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.498" app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:text="These might be the problems you are facing\n\n\u2022 Webpage or Website might be down\n\u2022 Your Internet connection might be poor\n\u2022 You might be using a proxy\n\u2022 Website might be blocked by firewall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:textColor="#4d4d4d"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="170dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
android:layout_width="53dp"
android:layout_height="53dp" app:srcCompat="@mipmap/ic_launcher_round_v1"
android:id="@+id/imageView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="4dp"
android:layout_marginStart="4dp"/>
<TextView
android:text="Genesis Search Engine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="#4d4d4d"
android:id="@+id/textView2"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="68dp"/>
<ImageView
android:layout_width="205dp"
android:layout_height="0dp" app:srcCompat="@drawable/interneticon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintBottom_toTopOf="@+id/reloadButton" android:layout_marginBottom="35dp"
android:layout_marginTop="35dp"/>
</android.support.constraint.ConstraintLayout>
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:id="@+id/progressBar"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:max="100"
android:progress="0" app:layout_constraintTop_toTopOf="parent"
/>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/splashScreen"
android:background="@drawable/backgradient"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintVertical_bias="1.0">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="95dp"
android:layout_height="95dp"
android:indeterminateTint="#ffffff"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="80dp"/>
<ImageView
android:layout_width="100dp"
android:layout_height="70dp" app:srcCompat="@drawable/logolarge"
android:id="@+id/imageView_loading" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="80dp"/>
<TextView
android:text="Genesis Search Engine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textStyle="bold"
android:id="@+id/textView3"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="35dp"
android:layout_marginEnd="231dp" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"/>
<TextView
android:text="Loading Please Wait"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textStyle="bold"
android:id="@+id/notification" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="50dp" android:layout_marginStart="76dp" android:layout_marginEnd="76dp"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -5,7 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".applicationController">
tools:context=".application_controller">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -63,6 +63,7 @@
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:text="Reload"
android:onClick="onReloadButtonPressed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/reloadButton"
@ -119,6 +120,7 @@
android:topLeftRadius="3dp"
android:scaleType="fitCenter"
android:src="@drawable/homeicon"
android:onClick="onHomeButtonPressed"
android:background="@drawable/pressedcolor"
android:topRightRadius="3dp"/>
<EditText

View File

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/splashScreen"
android:background="@drawable/backgradient"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintVertical_bias="1.0">
<ImageView
android:layout_width="100dp"
android:layout_height="70dp" app:srcCompat="@drawable/logolarge"
android:id="@+id/imageView_loading" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="80dp"/>
<TextView
android:text="Genesis Search Engine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textStyle="bold"
android:id="@+id/textView3"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="35dp"
android:layout_marginEnd="231dp" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"/>
<TextView
android:text="Loading Please Wait"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textStyle="bold"
android:id="@+id/notification" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="50dp" android:layout_marginStart="76dp" android:layout_marginEnd="76dp"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,7 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.20'
repositories {
google()
jcenter()
@ -9,7 +8,6 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

BIN
keystore1.jks Normal file

Binary file not shown.