commit 7ce301042cd9a56155b764f1e18f7396bc21b8fc Author: bim dsnake@protonmail.com Date: Sat Nov 14 20:59:02 2020 -0500
Initial work for V3 UI, DB Stuff, etc --- app/src/main/AndroidManifest.xml | 14 + .../org/torproject/android/OrbotMainActivity.java | 33 +- .../ui/hiddenservices/HiddenServicesActivity.java | 6 +- .../hiddenservices/adapters/OnionListAdapter.java | 7 +- .../ui/hiddenservices/dialogs/HSDeleteDialog.java | 6 +- .../permissions/PermissionManager.java | 14 +- .../providers/HSContentProvider.java | 6 +- .../DeleteOnionServiceDialogFragment.java | 41 +++ .../NewOnionServiceDialogFragment.java | 98 +++++ .../OnionServiceActionsDialogFragment.java | 93 +++++ .../OnionServiceContentProvider.java | 117 ++++++ .../ui/v3onionservice/OnionServiceDatabase.java | 38 ++ .../ui/v3onionservice/OnionServicesActivity.java | 98 +++++ .../ui/v3onionservice/OnionV3ListAdapter.java | 54 +++ app/src/main/res/menu/orbot_main.xml | 125 ++++--- app/src/main/res/values/strings.xml | 2 + .../java/org/torproject/android/core/DiskUtils.kt | 8 +- .../torproject/android/service/OrbotService.java | 408 +++++++-------------- .../android/service/TorServiceConstants.java | 2 +- 19 files changed, 797 insertions(+), 373 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a9db7611..7b81951f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -92,6 +92,15 @@ android:value=".OrbotMainActivity" /> </activity>
+ <activity + android:name=".ui.v3onionservice.OnionServicesActivity" + android:label="@string/hidden_services" + android:theme="@style/DefaultTheme"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".OrbotMainActivity" /> + </activity> + <activity android:name=".ui.hiddenservices.ClientCookiesActivity" android:label="@string/client_cookies" @@ -123,6 +132,11 @@ android:authorities="org.torproject.android.ui.hiddenservices.providers" android:exported="false" />
+ <provider + android:name=".ui.v3onionservice.OnionServiceContentProvider" + android:authorities="org.torproject.android.ui.v3onionservice" + android:exported="false" /> + <provider android:name="androidx.core.content.FileProvider" android:authorities="org.torproject.android.ui.hiddenservices.storage" diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index 1ee58106..abc87cc0 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -74,6 +74,7 @@ import org.torproject.android.ui.hiddenservices.permissions.PermissionManager; import org.torproject.android.ui.hiddenservices.providers.HSContentProvider; import org.torproject.android.ui.onboarding.BridgeWizardActivity; import org.torproject.android.ui.onboarding.OnboardingActivity; +import org.torproject.android.ui.v3onionservice.OnionServicesActivity;
import java.io.File; import java.io.UnsupportedEncodingException; @@ -114,6 +115,9 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan private static final int MESSAGE_PORTS = 3; private static final float ROTATE_FROM = 0.0f; private static final float ROTATE_TO = 360.0f * 4f;// 3.141592654f * 32.0f; + // this is what takes messages or values from the callback threads or other non-mainUI threads + // and passes them back into the main UI thread for display to the user + private final Handler mStatusUpdateHandler = new MainActivityStatusUpdateHandler(this); PulsatorLayout mPulsator; AlertDialog aDialog = null; /* Useful UI bits */ @@ -131,11 +135,6 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan /* Some tracking bits */ private String torStatus = null; //latest status reported from the tor service private Intent lastStatusIntent; // the last ACTION_STATUS Intent received - private SharedPreferences mPrefs = null; - private boolean autoStartFromIntent = false; - // this is what takes messages or values from the callback threads or other non-mainUI threads - // and passes them back into the main UI thread for display to the user - private final Handler mStatusUpdateHandler = new MainActivityStatusUpdateHandler(this); /** * The state and log info from {@link OrbotService} are sent to the UI here in * the form of a local broadcast. Regular broadcasts can be sent by any app, @@ -202,6 +201,8 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan } } }; + private SharedPreferences mPrefs = null; + private boolean autoStartFromIntent = false;
private void migratePreferences() { String hsPortString = mPrefs.getString("pref_hs_ports", ""); @@ -463,6 +464,8 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan } }
+ } else if (item.getItemId() == R.id.menu_v3_onion_services) { + startActivity(new Intent(this, OnionServicesActivity.class)); } else if (item.getItemId() == R.id.menu_hidden_services) { startActivity(new Intent(this, HiddenServicesActivity.class)); } else if (item.getItemId() == R.id.menu_client_cookies) { @@ -534,12 +537,8 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan sendIntentToService(ACTION_START_VPN); }
- private void enableHiddenServicePort( - String hsName, final int hsPort, int hsRemotePort, - final String backupToPackage, final Uri hsKeyPath, - final Boolean authCookie - ) { - + private void enableHiddenServicePort(String hsName, final int hsPort, int hsRemotePort, + final String backupToPackage, final Uri hsKeyPath, final Boolean authCookie) { String onionHostname = null;
if (hsName == null) @@ -687,9 +686,9 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan };
String requestMsg = getString(R.string.hidden_service_request, String.valueOf(hiddenServicePort)); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(requestMsg).setPositiveButton("Allow", dialogClickListener) - .setNegativeButton("Deny", dialogClickListener).show(); + new AlertDialog.Builder(this).setMessage(requestMsg) + .setPositiveButton(R.string.allow, dialogClickListener) + .setNegativeButton(R.string.deny, dialogClickListener).show();
return; //don't null the setIntent() as we need it later
@@ -1103,12 +1102,14 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan imgStatus.startAnimation(rotation); lblStatus.setText(getString(R.string.newnym)); break; - case STATUS_STARTING: return; // tor is starting up, a new identity isn't needed + case STATUS_STARTING: + return; // tor is starting up, a new identity isn't needed case STATUS_OFF: case STATUS_STOPPING: startTor(); break; - default: break; + default: + break; } }
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java index 6c780dde..d7429181 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/HiddenServicesActivity.java @@ -61,13 +61,9 @@ public class HiddenServicesActivity extends AppCompatActivity { mResolver = getContentResolver();
fab = findViewById(R.id.fab); - fab.setOnClickListener(view -> { - HSDataDialog dialog = new HSDataDialog(); - dialog.show(getSupportFragmentManager(), "HSDataDialog"); - }); + fab.setOnClickListener(view -> new HSDataDialog().show(getSupportFragmentManager(), "HSDataDialog"));
mAdapter = new OnionListAdapter(this, mResolver.query(HSContentProvider.CONTENT_URI, HSContentProvider.PROJECTION, mWhere, null, null), 0); - mResolver.registerContentObserver(HSContentProvider.CONTENT_URI, true, new HSObserver(new Handler()));
ListView onion_list = findViewById(R.id.onion_list); diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java index d4e39ece..e3983cfd 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/adapters/OnionListAdapter.java @@ -25,8 +25,7 @@ public class OnionListAdapter extends CursorAdapter { }
@Override - public void bindView(View view, Context context, Cursor cursor) { - final Context mContext = context; + public void bindView(View view, final Context context, Cursor cursor) { int id = cursor.getInt(cursor.getColumnIndex(HSContentProvider.HiddenService._ID)); final String where = HSContentProvider.HiddenService._ID + "=" + id;
@@ -40,12 +39,12 @@ public class OnionListAdapter extends CursorAdapter { SwitchCompat enabled = view.findViewById(R.id.hs_switch); enabled.setChecked(cursor.getInt(cursor.getColumnIndex(HSContentProvider.HiddenService.ENABLED)) == 1); enabled.setOnCheckedChangeListener((buttonView, isChecked) -> { - ContentResolver resolver = mContext.getContentResolver(); + ContentResolver resolver = context.getContentResolver(); ContentValues fields = new ContentValues(); fields.put(HSContentProvider.HiddenService.ENABLED, isChecked); resolver.update(HSContentProvider.CONTENT_URI, fields, where, null);
- Toast.makeText(mContext, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); + Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); }); }
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDeleteDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDeleteDialog.java index d26141a0..f4a96226 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDeleteDialog.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDeleteDialog.java @@ -20,11 +20,9 @@ public class HSDeleteDialog extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle arguments = getArguments(); - final Context context = getContext(); - return new AlertDialog.Builder(context) + return new AlertDialog.Builder(getContext()) .setTitle(R.string.confirm_service_deletion) - .setPositiveButton(android.R.string.ok, (dialog, which) -> doDelete(arguments, context)) + .setPositiveButton(android.R.string.ok, (dialog, which) -> doDelete(getArguments(), getContext())) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel()) .create(); } diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/permissions/PermissionManager.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/permissions/PermissionManager.java index 6d181967..52c5dc20 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/permissions/PermissionManager.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/permissions/PermissionManager.java @@ -23,9 +23,8 @@ public class PermissionManager {
@TargetApi(Build.VERSION_CODES.M) public static void requestBatteryPermissions(FragmentActivity activity, Context context) { - final Context mContext = context; - final String packageName = mContext.getPackageName(); - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + final String packageName = context.getPackageName(); + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName)) return; @@ -37,18 +36,15 @@ public class PermissionManager { Intent intent = new Intent(); intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); - mContext.startActivity(intent); + context.startActivity(intent); }).show(); }
@TargetApi(Build.VERSION_CODES.M) public static void requestDropBatteryPermissions(FragmentActivity activity, Context context) { - final Context mContext = context; - - final String packageName = context.getPackageName(); PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- if (!pm.isIgnoringBatteryOptimizations(packageName)) + if (!pm.isIgnoringBatteryOptimizations(context.getPackageName())) return;
Snackbar.make(activity.findViewById(android.R.id.content), @@ -57,7 +53,7 @@ public class PermissionManager { v -> { Intent intent = new Intent(); intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); - mContext.startActivity(intent); + context.startActivity(intent); }).show(); } } diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java index 87cad0ad..79b566fd 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/providers/HSContentProvider.java @@ -27,8 +27,7 @@ public class HSContentProvider extends ContentProvider { HiddenService.ENABLED }; private static final String AUTH = "org.torproject.android.ui.hiddenservices.providers"; - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTH + "/hs"); + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTH + "/hs"); //UriMatcher private static final int ONIONS = 1; private static final int ONION_ID = 2; @@ -61,8 +60,7 @@ public class HSContentProvider extends ContentProvider {
SQLiteDatabase db = mServervices.getReadableDatabase();
- return db.query(HSDatabase.HS_DATA_TABLE_NAME, projection, where, - selectionArgs, null, null, sortOrder); + return db.query(HSDatabase.HS_DATA_TABLE_NAME, projection, where, selectionArgs, null, null, sortOrder); }
@Nullable diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/DeleteOnionServiceDialogFragment.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/DeleteOnionServiceDialogFragment.java new file mode 100644 index 00000000..5028e8f3 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/DeleteOnionServiceDialogFragment.java @@ -0,0 +1,41 @@ +package org.torproject.android.ui.v3onionservice; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + +import org.torproject.android.R; +import org.torproject.android.core.DiskUtils; +import org.torproject.android.service.TorServiceConstants; +import org.torproject.android.ui.hiddenservices.HiddenServicesActivity; + +import java.io.File; + +public class DeleteOnionServiceDialogFragment extends DialogFragment { + DeleteOnionServiceDialogFragment(Bundle arguments) { + super(); + setArguments(arguments); + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + return new AlertDialog.Builder(getContext()) + .setTitle(R.string.confirm_service_deletion) + .setPositiveButton(android.R.string.ok, (dialog, which) -> doDelete(getArguments(), getContext())) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel()) + .create(); + } + + private void doDelete(Bundle arguments, Context context) { + context.getContentResolver().delete(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.OnionService._ID + '=' + arguments.getInt(OnionServicesActivity.BUNDLE_KEY_ID), null); + String base = context.getFilesDir().getAbsolutePath() + "/" + TorServiceConstants.ONION_SERVICES_DIR; + DiskUtils.recursivelyDeleteDirectory(new File(base, "v3" + arguments.getString(OnionServicesActivity.BUNDLE_KEY_PORT))); + } + +} diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/NewOnionServiceDialogFragment.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/NewOnionServiceDialogFragment.java new file mode 100644 index 00000000..1929eb72 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/NewOnionServiceDialogFragment.java @@ -0,0 +1,98 @@ +package org.torproject.android.ui.v3onionservice; + +import android.app.Dialog; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + +import org.torproject.android.R; + +public class NewOnionServiceDialogFragment extends DialogFragment { + + private EditText etServer, etLocalPort, etOnionPort; + private TextWatcher inputValidator; + + @Override + public void onStart() { + super.onStart(); + inputValidator.afterTextChanged(null); // initially disable positive button + } + + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final View dialogView = getActivity().getLayoutInflater().inflate(R.layout.layout_hs_data_dialog, null); + dialogView.findViewById(R.id.hsAuth).setVisibility(View.GONE); + etServer = dialogView.findViewById(R.id.hsName); + etLocalPort = dialogView.findViewById(R.id.hsLocalPort); + etOnionPort = dialogView.findViewById(R.id.hsOnionPort); + + AlertDialog alertDialog = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.hidden_services) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel()) + .setPositiveButton(R.string.save, (dialog, which) -> doSave(getContext())) + .setView(dialogView) + .create(); + + + inputValidator = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { // no-op + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { //no-op + } + + @Override + public void afterTextChanged(Editable s) { + Button btn = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + try { + int localPort = Integer.parseInt(etLocalPort.getText().toString()); + int onionPort = Integer.parseInt(etOnionPort.getText().toString()); + btn.setEnabled(checkInput(localPort, onionPort)); + } catch (NumberFormatException nfe) { + btn.setEnabled(false); + } + } + }; + + etServer.addTextChangedListener(inputValidator); + etLocalPort.addTextChangedListener(inputValidator); + etOnionPort.addTextChangedListener(inputValidator); + return alertDialog; + } + + private boolean checkInput(int local, int remote) { + if ((local < 1 || local > 65535) || (remote < 1 || remote > 65535)) return false; + return !TextUtils.isEmpty(etServer.getText().toString().trim()); + } + + private void doSave(Context context) { + String serverName = etServer.getText().toString().trim(); + int localPort = Integer.parseInt(etLocalPort.getText().toString()); + int onionPort = Integer.parseInt(etOnionPort.getText().toString()); + ContentValues fields = new ContentValues(); + fields.put(OnionServiceContentProvider.OnionService.NAME, serverName); + fields.put(OnionServiceContentProvider.OnionService.PORT, localPort); + fields.put(OnionServiceContentProvider.OnionService.ONION_PORT, onionPort); + fields.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, 1); + ContentResolver cr = getContext().getContentResolver(); + cr.insert(OnionServiceContentProvider.CONTENT_URI, fields); + Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActionsDialogFragment.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActionsDialogFragment.java new file mode 100644 index 00000000..822a45f2 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActionsDialogFragment.java @@ -0,0 +1,93 @@ +package org.torproject.android.ui.v3onionservice; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + +import org.torproject.android.R; +import org.torproject.android.core.ClipboardUtils; +import org.torproject.android.core.DiskUtils; +import org.torproject.android.ui.hiddenservices.backup.BackupUtils; + +import java.io.File; + +public class OnionServiceActionsDialogFragment extends DialogFragment { + + private static final int REQUEST_CODE_WRITE_FILE = 343; + + OnionServiceActionsDialogFragment(Bundle arguments) { + super(); + setArguments(arguments); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Bundle arguments = getArguments(); + AlertDialog ad = new AlertDialog.Builder(getActivity()) + .setItems(new CharSequence[]{ + getString(R.string.copy_address_to_clipboard), + getString(R.string.backup_service), + getString(R.string.delete_service)}, null) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) + .setTitle(R.string.hidden_services) + .create(); + + // done this way so we can startActivityForResult on backup without the dialog vanishing + ad.getListView().setOnItemClickListener((parent, view, position, id) -> { + if (position == 0) doCopy(arguments, getContext()); + else if (position == 1) doBackup(arguments, getContext()); + else if (position == 2) + new DeleteOnionServiceDialogFragment(arguments).show(getFragmentManager(), DeleteOnionServiceDialogFragment.class.getSimpleName()); + if (position != 1) dismiss(); + }); + return ad; + } + + private void doCopy(Bundle arguments, Context context) { + String onion = arguments.getString(OnionServicesActivity.BUNDLE_KEY_DOMAIN); + if (onion == null) + Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); + else + ClipboardUtils.copyToClipboard("onion", onion, getString(R.string.done), context); + } + + private void doBackup(Bundle arguments, Context context) { + String filename = "onion_service" + arguments.getInt(OnionServicesActivity.BUNDLE_KEY_PORT) + ".zip"; + if (arguments.getString(OnionServicesActivity.BUNDLE_KEY_DOMAIN) == null) { + Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); + return; + } + if (DiskUtils.supportsStorageAccessFramework()) { + Intent createFileIntent = DiskUtils.createWriteFileIntent(filename, "application/zip"); + startActivityForResult(createFileIntent, REQUEST_CODE_WRITE_FILE); + } else { // APIs 16, 17, 18 + attemptToWriteBackup(Uri.fromFile(new File(DiskUtils.getOrCreateLegacyBackupDir(), filename))); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_WRITE_FILE && resultCode == Activity.RESULT_OK) { + if (data != null) { + attemptToWriteBackup(data.getData()); + } + } + } + + private void attemptToWriteBackup(Uri outputFile) { + BackupUtils backupUtils = new BackupUtils(getContext()); +// String backup = backupUtils.createZipBackup(port, outputFile); TODO need to break apart backup logic for v2 and v3 onions + Toast.makeText(getContext(), backup != null ? R.string.backup_saved_at_external_storage : R.string.error, Toast.LENGTH_LONG).show(); + dismiss(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceContentProvider.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceContentProvider.java new file mode 100644 index 00000000..d61f7935 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceContentProvider.java @@ -0,0 +1,117 @@ +package org.torproject.android.ui.v3onionservice; + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.provider.BaseColumns; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class OnionServiceContentProvider extends ContentProvider { + + public static final String[] PROJECTION = { + OnionService._ID, + OnionService.NAME, + OnionService.PORT, + OnionService.DOMAIN, + OnionService.ONION_PORT, + OnionService.CREATED_BY_USER, + OnionService.ENABLED + }; + + private static final int ONIONS = 1, ONION_ID = 2; + private static final String AUTH = "org.torproject.android.ui.v3onionservice"; + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTH + "/v3"); + private static final UriMatcher uriMatcher; + + static { + uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + uriMatcher.addURI(AUTH, "v3", ONIONS); + uriMatcher.addURI(AUTH, "v3/#", ONION_ID); + } + + private OnionServiceDatabase mDatabase; + + @Override + public boolean onCreate() { + mDatabase = new OnionServiceDatabase(getContext()); + return true; + } + + @Nullable + @Override + public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { + String where = selection; + if (uriMatcher.match(uri) == ONION_ID) { + where = "_id=" + uri.getLastPathSegment(); + } + + SQLiteDatabase db = mDatabase.getReadableDatabase(); + return db.query(OnionServiceDatabase.ONION_SERVICE_TABLE_NAME, projection, where, selectionArgs, null, null, sortOrder); + } + + @Nullable + @Override + public String getType(@NonNull Uri uri) { + int match = uriMatcher.match(uri); + switch (match) { + case ONIONS: + return "vnd.android.cursor.dir/vnd.torproject.onions"; + case ONION_ID: + return "vnd.android.cursor.item/vnd.torproject.onion"; + default: + return null; + } + } + + @Nullable + @Override + public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { + SQLiteDatabase db = mDatabase.getWritableDatabase(); + long regId = db.insert(OnionServiceDatabase.ONION_SERVICE_TABLE_NAME, null, values); + getContext().getContentResolver().notifyChange(CONTENT_URI, null); + return ContentUris.withAppendedId(CONTENT_URI, regId); + } + + @Override + public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { + if (uriMatcher.match(uri) == ONION_ID) { + selection = "_id=" + uri.getLastPathSegment(); + } + SQLiteDatabase db = mDatabase.getWritableDatabase(); + int rows = db.delete(OnionServiceDatabase.ONION_SERVICE_TABLE_NAME, selection, selectionArgs); + getContext().getContentResolver().notifyChange(CONTENT_URI, null); + return rows; + } + + @Override + public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { + SQLiteDatabase db = mDatabase.getWritableDatabase(); + String where = selection; + if (uriMatcher.match(uri) == ONION_ID) { + where = "_id=" + uri.getLastPathSegment(); + } + + int rows = db.update(OnionServiceDatabase.ONION_SERVICE_TABLE_NAME, values, where, null); + getContext().getContentResolver().notifyChange(CONTENT_URI, null); + return rows; + } + + public static final class OnionService implements BaseColumns { + public static final String NAME = "name"; + public static final String PORT = "port"; + public static final String ONION_PORT = "onion_port"; + public static final String DOMAIN = "domain"; + public static final String CREATED_BY_USER = "created_by_user"; + public static final String ENABLED = "enabled"; + + private OnionService() { // no-op + } + } + +} diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java new file mode 100644 index 00000000..f2a812e8 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java @@ -0,0 +1,38 @@ +package org.torproject.android.ui.v3onionservice; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class OnionServiceDatabase extends SQLiteOpenHelper { + + static final String DATABASE_NAME = "onion_service", + ONION_SERVICE_TABLE_NAME = "onion_services"; + private static final int DATABASE_VERSION = 1; + + private static final String ONION_SERVICES_CREATE_SQL = + "CREATE TABLE " + ONION_SERVICE_TABLE_NAME + " (" + + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, " + + "domain TEXT, " + + "onion_port INTEGER, " + + "created_by_user INTEGER DEFAULT 0, " + + "enabled INTEGER DEFAULT 1, " + + "port INTEGER);"; + + public OnionServiceDatabase(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(ONION_SERVICES_CREATE_SQL); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + + +} diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java new file mode 100644 index 00000000..3be04731 --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java @@ -0,0 +1,98 @@ +package org.torproject.android.ui.v3onionservice; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.Bundle; +import android.os.Handler; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.ListView; +import android.widget.RadioButton; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import org.torproject.android.R; +import org.torproject.android.core.DiskUtils; +import org.torproject.android.core.LocaleHelper; + +public class OnionServicesActivity extends AppCompatActivity { + + static final String BUNDLE_KEY_ID = "id", BUNDLE_KEY_PORT = "port", BUNDLE_KEY_DOMAIN = "domain"; + private static final String WHERE_SELECTION_CLAUSE = OnionServiceContentProvider.OnionService.CREATED_BY_USER + "=1"; + private RadioButton radioShowUserServices, radioShowAppServices; + private FloatingActionButton fab; + private ContentResolver mContentResolver; + private OnionV3ListAdapter mAdapter; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + setContentView(R.layout.layout_hs_list_view); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + fab = findViewById(R.id.fab); + fab.setOnClickListener(v -> new NewOnionServiceDialogFragment().show(getSupportFragmentManager(), "NewOnionServiceDialogFragment")); + + mContentResolver = getContentResolver(); + mAdapter = new OnionV3ListAdapter(this, mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, WHERE_SELECTION_CLAUSE, null, null), 0); + mContentResolver.registerContentObserver(OnionServiceContentProvider.CONTENT_URI, true, new OnionServiceObserver(new Handler())); + + ListView onionList = findViewById(R.id.onion_list); + onionList.setAdapter(mAdapter); + onionList.setOnItemClickListener((parent, view, position, id) -> { + Cursor item = (Cursor) parent.getItemAtPosition(position); + Bundle arguments = new Bundle(); + arguments.putInt(BUNDLE_KEY_ID, item.getInt(item.getColumnIndex(OnionServiceContentProvider.OnionService._ID))); + arguments.putString(BUNDLE_KEY_PORT, item.getString(item.getColumnIndex(OnionServiceContentProvider.OnionService.PORT))); + arguments.putString(BUNDLE_KEY_DOMAIN, item.getString(item.getColumnIndex(OnionServiceContentProvider.OnionService.DOMAIN))); + OnionServiceActionsDialogFragment dialog = new OnionServiceActionsDialogFragment(arguments); + dialog.show(getSupportFragmentManager(), OnionServiceActionsDialogFragment.class.getSimpleName()); + }); + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(LocaleHelper.onAttach(base)); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.hs_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.menu_restore_backup) { + if (DiskUtils.supportsStorageAccessFramework()) { + + } else { // 16, 17, 18 + + } + } + return super.onOptionsItemSelected(item); + } + + private class OnionServiceObserver extends ContentObserver { + + OnionServiceObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + mAdapter.changeCursor(mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, WHERE_SELECTION_CLAUSE, null, null)); + // todo battery optimization stuff if lollipop or higher and running onion services + } + } + + +} diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionV3ListAdapter.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionV3ListAdapter.java new file mode 100644 index 00000000..c0489d3c --- /dev/null +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionV3ListAdapter.java @@ -0,0 +1,54 @@ +package org.torproject.android.ui.v3onionservice; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.widget.SwitchCompat; + +import org.torproject.android.R; +import org.torproject.android.ui.hiddenservices.providers.HSContentProvider; + +public class OnionV3ListAdapter extends CursorAdapter { + + private final LayoutInflater mLayoutInflater; + + OnionV3ListAdapter(Context context, Cursor cursor, int flags) { + super(context, cursor, flags); + mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mLayoutInflater.inflate(R.layout.layout_hs_list_item, parent, false); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + int id = cursor.getInt(cursor.getColumnIndex(OnionServiceContentProvider.OnionService._ID)); + final String where = OnionServiceContentProvider.OnionService._ID + "=" + id; + TextView port = view.findViewById(R.id.hs_port); + port.setText(cursor.getString(cursor.getColumnIndex(OnionServiceContentProvider.OnionService.PORT))); + TextView name = view.findViewById(R.id.hs_name); + name.setText(cursor.getString(cursor.getColumnIndex(OnionServiceContentProvider.OnionService.NAME))); + TextView domain = view.findViewById(R.id.hs_onion); + domain.setText(cursor.getString(cursor.getColumnIndex(OnionServiceContentProvider.OnionService.DOMAIN))); + + SwitchCompat enabled = view.findViewById(R.id.hs_switch); + enabled.setChecked(cursor.getInt(cursor.getColumnIndex(OnionServiceContentProvider.OnionService.ENABLED)) == 1); + enabled.setOnCheckedChangeListener((buttonView, isChecked) -> { + ContentResolver resolver = context.getContentResolver(); + ContentValues fields = new ContentValues(); + fields.put(OnionServiceContentProvider.OnionService.ENABLED, isChecked); + resolver.update(OnionServiceContentProvider.CONTENT_URI, fields, where, null); + Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show(); + }); + } +} diff --git a/app/src/main/res/menu/orbot_main.xml b/app/src/main/res/menu/orbot_main.xml index 6359ebdc..2fb0ad4e 100644 --- a/app/src/main/res/menu/orbot_main.xml +++ b/app/src/main/res/menu/orbot_main.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* * Copyright (C) 2008 Esmertec AG. * Copyright (C) 2008 The Android Open Source Project @@ -18,77 +17,83 @@ */ --> <menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:yourapp="http://schemas.android.com/apk/res-auto" - > + xmlns:yourapp="http://schemas.android.com/apk/res-auto%22%3E
- <item android:id="@+id/menu_newnym" - android:title="@string/menu_new_identity" + <item + android:id="@+id/menu_newnym" android:icon="@drawable/ic_refresh_white_24dp" - yourapp:showAsAction="always" - /> + android:title="@string/menu_new_identity" + yourapp:showAsAction="always" />
- <item android:id="@+id/menu_settings" + <item + android:id="@+id/menu_settings" + android:icon="@drawable/ic_action_settings" android:title="@string/menu_settings" - android:icon="@drawable/ic_action_settings" - yourapp:showAsAction="never" - /> + yourapp:showAsAction="never" />
- <item + <item android:title="@string/menu_qr" - yourapp:showAsAction="never" - > - <menu> - <item android:id="@+id/menu_scan" - android:title="@string/menu_scan" - yourapp:showAsAction="never" - /> - - <item android:id="@+id/menu_share_bridge" - android:title="@string/menu_share_bridge" - yourapp:showAsAction="never" - /> - </menu> - </item> + yourapp:showAsAction="never"> + <menu> + <item + android:id="@+id/menu_scan" + android:title="@string/menu_scan" + yourapp:showAsAction="never" /> + + <item + android:id="@+id/menu_share_bridge" + android:title="@string/menu_share_bridge" + yourapp:showAsAction="never" /> + </menu> + </item>
<item android:title="@string/menu_hidden_services" yourapp:showAsAction="never"> - <menu> - <item android:id="@+id/menu_hidden_services" - android:title="@string/hosted_services" - yourapp:showAsAction="never" - /> - - <item android:id="@+id/menu_client_cookies" - android:title="@string/client_cookies" - yourapp:showAsAction="never" - /> - </menu> + <menu> + + <item + android:id="@+id/menu_v3_onion_services" + android:title="@string/hidden_services" + yourapp:showAsAction="never" /> + + <item + android:id="@+id/menu_hidden_services" + android:title="@string/hosted_services" + yourapp:showAsAction="never" /> + + <item + android:id="@+id/menu_client_cookies" + android:title="@string/client_cookies" + yourapp:showAsAction="never" /> + </menu> </item> - - <!-- - <item android:id="@+id/menu_promo_apps" - android:title="@string/menu_promo_apps" - android:icon="@drawable/ic_menu_goto" - yourapp:showAsAction="never" - - /> - --> - - <item android:id="@+id/menu_about" + + <!-- + <item android:id="@+id/menu_promo_apps" + android:title="@string/menu_promo_apps" + android:icon="@drawable/ic_menu_goto" + yourapp:showAsAction="never" + + /> + --> + + <item + android:id="@+id/menu_about" + android:icon="@drawable/ic_menu_about" android:title="@string/menu_about" - android:icon="@drawable/ic_menu_about" - yourapp:showAsAction="never" - - /> - - <item android:id="@+id/menu_exit" + yourapp:showAsAction="never" + + /> + + <item + android:id="@+id/menu_exit" + android:icon="@drawable/ic_menu_exit" android:title="@string/menu_exit" - android:icon="@drawable/ic_menu_exit" - yourapp:showAsAction="never" - - /> - + yourapp:showAsAction="never" + + /> + </menu> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c9fc00a6..0501adf8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -101,6 +101,8 @@ <string name="obfsproxy_version">Obfs4proxy: https://github.com/Yawning/obfs4</string> <string name="openssl_version">OpenSSL: http://www.openssl.org</string> <string name="hidden_service_request">An app wants to open onion server port %1$s to the Tor network. This is safe if you trust the app.</string> + <string name="allow">Allow</string> + <string name="deny">Deny</string> <string name="found_existing_tor_process">found existing Tor process…</string> <string name="something_bad_happened">Something bad happened. Check the log</string> <string name="unable_to_read_hidden_service_name">unable to read onion service name</string> diff --git a/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt b/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt index 7e741695..be74aa4e 100644 --- a/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt +++ b/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt @@ -68,9 +68,15 @@ object DiskUtils { @JvmStatic fun getOrCreateLegacyBackupDir(): File? { if (Environment.MEDIA_MOUNTED != Environment.getExternalStorageState()) return null - val dir = File(Environment.getExternalStorageDirectory(), "Orbot") + val dir = File(Environment.getExternalStorageDirectory(), ) return if (!dir.isDirectory && !dir.mkdirs()) null else dir }
+ @JvmStatic + fun recursivelyDeleteDirectory(directory: File) : Boolean { + val contents = directory.listFiles() + contents?.forEach { recursivelyDeleteDirectory(it) } + return directory.delete() + }
} \ No newline at end of file diff --git a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java index 36dcb0ae..10acf5de 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java +++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java @@ -39,7 +39,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.jaredrummler.android.shell.CommandResult;
-import net.freehaven.tor.control.ConfigEntry; import net.freehaven.tor.control.TorControlCommands; import net.freehaven.tor.control.TorControlConnection;
@@ -72,7 +71,6 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Random; import java.util.StringTokenizer; import java.util.concurrent.ExecutorService; @@ -84,14 +82,36 @@ import IPtProxy.IPtProxy; public class OrbotService extends VpnService implements TorServiceConstants, OrbotConstants {
public final static String BINARY_TOR_VERSION = org.torproject.android.binary.TorServiceConstants.BINARY_TOR_VERSION; - private final static int CONTROL_SOCKET_TIMEOUT = 60000; static final int NOTIFY_ID = 1; + private final static int CONTROL_SOCKET_TIMEOUT = 60000; private static final int ERROR_NOTIFY_ID = 3; private static final int HS_NOTIFY_ID = 4; - private static final Uri HS_CONTENT_URI = Uri.parse("content://org.torproject.android.ui.hiddenservices.providers/hs"); + private static final Uri V2_HS_CONTENT_URI = Uri.parse("content://org.torproject.android.ui.hiddenservices.providers/hs"); + private static final Uri V3_ONION_SERVICES_CONTENT_URI = Uri.parse("content://org.torproject.android.ui.v3onionservice/v3"); private static final Uri COOKIE_CONTENT_URI = Uri.parse("content://org.torproject.android.ui.hiddenservices.providers.cookie/cookie"); private final static String NOTIFICATION_CHANNEL_ID = "orbot_channel_1"; - private final static String RESET_STRING = "="""; + private static final String[] LEGACY_V2_ONION_SERVICE_PROJECTION = new String[]{ + OnionService._ID, + OnionService.NAME, + OnionService.DOMAIN, + OnionService.PORT, + OnionService.AUTH_COOKIE, + OnionService.AUTH_COOKIE_VALUE, + OnionService.ONION_PORT, + OnionService.ENABLED}; + private static final String[] V3_ONION_SERVICE_PROJECTION = new String[]{ + OnionService._ID, + OnionService.NAME, + OnionService.DOMAIN, + OnionService.PORT, + OnionService.ONION_PORT, + OnionService.ENABLED, + }; + private static final String[] LEGACY_COOKIE_PROJECTION = new String[]{ + ClientCookie._ID, + ClientCookie.DOMAIN, + ClientCookie.AUTH_COOKIE_VALUE, + ClientCookie.ENABLED}; public static int mPortSOCKS = -1; public static int mPortHTTP = -1; public static int mPortDns = TOR_DNS_PORT_DEFAULT; @@ -100,6 +120,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb public static File appCacheHome; public static File fileTor; public static File fileTorRc; + private final ExecutorService mExecutor = Executors.newCachedThreadPool(); boolean mIsLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; TorEventHandler mEventHandler; OrbotVpnManager mVpnManager; @@ -110,29 +131,12 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb private String mCurrentStatus = STATUS_OFF; private TorControlConnection conn = null; private int mLastProcessId = -1; - private ArrayList<String> configBuffer = null; - private ArrayList<String> resetBuffer = null; private File fileControlPort, filePid; private NotificationManager mNotificationManager = null; private NotificationCompat.Builder mNotifyBuilder; private boolean mNotificationShowing = false; - private final ExecutorService mExecutor = Executors.newCachedThreadPool(); - private File mHSBasePath; + private File mHSBasePath, mV3OnionBasePath; private ArrayList<Bridge> alBridges = null; - private final String[] hsProjection = new String[]{ - HiddenService._ID, - HiddenService.NAME, - HiddenService.DOMAIN, - HiddenService.PORT, - HiddenService.AUTH_COOKIE, - HiddenService.AUTH_COOKIE_VALUE, - HiddenService.ONION_PORT, - HiddenService.ENABLED}; - private final String[] cookieProjection = new String[]{ - ClientCookie._ID, - ClientCookie.DOMAIN, - ClientCookie.AUTH_COOKIE_VALUE, - ClientCookie.ENABLED};
/** * @param bridgeList bridges that were manually entered into Orbot settings @@ -144,13 +148,16 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb return bridgeList.split("\n"); }
- public void debug(String msg) { + private static boolean useIPtProxy() { + String bridgeList = Prefs.getBridgesList(); + return bridgeList.contains("obfs3") || bridgeList.contains("obfs4") || bridgeList.contains("meek"); + }
+ public void debug(String msg) { Log.d(OrbotConstants.TAG, msg);
if (Prefs.useDebugLogging()) { sendCallbackLogMessage(msg); - } }
@@ -264,7 +271,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
public int onStartCommand(Intent intent, int flags, int startId) { - showToolbarNotification("", NOTIFY_ID, R.drawable.ic_stat_tor);
if (intent != null) @@ -347,7 +353,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
/** * if someone stops during startup, we may have to wait for the conn port to be setup, so we can properly shutdown tor - * @throws Exception */ private void stopTorDaemon(boolean waitForConnection) throws Exception {
@@ -372,7 +377,10 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (!waitForConnection) break;
- try { Thread.sleep(3000);}catch (Exception e){} + try { + Thread.sleep(3000); + } catch (Exception e) { + } } }
@@ -384,13 +392,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } catch (IOException e) { e.printStackTrace(); } - /** - // if that fails, try again using native utils - try { - killProcess(fileTor, "-1"); // this is -HUP - } catch (Exception e) { - e.printStackTrace(); - }**/ }
protected void logNotice(String msg) { @@ -439,14 +440,14 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb fileControlPort = new File(getFilesDir(), TOR_CONTROL_PORT_FILE); filePid = new File(getFilesDir(), TOR_PID_FILE);
- mHSBasePath = new File( - getFilesDir().getAbsolutePath(), - TorServiceConstants.HIDDEN_SERVICES_DIR - ); - + mHSBasePath = new File(getFilesDir().getAbsolutePath(), TorServiceConstants.HIDDEN_SERVICES_DIR); if (!mHSBasePath.isDirectory()) mHSBasePath.mkdirs();
+ mV3OnionBasePath = new File(getFilesDir().getAbsolutePath(), TorServiceConstants.ONION_SERVICES_DIR); + if (!mV3OnionBasePath.isDirectory()) + mV3OnionBasePath.mkdirs(); + mEventHandler = new TorEventHandler(this);
if (mNotificationManager == null) { @@ -501,12 +502,12 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
private boolean pluggableTransportInstall() {
- File fileCacheDir = new File(getCacheDir(),"pt"); + File fileCacheDir = new File(getCacheDir(), "pt"); if (!fileCacheDir.exists()) fileCacheDir.mkdir(); IPtProxy.setStateLocation(fileCacheDir.getAbsolutePath()); String fileTestState = IPtProxy.getStateLocation(); - debug ("IPtProxy state: " + fileTestState); + debug("IPtProxy state: " + fileTestState);
return false; } @@ -657,13 +658,10 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (isPortUsed) //the specified port is not available, so let Tor find one instead port++; } - - return port + ""; }
return portString; - }
public boolean updateTorConfigCustom(File fileTorRcCustom, String extraLines) throws IOException, TimeoutException { @@ -710,8 +708,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb * The entire process for starting tor and related services is run from this method. */ private void startTor() { - - try {
// STATUS_STARTING is set in onCreate() @@ -734,9 +730,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb String torProcId = conn.getInfo("process/pid"); if (!TextUtils.isEmpty(torProcId)) mLastProcessId = Integer.parseInt(torProcId); - } - else { - if (fileControlPort!=null && fileControlPort.exists()) + } else { + if (fileControlPort != null && fileControlPort.exists()) findExistingTorDaemon();
} @@ -765,9 +760,14 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
if (success) { try { - updateOnionNames(); + updateLegacyV2OnionNames(); + } catch (SecurityException se) { + logNotice("unable to upload legacy v2 onion names"); + } + try { + updateV3OnionNames(); } catch (SecurityException se) { - logNotice("unable to upload onion names"); + logNotice("unable to upload v3 onion names"); } }
@@ -777,21 +777,48 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb showToolbarNotification( getString(R.string.unable_to_start_tor) + ": " + e.getMessage(), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); + } + }
+ private void updateV3OnionNames() throws SecurityException { + ContentResolver contentResolver = getApplicationContext().getContentResolver(); + Cursor onionServices = contentResolver.query(V3_ONION_SERVICES_CONTENT_URI, null, null, null, null); + if (onionServices != null) { + try { + while (onionServices.moveToNext()) { + String domain = onionServices.getString(onionServices.getColumnIndex(OnionService.DOMAIN)); + int localPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.PORT)); + + if (domain == null || TextUtils.isEmpty(domain)) { + String v3OnionDirPath = new File(mV3OnionBasePath.getAbsolutePath(), "v3" + localPort).getCanonicalPath(); + File hostname = new File(v3OnionDirPath, "hostname"); + if (hostname.exists()) { + domain = Utils.readString(new FileInputStream(hostname)).trim(); + ContentValues fields = new ContentValues(); + fields.put(OnionService.DOMAIN, domain); + contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, fields, "port=" + localPort, null); + } + } + + } + } catch (Exception e) { + e.printStackTrace(); + } + onionServices.close(); } }
- private void updateOnionNames() throws SecurityException { + private void updateLegacyV2OnionNames() throws SecurityException { // Tor is running, update new .onion names at db ContentResolver mCR = getApplicationContext().getContentResolver(); - Cursor hidden_services = mCR.query(HS_CONTENT_URI, hsProjection, null, null, null); + Cursor hidden_services = mCR.query(V2_HS_CONTENT_URI, LEGACY_V2_ONION_SERVICE_PROJECTION, null, null, null); if (hidden_services != null) { try { while (hidden_services.moveToNext()) { - String HSDomain = hidden_services.getString(hidden_services.getColumnIndex(HiddenService.DOMAIN)); - Integer HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(HiddenService.PORT)); - Integer HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(HiddenService.AUTH_COOKIE)); - String HSAuthCookieValue = hidden_services.getString(hidden_services.getColumnIndex(HiddenService.AUTH_COOKIE_VALUE)); + String HSDomain = hidden_services.getString(hidden_services.getColumnIndex(OnionService.DOMAIN)); + Integer HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.PORT)); + Integer HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE)); + String HSAuthCookieValue = hidden_services.getString(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE_VALUE));
// Update only new domains or restored from backup with auth cookie if ((HSDomain == null || HSDomain.length() < 1) || (HSAuthCookie == 1 && (HSAuthCookieValue == null || HSAuthCookieValue.length() < 1))) { @@ -806,10 +833,10 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (HSAuthCookie == 1) { String[] aux = onionHostname.split(" "); onionHostname = aux[0]; - fields.put(HiddenService.AUTH_COOKIE_VALUE, aux[1]); + fields.put(OnionService.AUTH_COOKIE_VALUE, aux[1]); } - fields.put(HiddenService.DOMAIN, onionHostname); - mCR.update(HS_CONTENT_URI, fields, "port=" + HSLocalPort, null); + fields.put(OnionService.DOMAIN, onionHostname); + mCR.update(V2_HS_CONTENT_URI, fields, "port=" + HSLocalPort, null); } catch (FileNotFoundException e) { logException("unable to read onion hostname file", e); showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr); @@ -832,8 +859,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
private boolean runTorShellCmd() throws Exception { - boolean result = true; - File fileTorrcCustom = updateTorrcCustomFile();
//make sure Tor exists and we can execute it @@ -868,9 +893,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb exitCode = exec(torCmdString, false); } catch (Exception e) { logNotice("Tor was unable to start: " + e.getMessage()); - throw new Exception("Tor was unable to start: " + e.getMessage()); - }
if (exitCode != 0) { @@ -885,13 +908,11 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb logNotice(getString(R.string.couldn_t_start_tor_process_) + "; exit=" + exitCode); throw new Exception(getString(R.string.couldn_t_start_tor_process_) + "; exit=" + exitCode); } else { - logNotice("Tor started; process id=" + mLastProcessId); - result = true; } }
- return result; + return true; }
protected void exec(Runnable runn) { @@ -918,23 +939,17 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
while (conn == null && attempt++ < maxTries && (mCurrentStatus != STATUS_OFF)) { try { - controlPort = getControlPort(); - if (controlPort != -1) { logNotice(getString(R.string.connecting_to_control_port) + controlPort); - - break; }
} catch (Exception ce) { conn = null; // logException( "Error connecting to Tor local control port: " + ce.getMessage(),ce); - }
- try { // logNotice("waiting..."); Thread.sleep(2000); @@ -942,27 +957,19 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } }
- if (controlPort != -1) { Socket torConnSocket = new Socket(IP_LOCALHOST, controlPort); torConnSocket.setSoTimeout(CONTROL_SOCKET_TIMEOUT); - conn = new TorControlConnection(torConnSocket); - conn.launchThread(true);//is daemon - }
if (conn != null) { - logNotice("SUCCESS connected to Tor control port.");
File fileCookie = new File(appCacheHome, TOR_CONTROL_COOKIE);
if (fileCookie.exists()) { - - // We extend NullEventHandler so that we don't need to provide empty - // implementations for all the events we don't care about. logNotice("adding control port event handler");
conn.setEventHandler(mEventHandler); @@ -1019,7 +1026,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
sendCallbackPorts(mPortSOCKS, mPortHTTP, mPortDns, mPortTrans); - setTorNetworkEnabled(true);
return Integer.parseInt(torProcId); @@ -1066,20 +1072,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb return result; }
- /** - * Returns the port number that the HTTP proxy is running on - */ - public int getHTTPPort() { - return mPortHTTP; - } - - /** - * Returns the port number that the HTTP proxy is running on - */ - public int getSOCKSPort() { - return mPortSOCKS; - } - public String getInfo(String key) { try { if (conn != null) { @@ -1092,71 +1084,11 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb return null; }
- public String getConfiguration(String name) { - try { - if (conn != null) { - StringBuffer result = new StringBuffer(); - - List<ConfigEntry> listCe = conn.getConf(name); - - Iterator<ConfigEntry> itCe = listCe.iterator(); - ConfigEntry ce; - - - while (itCe.hasNext()) { - ce = itCe.next(); - - result.append(ce.key); - result.append(' '); - result.append(ce.value); - result.append('\n'); - } - - return result.toString(); - } - } catch (Exception ioe) { - - logException("Unable to get Tor configuration: " + ioe.getMessage(), ioe); - } - - return null; - } - - /** - * Set configuration - **/ - public boolean updateConfiguration(String name, String value, boolean saveToDisk) { - - - if (configBuffer == null) - configBuffer = new ArrayList<>(); - - if (resetBuffer == null) - resetBuffer = new ArrayList<>(); - - if (value == null || value.length() == 0) { - resetBuffer.add(name + RESET_STRING); - - } else { - - String sbConf = name + - ' ' + - value; - configBuffer.add(sbConf); - } - - return false; - } - - public void setTorNetworkEnabled(final boolean isEnabled) throws IOException { - - //it is possible to not have a connection yet, and someone might try to newnym - if (conn != null) { + if (conn != null) { // it is possible to not have a connection yet, and someone might try to newnym new Thread() { public void run() { try { - final String newValue = isEnabled ? "0" : "1"; conn.setConf("DisableNetwork", newValue); } catch (Exception ioe) { @@ -1165,7 +1097,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } }.start(); } - }
public void sendSignalActive() { @@ -1179,8 +1110,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
public void newIdentity() { - //it is possible to not have a connection yet, and someone might try to newnym - if (conn != null) { + if (conn != null) { // it is possible to not have a connection yet, and someone might try to newnym new Thread() { public void run() { try { @@ -1199,49 +1129,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } }
- public boolean saveConfiguration() { - try { - if (conn != null) { - - if (resetBuffer != null && resetBuffer.size() > 0) { - for (String value : configBuffer) { - - // debug("removing torrc conf: " + value); - - - } - - // conn.resetConf(resetBuffer); - resetBuffer = null; - } - - if (configBuffer != null && configBuffer.size() > 0) { - - for (String value : configBuffer) { - - debug("Setting torrc conf: " + value); - - - } - - conn.setConf(configBuffer); - - configBuffer = null; - } - - // Flush the configuration to disk. - //this is doing bad things right now NF 22/07/10 - //conn.saveConf(); - - return true; - } - } catch (Exception ioe) { - logException("Unable to update Tor configuration: " + ioe.getMessage(), ioe); - } - - return false; - } - protected void sendCallbackBandwidth(long upload, long download, long written, long read) { Intent intent = new Intent(LOCAL_ACTION_BANDWIDTH);
@@ -1255,11 +1142,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
private void sendCallbackLogMessage(final String logMessage) { - mHandler.post(() -> { - - Intent intent = new Intent(LOCAL_ACTION_LOG); - // You can also include some extra data. + Intent intent = new Intent(LOCAL_ACTION_LOG); // You can also include some extra data. intent.putExtra(LOCAL_EXTRA_LOG, logMessage); intent.putExtra(EXTRA_STATUS, mCurrentStatus);
@@ -1269,9 +1153,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
private void sendCallbackPorts(int socksPort, int httpPort, int dnsPort, int transPort) { - - Intent intent = new Intent(LOCAL_ACTION_PORTS); - // You can also include some extra data. + Intent intent = new Intent(LOCAL_ACTION_PORTS); // You can also include some extra data. intent.putExtra(EXTRA_SOCKS_PROXY_PORT, socksPort); intent.putExtra(EXTRA_HTTP_PROXY_PORT, httpPort); intent.putExtra(EXTRA_DNS_PORT, dnsPort); @@ -1355,26 +1237,19 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
private StringBuffer processSettingsImpl(StringBuffer extraLines) throws IOException { logNotice(getString(R.string.updating_settings_in_tor_service)); - SharedPreferences prefs = Prefs.getSharedPrefs(getApplicationContext());
boolean useBridges = Prefs.bridgesEnabled(); - boolean becomeRelay = prefs.getBoolean(OrbotConstants.PREF_OR, false); boolean ReachableAddresses = prefs.getBoolean(OrbotConstants.PREF_REACHABLE_ADDRESSES, false); - boolean enableStrictNodes = prefs.getBoolean("pref_strict_nodes", false); String entranceNodes = prefs.getString("pref_entrance_nodes", ""); String exitNodes = prefs.getString("pref_exit_nodes", ""); String excludeNodes = prefs.getString("pref_exclude_nodes", "");
if (!useBridges) { - extraLines.append("UseBridges 0").append('\n'); - - if (Prefs.useVpn()) //set the proxy here if we aren't using a bridge - { - + if (Prefs.useVpn()) { //set the proxy here if we aren't using a bridge if (!mIsLollipop) { String proxyType = "socks5"; extraLines.append(proxyType + "Proxy" + ' ' + OrbotVpnManager.sSocksProxyLocalhost + ':' + OrbotVpnManager.sSocksProxyServerPort).append('\n'); @@ -1400,15 +1275,12 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
} else if (proxyPass != null) extraLines.append(proxyType + "ProxyAuthenticator" + ' ' + proxyUser + ':' + proxyPort).append('\n'); - - } } } } else {
loadBridgeDefaults(); - extraLines.append("UseBridges 1").append('\n'); // extraLines.append("UpdateBridgesFromAuthority 1").append('\n');
@@ -1445,12 +1317,9 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb extraLines.append("Bridge "); extraLines.append(bridgeLine); extraLines.append("\n"); - } - }
- //only apply GeoIP if you need it File fileGeoIP = new File(appBinHome, GEOIP_ASSET_KEY); File fileGeoIP6 = new File(appBinHome, GEOIP6_ASSET_KEY); @@ -1473,16 +1342,12 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
try { if (ReachableAddresses) { - String ReachableAddressesPorts = - prefs.getString(OrbotConstants.PREF_REACHABLE_ADDRESSES_PORTS, "*:80,*:443"); - + String ReachableAddressesPorts = prefs.getString(OrbotConstants.PREF_REACHABLE_ADDRESSES_PORTS, "*:80,*:443"); extraLines.append("ReachableAddresses" + ' ' + ReachableAddressesPorts).append('\n'); - }
} catch (Exception e) { showToolbarNotification(getString(R.string.your_reachableaddresses_settings_caused_an_exception_), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); - return null; }
@@ -1490,7 +1355,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (becomeRelay && (!useBridges) && (!ReachableAddresses)) { int ORPort = Integer.parseInt(prefs.getString(OrbotConstants.PREF_OR_PORT, "9001")); String nickname = prefs.getString(OrbotConstants.PREF_OR_NICKNAME, "Orbot"); - String dnsFile = writeDNSFile();
extraLines.append("ServerDNSResolvConfFile" + ' ' + dnsFile).append('\n'); @@ -1501,33 +1365,56 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } } catch (Exception e) { showToolbarNotification(getString(R.string.your_relay_settings_caused_an_exception_), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); - - return null; }
- ContentResolver mCR = getApplicationContext().getContentResolver(); + ContentResolver contentResolver = getApplicationContext().getContentResolver(); + addV3OnionServicesToTorrc(extraLines, contentResolver); +// addV2HiddenServicesToTorrc(extraLines, contentResolver); +// addV2ClientCookiesToTorrc(extraLines, contentResolver); + return extraLines; + }
+ private void addV3OnionServicesToTorrc(StringBuffer torrc, ContentResolver contentResolver) { try { - /* ---- Hidden Services ---- */ - Cursor hidden_services = mCR.query(HS_CONTENT_URI, hsProjection, HiddenService.ENABLED + "=1", null, null); + Cursor onionServices = contentResolver.query(V3_ONION_SERVICES_CONTENT_URI, V3_ONION_SERVICE_PROJECTION, OnionService.ENABLED + "=1", null, null); + if (onionServices != null) { + while (onionServices.moveToNext()) { + int localPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.PORT)); + int onionPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.ONION_PORT)); + String v3DirPath = new File(mV3OnionBasePath.getAbsolutePath(), "v3" + localPort).getCanonicalPath(); + torrc.append("HiddenServiceDir ").append(v3DirPath).append("\n"); + torrc.append("HiddenServiceVersion 3").append("\n"); + torrc.append("HiddenServicePort ").append(onionPort).append(" 127.0.0.1:").append(localPort).append("\n"); + } + onionServices.close(); + } + } catch (Exception e) { + Log.e(TAG, e.getLocalizedMessage()); + } + } + + // todo needs modifications to set hidden service version back after doing v3 stuff... + private void addV2HiddenServicesToTorrc(StringBuffer torrc, ContentResolver contentResolver) { + try { + Cursor hidden_services = contentResolver.query(V2_HS_CONTENT_URI, LEGACY_V2_ONION_SERVICE_PROJECTION, OnionService.ENABLED + "=1", null, null); if (hidden_services != null) { try { while (hidden_services.moveToNext()) { - String HSname = hidden_services.getString(hidden_services.getColumnIndex(HiddenService.NAME)); - Integer HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(HiddenService.PORT)); - Integer HSOnionPort = hidden_services.getInt(hidden_services.getColumnIndex(HiddenService.ONION_PORT)); - Integer HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(HiddenService.AUTH_COOKIE)); + String HSname = hidden_services.getString(hidden_services.getColumnIndex(OnionService.NAME)); + int HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.PORT)); + int HSOnionPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.ONION_PORT)); + int HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE)); String hsDirPath = new File(mHSBasePath.getAbsolutePath(), "hs" + HSLocalPort).getCanonicalPath();
debug("Adding hidden service on port: " + HSLocalPort);
- extraLines.append("HiddenServiceDir" + ' ' + hsDirPath).append('\n'); - extraLines.append("HiddenServicePort" + ' ' + HSOnionPort + " 127.0.0.1:" + HSLocalPort).append('\n'); - extraLines.append("HiddenServiceVersion 2").append('\n'); + torrc.append("HiddenServiceDir" + ' ' + hsDirPath).append('\n'); + torrc.append("HiddenServicePort" + ' ' + HSOnionPort + " 127.0.0.1:" + HSLocalPort).append('\n'); + torrc.append("HiddenServiceVersion 2").append('\n');
if (HSAuthCookie == 1) - extraLines.append("HiddenServiceAuthorizeClient stealth " + HSname).append('\n'); + torrc.append("HiddenServiceAuthorizeClient stealth " + HSname).append('\n'); } } catch (NumberFormatException e) { Log.e(OrbotConstants.TAG, "error parsing hsport", e); @@ -1539,28 +1426,25 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } } catch (SecurityException se) { } + }
+ private void addV2ClientCookiesToTorrc(StringBuffer torrc, ContentResolver contentResolver) { try { - - /* ---- Client Cookies ---- */ - Cursor client_cookies = mCR.query(COOKIE_CONTENT_URI, cookieProjection, ClientCookie.ENABLED + "=1", null, null); + Cursor client_cookies = contentResolver.query(COOKIE_CONTENT_URI, LEGACY_COOKIE_PROJECTION, ClientCookie.ENABLED + "=1", null, null); if (client_cookies != null) { try { while (client_cookies.moveToNext()) { String domain = client_cookies.getString(client_cookies.getColumnIndex(ClientCookie.DOMAIN)); String cookie = client_cookies.getString(client_cookies.getColumnIndex(ClientCookie.AUTH_COOKIE_VALUE)); - extraLines.append("HidServAuth" + ' ' + domain + ' ' + cookie).append('\n'); + torrc.append("HidServAuth" + ' ' + domain + ' ' + cookie).append('\n'); } } catch (Exception e) { Log.e(OrbotConstants.TAG, "error starting share server", e); } - client_cookies.close(); } } catch (SecurityException se) { } - - return extraLines; }
//using Google DNS for now as the public DNS server @@ -1614,7 +1498,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind"); - //do nothing here return super.onBind(intent); // invoking super class will call onRevoke() when appropriate }
@@ -1676,8 +1559,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb alBridges = new ArrayList<>();
try { - BufferedReader in = - new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.bridges), "UTF-8")); + BufferedReader in = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.bridges), "UTF-8")); String str;
while ((str = in.readLine()) != null) { @@ -1692,9 +1574,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb sbConfig.append(st.nextToken()).append(' ');
b.config = sbConfig.toString().trim(); - alBridges.add(b); - }
in.close(); @@ -1702,7 +1582,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb e.printStackTrace(); } } - }
private void getBridges(String type, StringBuffer extraLines) { @@ -1728,20 +1607,18 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb break; } } - }
- public static final class HiddenService implements BaseColumns { + public static final class OnionService implements BaseColumns { public static final String NAME = "name"; public static final String PORT = "port"; public static final String ONION_PORT = "onion_port"; public static final String DOMAIN = "domain"; public static final String AUTH_COOKIE = "auth_cookie"; public static final String AUTH_COOKIE_VALUE = "auth_cookie_value"; - public static final String CREATED_BY_USER = "created_by_user"; public static final String ENABLED = "enabled";
- private HiddenService() { + private OnionService() { } }
@@ -1768,7 +1645,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb }
public void run() { - String action = mIntent.getAction();
if (!TextUtils.isEmpty(action)) { @@ -1804,11 +1680,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (mVpnManager != null && (!mVpnManager.isStarted())) { //start VPN here Intent vpnIntent = VpnService.prepare(OrbotService.this); - if (vpnIntent == null) //then we can run the VPN - { + if (vpnIntent == null) { //then we can run the VPN mVpnManager.handleIntent(new Builder(), mIntent); - - } }
@@ -1828,9 +1701,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } else if (action.equals(CMD_ACTIVE)) { sendSignalActive(); } else if (action.equals(CMD_SET_EXIT)) { - setExitNode(mIntent.getStringExtra("exit")); - } else { Log.w(OrbotConstants.TAG, "unhandled OrbotService Intent: " + action); } @@ -1852,5 +1723,4 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } } } - } diff --git a/orbotservice/src/main/java/org/torproject/android/service/TorServiceConstants.java b/orbotservice/src/main/java/org/torproject/android/service/TorServiceConstants.java index f1769687..915f149d 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/TorServiceConstants.java +++ b/orbotservice/src/main/java/org/torproject/android/service/TorServiceConstants.java @@ -112,6 +112,6 @@ public interface TorServiceConstants { String OBFSCLIENT_ASSET_KEY = "obfs4proxy";
String HIDDEN_SERVICES_DIR = "hidden_services"; - + String ONION_SERVICES_DIR = "v3_onion_services";
}
tor-commits@lists.torproject.org