big checkin for 0.0.8-beta-280710a build with new start wizard, improved ctrlport handling, and root config

svn:r22697
This commit is contained in:
Nathan Freitas 2010-07-28 04:43:58 +00:00
parent 2832e744b2
commit d94157e6f6
28 changed files with 1096 additions and 147 deletions

View File

@ -25,6 +25,7 @@
<activity android:name=".SettingsPreferences" android:label="@string/app_name"/>
<activity android:name=".AppManager" android:label="@string/app_name"/>
<activity android:name=".WizardActivity" android:label="@string/app_name"/>
<service android:name=".service.TorService" android:process=":remote" android:debuggable="false">
<intent-filter>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
res/drawable/bak/toroff.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
res/drawable/bak/toron.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
res/drawable/bak/torstarting.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
res/drawable/bak/torstopping.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
res/drawable/bgtitanium.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

BIN
res/drawable/ic_menu_exit.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -11,13 +11,28 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:text="@string/wizard_details"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="15px"
android:paddingLeft="15px"
android:textStyle="bold"
android:textColor="#00ff00" />
<TextView android:text="@string/wizard_details_msg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:textColorLink="#ffffff"
android:paddingLeft="15px"
android:textColor="#ffffff" />
<TextView android:text="Version: "
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="15px"
android:paddingLeft="15px"
android:textStyle="bold"
android:textColor="#ffffff" />
android:textColor="#00ff00" />
<TextView android:text="- Unknown -"
android:id="@+id/versionName"
android:layout_width="fill_parent"
@ -25,13 +40,13 @@
android:paddingLeft="15px"
android:layout_gravity="center_vertical"
android:textColor="#ffffff" />
<TextView android:text="Project-Home: "
<TextView android:text="Project Home(s): "
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="15px"
android:paddingLeft="15px"
android:textStyle="bold"
android:textColor="#ffffff" />
android:textColor="#00ff00" />
<TextView android:text="https://www.torproject.org/docs/android\nhttps://guardianproject.info/apps/orbot/"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -45,7 +60,7 @@
android:paddingTop="15px"
android:paddingLeft="15px"
android:textStyle="bold"
android:textColor="#ffffff" />
android:textColor="#00ff00" />
<TextView android:text="The Tor License"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -64,7 +79,7 @@
android:paddingTop="15px"
android:paddingLeft="15px"
android:textStyle="bold"
android:textColor="#ffffff" />
android:textColor="#00ff00" />
<TextView android:text="Tor v0.2.2.13: https://www.torproject.org"
android:layout_width="fill_parent"
android:layout_height="wrap_content"

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:id="@+id/helpscrollview"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:text=""
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:id="@+id/helpscrollview"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3px">
<TextView android:text="@string/wizard_configure_msg" android:textColor="#ffffff" android:id="@+id/WizardRootTextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<CheckBox android:layout_marginTop="20px" android:text="@string/wizard_configure_all" android:id="@+id/WizardRootCheckBox01" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
<TextView android:text=" or " android:textColor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<Button android:text="@string/wizard_configure_select_apps" android:id="@+id/WizardRootButton01" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:id="@+id/helpscrollview"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3px">
<TextView android:text="@string/wizard_permissions_msg_stock" android:textColor="#ffffff" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<Button android:text="@string/wizard_permission_enable_root" android:layout_marginTop="10px" android:id="@+id/WizardRootButtonEnable" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:text="@string/wizard_permissions_no_root" android:layout_marginTop="10px" android:textColor="#ffffff" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<CheckBox android:text="@string/wizard_permissions_consent" android:id="@+id/CheckBoxConsent" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:id="@+id/helpscrollview"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3px">
<TextView android:text="@string/wizard_tips_msg" android:textColor="#ffffff" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<Button android:text="@string/wizard_tips_otrchat" android:layout_marginTop="10px" android:id="@+id/WizardRootButtonInstallOtrchat" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button android:text="@string/wizard_tips_orweb" android:layout_marginTop="10px" android:id="@+id/WizardRootButtonInstallOrweb" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:id="@+id/helpscrollview"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3px">
<TextView android:text="@string/wizard_welcome_msg" android:textColor="#ffffff" android:id="@+id/WizardRootTextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -58,10 +58,52 @@ and all DNS requests. This includes the built-in Browser, Gmail, YouTube and Map
<string name="pref_trans_proxy_summary">Automatic Torifying of Apps</string>
<string name="pref_transparent_all_title">Tor Everything</string>
<string name="pref_transparent_all_summary">Send traffic for all apps through Tor</string>
<string name="pref_transparent_all_summary">Proxy traffic for all apps through Tor</string>
<string name="status_install_success">Tor binaries successfully installed!</string>
<string name="status_install_fail">The Tor binary files were unable to be installed. Please check the log and notify tor-assistants@torproject.org</string>
<string name="title_error">Application Error</string>
<string name="wizard_title">Welcome to Orbot</string>
<string name="wizard_btn_tell_me_more">About Orbot</string>
<string name="btn_next">Next</string>
<string name="btn_back">Back</string>
<string name="btn_finish">Finish</string>
<!-- Welcome Wizard strings (DJH) -->
<string name="wizard_welcome_msg">Orbot brings Tor to Android. Tor is free software and an open network that helps you defend against a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security known as traffic analysis.\n\n*WARNING:* Simply installing Orbot will _not_ magically anonymize your mobile traffic! This wizard will help you get started.</string>
<string name="wizard_details">Some Orbot Details</string>
<string name="wizard_details_msg">Orbot is an open-source application that contains Tor, LibEvent and Privoxy. It provides a local HTTP proxy (8118) and a SOCKS proxy (9050) into the Tor network. Orbot also has the ability, on rooted device, to send all internet traffic through Tor.</string>
<string name="wizard_permissions_root">Grant Permissions</string>
<string name="wizard_permissions_stock">Permissions Warning</string>
<string name="wizard_premissions_msg_root">Excellent! We\'ve detected that you have root permissions enabled for Orbot. We will use this power wisely.</string>
<string name="wizard_permissions_msg_stock">We\'ve detected that you do not have root permissions enabled. Your application data usage will NOT be transparently routed through Tor without root access. </string>
<string name="wizard_permissions_no_root">If you choose to continue WITHOUT root, you must use apps that know how to talk to Tor.</string>
<string name="wizard_permissions_consent">I understand and would like to continue without root</string>
<string name="wizard_permission_enable_root">Attempt to enable root access</string>
<string name="wizard_configure">Configure Torification</string>
<string name="wizard_configure_msg">Orbot gives you the option to route all application traffic through Tor OR to choose your applications individually.</string>
<string name="wizard_configure_all">Proxy All Apps Through Tor</string>
<string name="wizard_configure_select_apps">Select Individual Apps for Tor</string>
<string name="wizard_tips_tricks">Orbot-enabled Apps</string>
<string name="wizard_tips_msg">We encourage you to download &amp; use apps that know how to connect directly to Orbot. Click on the buttons below to install.</string>
<string name="wizard_tips_otrchat">OtrChat - From the Orbot dev team, a secure Instant Messaging client for Android.</string>
<string name="wizard_tips_orweb">OrWeb (Android 1.x Only) - From the Orbot dev team, a web browser designed to work with Tor.</string>
<string name="wizard_final">Orbot is ready!</string>
<string name="wizard_final_msg">Hundreds of thousands of people around the world use Tor for a wide variety of reasons: journalists and bloggers, human rights workers, law enforcement officers, soldiers, corporations, citizens of repressive regimes, and just ordinary citizens... and now you are ready to, as well!</string>
<string name="otrchat_apk_url">https://github.com/downloads/guardianproject/OtRChat/OtRChat-0.0.1-alpha-build6a.apk</string>
<string name="orweb_apk_url">http://github.com/downloads/guardianproject/Orweb/Orweb-0.0.1c.apk.apk</string>
<!-- END Welcome Wizard strings (DJH) -->
</resources>

