commit 3ba1d395ead1eddcd2ab7404a4c80bb314a70783 Merge: f6f4d26 ff61d66 Author: Juan Ezquerro LLanes juan@paynopain.com Date: Tue Nov 29 11:09:49 2016 +0100
Merge branch 'master' into hidden_services
# Conflicts: # app/src/main/java/org/torproject/android/OrbotMainActivity.java
.../org/torproject/android/OrbotMainActivity.java | 1571 +++++++++++--------- app/src/main/res/layout/layout_main.xml | 15 +- app/src/main/res/layout/layout_orbot_control.xml | 12 +- .../org/torproject/android/service/TorService.java | 27 +- 4 files changed, 866 insertions(+), 759 deletions(-)
diff --cc app/src/main/java/org/torproject/android/OrbotMainActivity.java index a4bb32e,7706c0f..020bcb8 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@@ -99,20 -90,20 +93,20 @@@ public class OrbotMainActivity extends private TextView downloadText = null; private TextView uploadText = null; private TextView mTxtOrbotLog = null; - + private Button mBtnBrowser = null; - private Button mBtnStart = null; + private Button mBtnStart = null;
- private SwitchCompat mBtnVPN = null; + private SwitchCompat mBtnVPN = null; private SwitchCompat mBtnBridges = null; - + private Spinner spnCountries = null;
- private DrawerLayout mDrawer; - private ActionBarDrawerToggle mDrawerToggle; - + private DrawerLayout mDrawer; + private ActionBarDrawerToggle mDrawerToggle; + /* Some tracking bits */ - private String torStatus = TorServiceConstants.STATUS_OFF; //latest status reported from the tor service + private String torStatus = null; //latest status reported from the tor service private Intent lastStatusIntent; // the last ACTION_STATUS Intent received
private SharedPreferences mPrefs = null; @@@ -129,62 -120,39 +123,63 @@@ private final static int STATUS_UPDATE = 1; private static final int MESSAGE_TRAFFIC_COUNT = 2;
- public final static String INTENT_ACTION_REQUEST_HIDDEN_SERVICE = "org.torproject.android.REQUEST_HS_PORT"; - public final static String INTENT_ACTION_REQUEST_START_TOR = "org.torproject.android.START_TOR"; + public final static String INTENT_ACTION_REQUEST_HIDDEN_SERVICE = "org.torproject.android.REQUEST_HS_PORT"; + public final static String INTENT_ACTION_REQUEST_START_TOR = "org.torproject.android.START_TOR";
- // for bridge loading from the assets default bridges.txt file - class Bridge { - String type; - String config; + // for bridge loading from the assets default bridges.txt file + class Bridge + { + String type; + String config; } - + private ArrayList<Bridge> alBridges = null; - - + //this is needed for backwards compat back to Android 2.3.* @SuppressLint("NewApi") - public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { - if (Build.VERSION.SDK_INT >= 11) - return super.onCreateView(parent, name, context, attrs); + public View onCreateView(View parent, String name, Context context, AttributeSet attrs) + { + if(Build.VERSION.SDK_INT >= 11) + return super.onCreateView(parent, name, context, attrs); return null; } - - /** Called when the activity is first created. */ + + private void migratePreferences() { + String hsPortString = mPrefs.getString("pref_hs_ports", ""); + if (hsPortString.length() > 0) { + StringTokenizer st = new StringTokenizer(hsPortString, ","); + ContentResolver cr = getContentResolver(); + while (st.hasMoreTokens()) { + int hsPort = Integer.parseInt(st.nextToken().split(" ")[0]); + ContentValues fields = new ContentValues(); + fields.put("name", hsPort); + fields.put("port", hsPort); + fields.put("onion_port", hsPort); + cr.insert(HSContentProvider.CONTENT_URI, fields); + } + + Editor pEdit = mPrefs.edit(); + pEdit.remove("pref_hs_ports"); + pEdit.commit(); + } + } + + /** + * Called when the activity is first created. + */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
mPrefs = TorServiceUtils.getSharedPrefs(getApplicationContext());
+ migratePreferences(); // Migrate old preferences + /* Create the widgets before registering for broadcasts to guarantee * that the widgets exist when the status updates try to update them */ - doLayout(); + doLayout();
/* receive the internal status broadcasts, which are separate from the public - * status broadcasts to prevent other apps from sending fake/wrong status + * status broadcasts to prevent other apps from sending fake/wrong status * info to this app */ LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); lbm.registerReceiver(mLocalBroadcastReceiver, @@@ -559,264 -555,227 +582,273 @@@ } else stopVpnService(); } - - private void enableHiddenServicePort (int hsPort) throws RemoteException, InterruptedException - { - - Editor pEdit = mPrefs.edit(); - - String hsPortString = mPrefs.getString("pref_hs_ports", ""); - String onionHostname = mPrefs.getString("pref_hs_hostname",""); - - if (hsPortString.indexOf(hsPort+"")==-1) - { - if (hsPortString.length() > 0 && hsPortString.indexOf(hsPort+"")==-1) - hsPortString += ',' + hsPort; - else - hsPortString = hsPort + ""; - - pEdit.putString("pref_hs_ports", hsPortString); - pEdit.putBoolean("pref_hs_enable", true); - - pEdit.commit(); - }
- if (onionHostname == null || onionHostname.length() == 0) - { - requestTorRereadConfig(); + private void enableHiddenServicePort( + String hsName, final int hsPort, int hsRemotePort, + final String backupToPackage, final Uri hsKeyPath + ) throws RemoteException, InterruptedException {
- new Thread () { + String onionHostname = null;
- public void run () - { - String onionHostname = mPrefs.getString("pref_hs_hostname",""); + if (hsName == null) + hsName = "hs" + hsPort;
- while (onionHostname.length() == 0) - { - //we need to stop and start Tor - try { - Thread.sleep(3000); //wait three seconds - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - onionHostname = mPrefs.getString("pref_hs_hostname",""); - } - - Intent nResult = new Intent(); - nResult.putExtra("hs_host", onionHostname); - setResult(RESULT_OK, nResult); - finish(); - } - }.start(); - - } - else - { - Intent nResult = new Intent(); - nResult.putExtra("hs_host", onionHostname); - setResult(RESULT_OK, nResult); - finish(); - } - - } - - private synchronized void handleIntents () - { - if (getIntent() == null) - return; - - // Get intent, action and MIME type - Intent intent = getIntent(); - String action = intent.getAction(); - Log.d(TAG, "handleIntents " + action); + if (hsRemotePort == -1) + hsRemotePort = hsPort;
- //String type = intent.getType(); - - if (action == null) - return; - - if (action.equals(INTENT_ACTION_REQUEST_HIDDEN_SERVICE)) - { - final int hiddenServicePortRequest = getIntent().getIntExtra("hs_port", -1); - - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - - public void onClick(DialogInterface dialog, int which) { - switch (which){ - case DialogInterface.BUTTON_POSITIVE: - - try { - enableHiddenServicePort (hiddenServicePortRequest); - - } catch (RemoteException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + ContentValues fields = new ContentValues(); + fields.put(HSContentProvider.HiddenService.NAME, hsName); + fields.put(HSContentProvider.HiddenService.PORT, hsPort); + fields.put(HSContentProvider.HiddenService.ONION_PORT, hsRemotePort);
- - break; - - case DialogInterface.BUTTON_NEGATIVE: - //No button clicked - finish(); - break; - } - } - }; - - String requestMsg = getString(R.string.hidden_service_request, hiddenServicePortRequest); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(requestMsg).setPositiveButton("Allow", dialogClickListener) - .setNegativeButton("Deny", dialogClickListener).show(); - - return; //don't null the setIntent() as we need it later - } - else if (action.equals(INTENT_ACTION_REQUEST_START_TOR)) - { - autoStartFromIntent = true; - - startTor(); - - //never allow backgrounds start from this type of intent start - //app devs who want background starts, can use the service intents - /** - if (Prefs.allowBackgroundStarts()) - { - Intent resultIntent; - if (lastStatusIntent == null) { - resultIntent = new Intent(intent); - } else { - resultIntent = lastStatusIntent; - } - resultIntent.putExtra(TorServiceConstants.EXTRA_STATUS, torStatus); - setResult(RESULT_OK, resultIntent); - finish(); - }*/ - - } - else if (action.equals(Intent.ACTION_VIEW)) - { - String urlString = intent.getDataString(); - - if (urlString != null) - { - - if (urlString.toLowerCase().startsWith("bridge://")) + ContentResolver cr = getContentResolver();
- { - String newBridgeValue = urlString.substring(9); //remove the bridge protocol piece - newBridgeValue = URLDecoder.decode(newBridgeValue); //decode the value here + Cursor row = cr.query( + HSContentProvider.CONTENT_URI, + HSContentProvider.PROJECTION, + HSContentProvider.HiddenService.ONION_PORT + "=" + hsPort, + null, + null + );
- showAlert(getString(R.string.bridges_updated),getString(R.string.restart_orbot_to_use_this_bridge_) + newBridgeValue,false); - - setNewBridges(newBridgeValue); - } - } - } - - updateStatus(null); - - setIntent(null); - - - } - - private void setNewBridges (String newBridgeValue) - { + if (row == null || row.getCount() < 1) { + cr.insert(HSContentProvider.CONTENT_URI, fields); + } else { + onionHostname = row.getString(row.getColumnIndex(HSContentProvider.HiddenService.DOMAIN)); + row.close(); + }
- Prefs.setBridgesList(newBridgeValue); //set the string to a preference - Prefs.putBridgesEnabled(true); - - setResult(RESULT_OK); - - mBtnBridges.setChecked(true); - - enableBridges(true); - } + if (onionHostname == null || onionHostname.length() < 1) { + + if (hsKeyPath != null) { + BackupUtils hsutils = new BackupUtils(getApplicationContext()); + hsutils.restoreKeyBackup(hsPort, hsKeyPath); + } + + if (torStatus.equals(TorServiceConstants.STATUS_OFF)) { + startTor(); + } else { + stopTor(); + Toast.makeText( + this, R.string.start_tor_again_for_finish_the_process, Toast.LENGTH_LONG + ).show(); + } + + new Thread() { + + public void run() { + String hostname = null; + Intent nResult = new Intent(); + + while (hostname == null) { + try { + Thread.sleep(3000); //wait three seconds + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + Cursor onion = getContentResolver().query( + HSContentProvider.CONTENT_URI, + HSContentProvider.PROJECTION, + HSContentProvider.HiddenService.ONION_PORT + "=" + hsPort, + null, + null + ); + + if (onion != null && onion.getCount() > 0) { + onion.moveToNext(); + hostname = onion.getString(onion.getColumnIndex(HSContentProvider.HiddenService.DOMAIN)); + + if(hostname == null || hostname.length() < 1) + continue; + + nResult.putExtra("hs_host", hostname); + + if (backupToPackage != null && backupToPackage.length() > 0) { + String servicePath = getFilesDir() + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR + "/hs" + hsPort; + File hidden_service_key = new File(servicePath, "private_key"); + Context context = getApplicationContext(); + + Uri contentUri = getUriForFile( + context, + "org.torproject.android.ui.hiddenservices.storage", + hidden_service_key + ); + + context.grantUriPermission(backupToPackage, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + nResult.setData(contentUri); + nResult.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + onion.close(); + setResult(RESULT_OK, nResult); + finish(); + } + } + } + }.start(); + + } else { + Intent nResult = new Intent(); + nResult.putExtra("hs_host", onionHostname); + setResult(RESULT_OK, nResult); + finish(); + } + } + + private synchronized void handleIntents() { + if (getIntent() == null) + return; + + // Get intent, action and MIME type + Intent intent = getIntent(); + String action = intent.getAction(); + Log.d(TAG, "handleIntents " + action); + + //String type = intent.getType(); + + if (action == null) + return; + + switch (action) { + case INTENT_ACTION_REQUEST_HIDDEN_SERVICE: + final int hiddenServicePort = intent.getIntExtra("hs_port", -1); + final int hiddenServiceRemotePort = intent.getIntExtra("hs_onion_port", -1); + final String hiddenServiceName = intent.getStringExtra("hs_name"); + final String backupToPackage = intent.getStringExtra("hs_backup_to_package"); + final Uri mKeyUri = intent.getData(); + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + try { + enableHiddenServicePort( + hiddenServiceName, hiddenServicePort, + hiddenServiceRemotePort, backupToPackage, mKeyUri + ); + } catch (RemoteException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + break; + } + } + }; + + String requestMsg = getString(R.string.hidden_service_request, hiddenServicePort); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(requestMsg).setPositiveButton("Allow", dialogClickListener) + .setNegativeButton("Deny", dialogClickListener).show(); + + return; //don't null the setIntent() as we need it later + + case INTENT_ACTION_REQUEST_START_TOR: + autoStartFromIntent = true; + + startTor(); + + //never allow backgrounds start from this type of intent start + //app devs who want background starts, can use the service intents + /** + if (Prefs.allowBackgroundStarts()) + { + Intent resultIntent; + if (lastStatusIntent == null) { + resultIntent = new Intent(intent); + } else { + resultIntent = lastStatusIntent; + } + resultIntent.putExtra(TorServiceConstants.EXTRA_STATUS, torStatus); + setResult(RESULT_OK, resultIntent); + finish(); + }*/ + + break; + case Intent.ACTION_VIEW: + String urlString = intent.getDataString(); + + if (urlString != null) { + + if (urlString.toLowerCase().startsWith("bridge://")) + + { + String newBridgeValue = urlString.substring(9); //remove the bridge protocol piece + newBridgeValue = URLDecoder.decode(newBridgeValue); //decode the value here + + showAlert(getString(R.string.bridges_updated), getString(R.string.restart_orbot_to_use_this_bridge_) + newBridgeValue, false); + + setNewBridges(newBridgeValue); + } + } + break; + } + + updateStatus(null); + + setIntent(null); + + } + + private void setNewBridges(String newBridgeValue) { + + Prefs.setBridgesList(newBridgeValue); //set the string to a preference + Prefs.putBridgesEnabled(true); + + setResult(RESULT_OK); + + mBtnBridges.setChecked(true); + + enableBridges(true); + }
- /* - * Launch the system activity for Uri viewing with the provided url - */ - private void openBrowser(final String browserLaunchUrl, boolean forceExternal) { - boolean isBrowserInstalled = appInstalledOrNot(TorServiceConstants.BROWSER_APP_USERNAME); - - if (isBrowserInstalled) { - startIntent(TorServiceConstants.BROWSER_APP_USERNAME, Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); - } else if (mBtnVPN.isChecked() || forceExternal) { - //use the system browser since VPN is on - startIntent(null, Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); - } else if (Prefs.useTransparentProxying()) { - startIntent(null, Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); - } else { - AlertDialog aDialog = new AlertDialog.Builder(OrbotMainActivity.this) - .setTitle(R.string.install_apps_) - .setMessage(R.string.it_doesn_t_seem_like_you_have_orweb_installed_want_help_with_that_or_should_we_just_open_the_browser_) - .setPositiveButton(R.string.install_orweb, new Dialog.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - - //prompt to install Orweb - //Intent intent = new Intent(OrbotMainActivity.this,PromoAppsActivity.class); - //startActivity(intent); - - startActivity(PromoAppsActivity.getInstallIntent(TorServiceConstants.BROWSER_APP_USERNAME, OrbotMainActivity.this)); + /* + * Launch the system activity for Uri viewing with the provided url + */ + private void openBrowser(final String browserLaunchUrl,boolean forceExternal) + { + boolean isBrowserInstalled = appInstalledOrNot(TorServiceConstants.BROWSER_APP_USERNAME);
+ if (isBrowserInstalled) + { + startIntent(TorServiceConstants.BROWSER_APP_USERNAME,Intent.ACTION_VIEW,Uri.parse(browserLaunchUrl)); + } + else if (mBtnVPN.isChecked()||forceExternal) + { + //use the system browser since VPN is on + startIntent(null,Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); + } + else if (Prefs.useTransparentProxying()) + { + startIntent(null,Intent.ACTION_VIEW, Uri.parse(browserLaunchUrl)); + } + else + { + AlertDialog aDialog = new AlertDialog.Builder(OrbotMainActivity.this) + .setTitle(R.string.install_apps_) + .setMessage(R.string.it_doesn_t_seem_like_you_have_orweb_installed_want_help_with_that_or_should_we_just_open_the_browser_) + .setPositiveButton(R.string.install_orweb, new Dialog.OnClickListener () + { + + @Override + public void onClick(DialogInterface dialog, int which) { + + //prompt to install Orweb + //Intent intent = new Intent(OrbotMainActivity.this,PromoAppsActivity.class); + //startActivity(intent); + + startActivity(PromoAppsActivity.getInstallIntent(TorServiceConstants.BROWSER_APP_USERNAME,OrbotMainActivity.this));
- }
- }) + } + + }) .setNeutralButton(R.string.apps_mode, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@@ -1173,11 -1190,16 +1263,12 @@@ getString(R.string.connect_first_time), true); }
- if (autoStartFromIntent) { + if (autoStartFromIntent) + { autoStartFromIntent = false; -- Intent resultIntent = lastStatusIntent; - resultIntent.putExtra(TorServiceConstants.EXTRA_STATUS, torStatus); - setResult(RESULT_OK, resultIntent); - - if (resultIntent == null) - resultIntent = new Intent(TorServiceConstants.ACTION_START); - ++ Intent resultIntent = lastStatusIntent; + resultIntent.putExtra(TorServiceConstants.EXTRA_STATUS, torStatus); + setResult(RESULT_OK, resultIntent); finish(); Log.d(TAG, "autoStartFromIntent finish"); }
tor-commits@lists.torproject.org