View File

@ -0,0 +1,263 @@
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
/* See LICENSE for licensing information */
package org.torproject.android;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class AppManager extends Activity implements OnCheckedChangeListener, OnClickListener, TorConstants {
private static TorifiedApp[] apps = null;
private ListView listApps;
private AppManager mAppManager;
private boolean appsLoaded = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.layout_apps);
mAppManager = this;
}
@Override
protected void onResume() {
super.onResume();
listApps = (ListView)findViewById(R.id.applistview);
if (!appsLoaded)
loadApps();
}
private void loadApps ()
{
final TorifiedApp[] apps = getApps(this);
Arrays.sort(apps, new Comparator<TorifiedApp>() {
public int compare(TorifiedApp o1, TorifiedApp o2) {
if (o1.isTorified() == o2.isTorified()) return o1.getName().compareTo(o2.getName());
if (o1.isTorified()) return -1;
return 1;
}
});
final LayoutInflater inflater = getLayoutInflater();
final ListAdapter adapter = new ArrayAdapter<TorifiedApp>(this,R.layout.layout_apps_item,R.id.itemtext,apps) {
public View getView(int position, View convertView, ViewGroup parent) {
ListEntry entry;
if (convertView == null) {
// Inflate a new view
convertView = inflater.inflate(R.layout.layout_apps_item, parent, false);
entry = new ListEntry();
entry.icon = (ImageView) convertView.findViewById(R.id.itemicon);
entry.box = (CheckBox) convertView.findViewById(R.id.itemcheck);
entry.text = (TextView) convertView.findViewById(R.id.itemtext);
entry.text.setOnClickListener(mAppManager);
entry.text.setOnClickListener(mAppManager);
convertView.setTag(entry);
entry.box.setOnCheckedChangeListener(mAppManager);
} else {
// Convert an existing view
entry = (ListEntry) convertView.getTag();
}
final TorifiedApp app = apps[position];
entry.icon.setImageDrawable(app.getIcon());
entry.text.setText(app.getName());
final CheckBox box = entry.box;
box.setTag(app);
box.setChecked(app.isTorified());
entry.text.setTag(box);
entry.icon.setTag(box);
return convertView;
}
};
listApps.setAdapter(adapter);
appsLoaded = true;
}
private static class ListEntry {
private CheckBox box;
private TextView text;
private ImageView icon;
}
/* (non-Javadoc)
* @see android.app.Activity#onStop()
*/
@Override
protected void onStop() {
super.onStop();
//Log.i(getClass().getName(),"Exiting Preferences");
}
public static TorifiedApp[] getApps (Context context)
{
if (apps != null)
return apps;
final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0);
String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, "");
String[] tordApps;
StringTokenizer st = new StringTokenizer(tordAppString,"|");
tordApps = new String[st.countTokens()];
int tordIdx = 0;
while (st.hasMoreTokens())
{
tordApps[tordIdx++] = st.nextToken();
}
Arrays.sort(tordApps);
//else load the apps up
PackageManager pMgr = context.getPackageManager();
List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
apps = new TorifiedApp[lAppInfo.size()];
ApplicationInfo aInfo = null;
int appIdx = 0;
while (itAppInfo.hasNext())
{
aInfo = itAppInfo.next();
apps[appIdx] = new TorifiedApp();
apps[appIdx].setEnabled(aInfo.enabled);
apps[appIdx].setUid(aInfo.uid);
apps[appIdx].setUsername(pMgr.getNameForUid(apps[appIdx].getUid()));
apps[appIdx].setProcname(aInfo.processName);
apps[appIdx].setName(pMgr.getApplicationLabel(aInfo).toString());
apps[appIdx].setIcon(pMgr.getApplicationIcon(aInfo));
// check if this application is allowed
if (Arrays.binarySearch(tordApps, apps[appIdx].getUsername()) >= 0) {
apps[appIdx].setTorified(true);
}
else
{
apps[appIdx].setTorified(false);
}
appIdx++;
}
return apps;
}
public static void saveAppSettings (Context context)
{
if (apps == null)
return;
final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0);
StringBuilder tordApps = new StringBuilder();
for (int i = 0; i < apps.length; i++)
{
if (apps[i].isTorified())
{
tordApps.append(apps[i].getUsername());
tordApps.append("|");
}
}
Editor edit = prefs.edit();
edit.putString(PREFS_KEY_TORIFIED, tordApps.toString());
edit.commit();
}
/**
* Called an application is check/unchecked
*/
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final TorifiedApp app = (TorifiedApp) buttonView.getTag();
if (app != null) {
app.setTorified(isChecked);
}
saveAppSettings(this);
}
@Override
public void onClick(View v) {
CheckBox cbox = (CheckBox)v.getTag();
final TorifiedApp app = (TorifiedApp)cbox.getTag();
if (app != null) {
app.setTorified(!app.isTorified());
cbox.setChecked(app.isTorified());
}
saveAppSettings(this);
}
}

View File

@ -0,0 +1,25 @@
package org.torproject.android;
//list view with add/remove hidden services - user is prompted for port
public class HiddenServiceManager {
}
/*
*
* ## Once you have configured a hidden service, you can look at the
## contents of the file ".../hidden_service/hostname" for the address
## to tell people.
##
## HiddenServicePort x y:z says to redirect requests on port x to the
## address y:z.
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/hidden_service/
#HiddenServicePort 80 127.0.0.1:80
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/other_hidden_service/
#HiddenServicePort 80 127.0.0.1:80
#HiddenServicePort 22 127.0.0.1:22
*/

View File

@ -0,0 +1,18 @@
package org.torproject.android;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class OnBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("org.torproject.android.service.TorService");
context.startService(serviceIntent);
}
}

View File

@ -19,6 +19,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@ -35,7 +36,10 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.TextView;
@ -58,10 +62,14 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
/* The primary interface we will be calling on the service. */
ITorService mService = null;
Orbot mOrbot = null;
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOrbot = this;
setTheme(android.R.style.Theme_Black_NoTitleBar);
//setTitle(getString(R.string.app_name) + ' ' + getString(R.string.app_version));
showMain();
@ -244,10 +252,8 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
if (mService != null)
{
try {
@ -258,6 +264,23 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
}
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mOrbot);
boolean showWizard = prefs.getBoolean("show_wizard",true);
if (showWizard)
{
Editor pEdit = prefs.edit();
pEdit.putBoolean("show_wizard",false);
pEdit.commit();
showHelp();
}
}
/* (non-Javadoc)
@ -272,7 +295,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
//updateStatus ("");
hasRoot = TorTransProxy.hasRootAccess();
}
@ -297,7 +320,6 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
{
bindService(); //connect the UI activity to the remote service
currentView = R.layout.layout_main;
setContentView(currentView);
@ -358,64 +380,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
private void showHelp ()
{
LayoutInflater li = LayoutInflater.from(this);
View view = li.inflate(R.layout.layout_help, null);
StringBuilder msg = new StringBuilder();
msg.append(getString(R.string.help_text_1));
msg.append("\n\n");
if (hasRoot)
{
msg.append("Your device is ROOTED. Please enable the 'Transparent Proxying' setting to select which apps to send through Tor.");
}
else
{
msg.append("Your device is NOT rooted.\n");
msg.append(getString(R.string.help_text_5));
msg.append("\n\n");
msg.append(getString(R.string.not_anonymous_yet));
}
/*
msg.append(getString(R.string.help_text_2));
msg.append("\n\n");
msg.append(getString(R.string.help_text_3));
msg.append("\n\n");
msg.append(getString(R.string.help_text_4));
msg.append("\n\n");
msg.append(getString(R.string.help_text_5));
msg.append("\n\n");
*/
new AlertDialog.Builder(this)
.setTitle(getString(R.string.menu_info))
.setMessage(msg.toString())
.setNeutralButton(getString(R.string.button_about), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
showAbout();
}
})
.setNegativeButton(getString(R.string.button_close), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Log.d(TAG, "Close pressed");
}
})
.show();
}
private void showHelpWizard ()
{
//sshowAlert("Configure",getString(R.string.not_anonymous_yet));
new WizardHelper(this).showWizard();
}
@ -447,6 +412,8 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
}
/*
* Read in the Preferences and write then to the .torrc file
*/
@ -611,18 +578,9 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
return;
}
mService.updateConfiguration("UseBridges", "1", false);
if (autoUpdateBridges)
{
mService.updateConfiguration("UpdateBridgesFromAuthority", "1", false);
}
else
{
mService.updateConfiguration("UpdateBridgesFromAuthority", "0", false);
}
String bridgeDelim = "\n";
if (bridgeList.indexOf(",") != -1)
@ -637,6 +595,9 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
mService.updateConfiguration("bridge", st.nextToken(), false);
}
mService.updateConfiguration("UpdateBridgesFromAuthority", "0", false);
}
else
{
@ -721,7 +682,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
lblStatus.setText(getString(R.string.status_activated));
showHelpWizard ();
/*
@ -998,7 +959,6 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
};
boolean mIsBound = false;
boolean hasRoot = false;
private void bindService ()
{

View File

@ -4,6 +4,7 @@
package org.torproject.android;
import org.torproject.android.service.TorServiceUtils;
import org.torproject.android.service.TorTransProxy;
import android.content.Intent;
import android.os.Bundle;
@ -28,7 +29,7 @@ public class SettingsPreferences
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
hasRoot = TorServiceUtils.hasRoot();
hasRoot = TorTransProxy.hasRootAccess();
}

View File

@ -46,6 +46,8 @@ public interface TorConstants {
public final static String PREF_REACHABLE_ADDRESSES = "pref_reachable_addresses";
public final static String PREF_REACHABLE_ADDRESSES_PORTS = "pref_reachable_addresses_ports";
public final static String PREF_TRANSPARENT = "pref_transparent";
public final static String PREF_TRANSPARENT_ALL = "pref_transparent_all";
}

View File

@ -0,0 +1,71 @@
package org.torproject.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
public class WizardActivity extends Activity implements OnClickListener
{
protected void onCreate(Bundle savedInstanceState)
{
this.setContentView(R.layout.layout_help);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
showStep1();
}
public void showStep1()
{
showDialog("Test","this is nathan's test","foo","bar",this);
}
private void showDialog (String title, String msg, String button1, String button2, OnClickListener ocListener)
{
new AlertDialog.Builder(this)
.setInverseBackgroundForced(true)
.setTitle(title)
.setMessage(msg)
.setNeutralButton(button1, ocListener)
.setNegativeButton(button2, ocListener)
.show();
}
@Override
public void onClick(DialogInterface arg0, int arg1) {
}
}

View File

@ -0,0 +1,371 @@
package org.torproject.android;
import org.torproject.android.service.TorTransProxy;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Toast;
public class WizardHelper implements TorConstants {
private Context context;
private Dialog currentDialog;
public WizardHelper (Context context)
{
this.context = context;
}
public void showWizard ()
{
showWizardStep1();
}
public void showWizardStep1()
{
String title = context.getString(R.string.wizard_title);
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.layout_wizard_welcome, null);
showCustomDialog(title, view,context.getString(R.string.btn_next),context.getString(R.string.wizard_btn_tell_me_more),new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == DialogInterface.BUTTON_NEUTRAL)
{
showWizardStep2();
}
else if (which == DialogInterface.BUTTON_POSITIVE)
{
showAbout();
}
}
});
}
public void showWizardStep2()
{
String title = null;
String msg = null;
title = context.getString(R.string.wizard_permissions_root);
msg = context.getString(R.string.wizard_premissions_msg_root);
title = context.getString(R.string.wizard_permissions_stock);
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.layout_wizard_stock, null);
Button btn1 = (Button)view.findViewById(R.id.WizardRootButtonEnable);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
boolean hasRoot = TorTransProxy.hasRootAccess();
if (hasRoot)
{
currentDialog.dismiss();
showWizardStep2Root();
}
else
{
Toast.makeText(context, "Unable to get root access", Toast.LENGTH_LONG).show();
}
}
});
showCustomDialog(title, view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == DialogInterface.BUTTON_NEUTRAL)
{
showWizardTipsAndTricks();
}
else if (which == DialogInterface.BUTTON_POSITIVE)
{
showWizardStep1();
}
}
});
}
public void showWizardStep2Root()
{
String title = null;
String msg = null;
title = context.getString(R.string.wizard_permissions_root);
msg = context.getString(R.string.wizard_premissions_msg_root);
showDialog(title, msg,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == DialogInterface.BUTTON_NEUTRAL)
{
showWizardRootConfigureTorification();
}
else if (which == DialogInterface.BUTTON_POSITIVE)
{
showWizardStep1();
}
}
});
}
public void showWizardTipsAndTricks()
{
String title = context.getString(R.string.wizard_tips_tricks);
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.layout_wizard_tips, null);
Button btn1 = (Button)view.findViewById(R.id.WizardRootButtonInstallOtrchat);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String url = context.getString(R.string.otrchat_apk_url);
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
});
Button btn2 = (Button)view.findViewById(R.id.WizardRootButtonInstallOrweb);
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String url = context.getString(R.string.orweb_apk_url);
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
});
showCustomDialog(title, view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == DialogInterface.BUTTON_NEUTRAL)
{
showWizardFinal();
}
else if (which == DialogInterface.BUTTON_POSITIVE)
{
showWizardStep2();
}
}
});
}
public void showWizardRootConfigureTorification()
{
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.layout_wizard_root, null);
CheckBox cb1 = (CheckBox)view.findViewById(R.id.WizardRootCheckBox01);
Button btn1 = (Button)view.findViewById(R.id.WizardRootButton01);
cb1.setOnCheckedChangeListener(new OnCheckedChangeListener (){
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Editor pEdit = prefs.edit();
pEdit.putBoolean(PREF_TRANSPARENT, isChecked);
pEdit.putBoolean(PREF_TRANSPARENT_ALL, isChecked);
pEdit.commit();
//Button btn1 = (Button)buttonView.getParent().findViewById(R.id.WizardRootButton01);
//btn1.setEnabled(!isChecked);
}
});
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Editor pEdit = prefs.edit();
pEdit.putBoolean(PREF_TRANSPARENT, true);
pEdit.putBoolean(PREF_TRANSPARENT_ALL, false);
pEdit.commit();
context.startActivity(new Intent(context, AppManager.class));
}
});
showCustomDialog(context.getString(R.string.wizard_configure),view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == DialogInterface.BUTTON_NEUTRAL)
{
showWizardTipsAndTricks();
}
else if (which == DialogInterface.BUTTON_POSITIVE)
{
showWizardStep2();
}
}
});
}
private void showWizardFinal ()
{
String title = null;
String msg = null;
title = context.getString(R.string.wizard_final);
msg = context.getString(R.string.wizard_final_msg);
new AlertDialog.Builder(context)
.setIcon(R.drawable.icon)
.setTitle(title)
.setPositiveButton(R.string.button_close, null)
.setMessage(msg)
.show();
}
private void showDialog (String title, String msg, String button1, String button2, DialogInterface.OnClickListener ocListener)
{
// dialog.setContentView(R.layout.custom_dialog);
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setIcon(R.drawable.icon)
.setTitle(title)
.setMessage(msg)
.setNeutralButton(button1, ocListener)
.setPositiveButton(button2, ocListener);
currentDialog = builder.show();
}
private void showCustomDialog (String title, View view, String button1, String button2, DialogInterface.OnClickListener ocListener)
{
currentDialog = new AlertDialog.Builder(context)
.setIcon(R.drawable.icon)
.setTitle(title)
.setView(view)
.setNeutralButton(button1, ocListener)
.setPositiveButton(button2, ocListener)
.show();
}
private void showAbout ()
{
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.layout_about, null);
TextView versionName = (TextView)view.findViewById(R.id.versionName);
versionName.setText(R.string.app_version);
new AlertDialog.Builder(context)
.setTitle(context.getString(R.string.button_about))
.setView(view)
.setNeutralButton(context.getString(R.string.btn_back), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
showWizard();
}
})
.show();
}
}

View File

@ -49,7 +49,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
private ArrayList<String> configBuffer = null;
private boolean hasRoot = false;
private String appHome = null;
private String torBinaryPath = null;
@ -62,8 +61,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
Log.i(TAG,"TorService: onCreate");
}
@ -223,15 +220,25 @@ public class TorService extends Service implements TorServiceConstants, Runnable
sendCallbackMessage("Web proxy shutdown");
killTorProcess ();
try
{
killTorProcess ();
currentStatus = STATUS_READY;
currentStatus = STATUS_READY;
showToolbarNotification (getString(R.string.status_disabled),R.drawable.tornotificationoff);
sendCallbackMessage(getString(R.string.status_disabled));
showToolbarNotification (getString(R.string.status_disabled),R.drawable.tornotificationoff);
sendCallbackMessage(getString(R.string.status_disabled));
setupTransProxy(false);
setupTransProxy(false);
}
catch (Exception e)
{
Log.i(TAG, "An error occured stopping Tor",e);
logNotice("An error occured stopping Tor: " + e.getMessage());
sendCallbackMessage("Something bad happened. Check the log");
}
}
@ -257,7 +264,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
}
}
private void killTorProcess ()
private void killTorProcess () throws Exception
{
if (conn != null)
@ -318,6 +325,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
String APK_EXT = ".apk";
int MAX_TRIES = 10;
String buildPath = apkBase + TOR_APP_USERNAME + APK_EXT;
Log.i(TAG, "Checking APK location: " + buildPath);
@ -327,7 +335,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (fileApk.exists())
return fileApk.getAbsolutePath();
for (int i = 0; i < 10; i++)
for (int i = 0; i < MAX_TRIES; i++)
{
buildPath = apkBase + TOR_APP_USERNAME + '-' + i + APK_EXT;
fileApk = new File(buildPath);
@ -338,10 +346,33 @@ public class TorService extends Service implements TorServiceConstants, Runnable
return fileApk.getAbsolutePath();
}
String apkBaseExt = "/mnt/asec/" + TOR_APP_USERNAME;
String pkgFile = "/pkg.apk";
buildPath = apkBaseExt + pkgFile;
fileApk = new File(buildPath);
Log.i(TAG, "Checking external storage APK location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
for (int i = 0; i < MAX_TRIES; i++)
{
buildPath = apkBaseExt + '-' + i + pkgFile;
fileApk = new File(buildPath);
Log.i(TAG, "Checking external storage APK location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
}
return null;
}
private boolean checkTorBinaries ()
private boolean checkTorBinaries () throws Exception
{
//android.os.Debug.waitForDebugger();
@ -366,8 +397,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
return false;
}
torBinaryPath = appHome + '/' + TOR_BINARY_ASSET_KEY;
privoxyPath = appHome + '/' + PRIVOXY_ASSET_KEY;
torBinaryPath = appHome + TOR_BINARY_ASSET_KEY;
privoxyPath = appHome + PRIVOXY_ASSET_KEY;
boolean torBinaryExists = new File(torBinaryPath).exists();
boolean privoxyBinaryExists = new File(privoxyPath).exists();
@ -401,15 +432,22 @@ public class TorService extends Service implements TorServiceConstants, Runnable
return false;
}
}
else
{
logNotice("Found Tor binary: " + torBinaryPath);
logNotice("Found prvoxy binary: " + privoxyPath);
}
StringBuilder log = new StringBuilder ();
logNotice("Setting permission on Tor binary");
logNotice("(re)Setting permission on Tor binary");
String[] cmd1 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + torBinaryPath};
TorServiceUtils.doShellCommand(cmd1, log, false, true);
logNotice("Setting permission on Privoxy binary");
logNotice("(re)Setting permission on Privoxy binary");
String[] cmd2 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + privoxyPath};
TorServiceUtils.doShellCommand(cmd2, log, false, true);
@ -525,6 +563,9 @@ public class TorService extends Service implements TorServiceConstants, Runnable
private void runPrivoxyShellCmd () throws Exception
{
Log.i(TAG,"Starting privoxy process");
int privoxyProcId = TorServiceUtils.findProcessId(privoxyPath);
StringBuilder log = null;
@ -538,7 +579,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
String privoxyConfigPath = appHome + PRIVOXYCONFIG_ASSET_KEY;
String[] cmds =
{ privoxyPath + " " + privoxyConfigPath };
{ privoxyPath + " " + privoxyConfigPath + " &" };
logNotice (cmds[0]);
@ -845,13 +886,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (appHome == null)
{
checkTorBinaries();
try
{
checkTorBinaries();
findExistingProc ();
findExistingProc ();
_torInstance = this;
hasRoot = TorServiceUtils.hasRoot();
_torInstance = this;
}
catch (Exception e)
{
Log.i(TAG,"Unable to check for Tor binaries",e);
return null;
}
}
if (ITorService.class.getName().equals(intent.getAction())) {
@ -1037,6 +1084,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
logNotice ("Transparent Proxying: " + enableTransparentProxy);
boolean hasRoot = TorTransProxy.hasRootAccess();
if (enabled)
{
@ -1044,8 +1093,18 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (hasRoot && enableTransparentProxy)
{
TorTransProxy.setDNSProxying();
TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
try
{
TorTransProxy.setDNSProxying();
boolean success = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
logNotice ("TorTransProxy enabled: " + success);
} catch (Exception e) {
logNotice("WARNING: Error configuring transparenty proxying: " + e.getMessage());
Log.w(TAG, "error refreshing iptables: err=" + e.getMessage(), e);
}
}
else

View File

@ -123,26 +123,16 @@ public class TorServiceUtils implements TorServiceConstants {
}
public static boolean hasRoot ()
public static int doShellCommand(String[] cmds, StringBuilder log, boolean runAsRoot, boolean waitFor) throws Exception
{
String[] cmds = {"exit 0"};
int code = doShellCommand(cmds,null,true, true);
return (code == 0);
}
public static int doShellCommand(String[] cmds, StringBuilder log, boolean isRoot, boolean waitFor)
{
Log.i(TAG,"executing shell cmds: " + cmds[0] + "; isRoot=" + isRoot);
Log.i(TAG,"executing shell cmds: " + cmds[0] + "; runAsRoot=" + runAsRoot);
Process proc = null;
int exitCode = -1;
try {
if (isRoot)
if (runAsRoot)
proc = Runtime.getRuntime().exec("su");
else
proc = Runtime.getRuntime().exec("sh");
@ -163,10 +153,7 @@ public class TorServiceUtils implements TorServiceConstants {
if (waitFor)
{
exitCode = proc.waitFor();
log.append("process exit code: ");
log.append(exitCode);
log.append("\n");
final char buf[] = new char[10];
@ -183,12 +170,15 @@ public class TorServiceUtils implements TorServiceConstants {
while ((read=reader.read(buf)) != -1) {
if (log != null) log.append(buf, 0, read);
}
exitCode = proc.waitFor();
log.append("process exit code: ");
log.append(exitCode);
log.append("\n");
Log.i(TAG,"command process exit value: " + exitCode);
}
} catch (Exception e) {
Log.w(TAG, "Error executing shell cmd: " + e.getMessage());
}
return exitCode;

View File

@ -1,13 +1,8 @@
package org.torproject.android.service;
import java.util.Iterator;
import java.util.List;
import org.torproject.android.TorifiedApp;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
public class TorTransProxy {
@ -23,29 +18,35 @@ public class TorTransProxy {
private final static String IPTABLES_ADD = " -A ";
//private final static String IPTABLES_DELETE = " -D "; //not deleting manually anymore - just calling a system wide flush of iptables rules
private final static String IPTABLES_DROP_ALL = " -j DROP ";
private static boolean hasRoot = false;
// private final static String IPTABLES_DROP_ALL = " -j DROP ";
/**
* Check if we have root access
* @return boolean true if we have root
*/
public static boolean hasRootAccess() {
if (hasRoot) return true;
StringBuilder log = new StringBuilder();
try {
// Run an empty script just to check root access
String[] cmd = {"exit 0"};
if (TorServiceUtils.doShellCommand(cmd, null, true, true) == 0) {
hasRoot = true;
String[] cmd = {"whoami"};
int exitCode = TorServiceUtils.doShellCommand(cmd, log, true, true);
if (exitCode == 0) {
return true;
}
} catch (Exception e) {
Log.w(TAG,"Error checking for root access: " + e.getMessage() ,e);
}
Log.w(TAG, "Could not acquire root access.");
Log.w(TAG, "Could not acquire root access: " + log.toString());
return false;
}
public static int setDNSProxying ()
public static int setDNSProxying () throws Exception
{
final StringBuilder log = new StringBuilder();
@ -93,7 +94,8 @@ public class TorTransProxy {
}
}
public static boolean setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) {
public static boolean setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) throws Exception
{
String command = null;
@ -104,9 +106,6 @@ public class TorTransProxy {
StringBuilder res = new StringBuilder();
int code = -1;
try {
for (int i = 0; i < apps.length; i++)
{
if (forceAll || apps[i].isTorified())
@ -147,9 +146,7 @@ public class TorTransProxy {
String msg = res.toString();
Log.e(TAG, msg);
} catch (Exception e) {
Log.w(TAG, "error refreshing iptables: err=" + code + "; resp=" + res.toString(), e);
}
return false;
}