tor-commits
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2021
- 15 participants
- 1465 discussions
[orbot/master] small bug where 'snowflake' can appear in a field to paste custom bridge config
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit 5bf2ba8941740b836d38eb801259d23c014096dd
Author: bim <dsnake(a)protonmail.com>
Date: Wed Feb 3 10:43:02 2021 -0500
small bug where 'snowflake' can appear in a field to paste custom bridge config
---
.../torproject/android/ui/onboarding/CustomBridgesActivity.java | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
index f34a49cc..6d7817df 100644
--- a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
@@ -80,7 +80,7 @@ public class CustomBridgesActivity extends AppCompatActivity implements View.OnC
findViewById(R.id.btCopyUrl).setOnClickListener(this);
String bridges = Prefs.getBridgesList().trim();
- if (!Prefs.bridgesEnabled() || bridges.equals("obfs4") || bridges.equals("meek")) {
+ if (!Prefs.bridgesEnabled() || userHasSetPreconfiguredBridge(bridges)) {
bridges = null;
}
@@ -90,9 +90,7 @@ public class CustomBridgesActivity extends AppCompatActivity implements View.OnC
mEtPastedBridges.addTextChangedListener(this);
findViewById(R.id.btScanQr).setOnClickListener(this);
-
findViewById(R.id.btShareQr).setOnClickListener(this);
-
findViewById(R.id.btEmail).setOnClickListener(this);
}
@@ -224,4 +222,9 @@ public class CustomBridgesActivity extends AppCompatActivity implements View.OnC
intent.setAction(TorServiceConstants.CMD_SIGNAL_HUP);
startService(intent);
}
+
+ private static boolean userHasSetPreconfiguredBridge(String bridges) {
+ if (bridges == null) return false;
+ return bridges.equals("obfs4") || bridges.equals("meek") || bridges.equals("snowflake");
+ }
}
1
0
commit 85dba3bf440f68ba1036dda596f4adceea1b5d94
Author: bim <dsnake(a)protonmail.com>
Date: Sat Nov 28 12:46:28 2020 -0500
Battery permissions on v3 services
---
.../android/ui/v3onionservice/OnionServicesActivity.java | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
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
index ba06b7c0..64a014e4 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
@@ -26,6 +26,7 @@ import org.torproject.android.core.DiskUtils;
import org.torproject.android.core.LocaleHelper;
import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
import org.torproject.android.ui.hiddenservices.backup.ZipUtilities;
+import org.torproject.android.ui.hiddenservices.permissions.PermissionManager;
import java.io.File;
@@ -161,8 +162,16 @@ public class OnionServicesActivity extends AppCompatActivity {
@Override
public void onChange(boolean selfChange) {
- mAdapter.changeCursor(mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, BASE_WHERE_SELECTION_CLAUSE + '1', null, null));
- // todo battery optimization stuff if lollipop or higher and running onion services
+ filterServices(radioShowUserServices.isChecked()); // updates adapter
+ if (!PermissionManager.isLollipopOrHigher()) return;
+ Cursor activeServices = mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION,
+ OnionServiceContentProvider.OnionService.ENABLED + "=1", null, null);
+ if (activeServices == null) return;
+ if (activeServices.getCount() > 0)
+ PermissionManager.requestBatteryPermissions(OnionServicesActivity.this, getApplicationContext());
+ else
+ PermissionManager.requestDropBatteryPermissions(OnionServicesActivity.this, getApplicationContext());
+ activeServices.close();
}
}
1
0
[orbot/master] altered code that will break with gradle 5 (resource IDs will be declared non-final in Java)
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit fe69a3156a4ea5e9e1af38e32eb881b51c436d71
Author: bim <dsnake(a)protonmail.com>
Date: Wed Feb 3 11:45:51 2021 -0500
altered code that will break with gradle 5 (resource IDs will be declared non-final in Java)
---
.../ui/hiddenservices/HiddenServicesActivity.java | 13 ++---
.../ui/onboarding/CustomBridgesActivity.java | 66 +++++++---------------
2 files changed, 24 insertions(+), 55 deletions(-)
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 62b3613b..6c780dde 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
@@ -166,15 +166,10 @@ public class HiddenServicesActivity extends AppCompatActivity {
}
public void onRadioButtonClick(View view) {
- switch (view.getId()) {
- case R.id.radioUserServices:
- filterServices(true);
- break;
- case R.id.radioAppServices:
- filterServices(false);
- break;
- default:
- break;
+ if (view.getId() == R.id.radioUserServices) {
+ filterServices(true);
+ } else if (view.getId() == R.id.radioAppServices) {
+ filterServices(false);
}
}
diff --git a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
index a8eeb30f..6fce9852 100644
--- a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
@@ -40,7 +40,7 @@ import java.net.URLEncoder;
import static org.torproject.android.MainConstants.EMAIL_TOR_BRIDGES;
import static org.torproject.android.MainConstants.URL_TOR_BRIDGES;
-public class CustomBridgesActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
+public class CustomBridgesActivity extends AppCompatActivity implements TextWatcher {
private EditText mEtPastedBridges;
@@ -75,7 +75,7 @@ public class CustomBridgesActivity extends AppCompatActivity implements View.OnC
((TextView) findViewById(R.id.tvDescription)).setText(getString(R.string.in_a_browser, URL_TOR_BRIDGES));
- findViewById(R.id.btCopyUrl).setOnClickListener(this);
+ findViewById(R.id.btCopyUrl).setOnClickListener(v -> ClipboardUtils.copyToClipboard("bridge_url", URL_TOR_BRIDGES, getString(R.string.done), this));
String bridges = Prefs.getBridgesList().trim();
if (!Prefs.bridgesEnabled() || userHasSetPreconfiguredBridge(bridges)) {
@@ -86,62 +86,36 @@ public class CustomBridgesActivity extends AppCompatActivity implements View.OnC
configureMultilineEditTextInScrollView(mEtPastedBridges);
mEtPastedBridges.setText(bridges);
mEtPastedBridges.addTextChangedListener(this);
+ final IntentIntegrator integrator = new IntentIntegrator(this);
- findViewById(R.id.btScanQr).setOnClickListener(this);
- findViewById(R.id.btShareQr).setOnClickListener(this);
- findViewById(R.id.btEmail).setOnClickListener(this);
+ findViewById(R.id.btScanQr).setOnClickListener(v -> integrator.initiateScan());
+ findViewById(R.id.btShareQr).setOnClickListener(v -> {
+ String setBridges = Prefs.getBridgesList();
+ if (!TextUtils.isEmpty(setBridges)) {
+ try {
+ integrator.shareText("bridge://" + URLEncoder.encode(setBridges, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ findViewById(R.id.btEmail).setOnClickListener(v -> {
+ Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + EMAIL_TOR_BRIDGES));
+ emailIntent.putExtra(Intent.EXTRA_SUBJECT, "get transport");
+ emailIntent.putExtra(Intent.EXTRA_TEXT, "get transport");
+ startActivity(Intent.createChooser(emailIntent, getString(R.string.send_email)));
+ });
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
-
return true;
}
-
return super.onOptionsItemSelected(item);
}
- @Override
- public void onClick(View view) {
- IntentIntegrator integrator = new IntentIntegrator(this);
-
- switch (view.getId()) {
- case R.id.btCopyUrl:
- ClipboardUtils.copyToClipboard("bridge_url", URL_TOR_BRIDGES, getString(R.string.done), this);
- break;
-
- case R.id.btScanQr:
- integrator.initiateScan();
- break;
-
- case R.id.btShareQr:
- String bridges = Prefs.getBridgesList();
-
- if (!TextUtils.isEmpty(bridges)) {
- try {
- bridges = "bridge://" + URLEncoder.encode(bridges, "UTF-8");
-
- integrator.shareText(bridges);
-
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
-
- break;
-
- case R.id.btEmail:
- Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + EMAIL_TOR_BRIDGES));
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, "get transport");
- emailIntent.putExtra(Intent.EXTRA_TEXT, "get transport");
- startActivity(Intent.createChooser(emailIntent, getString(R.string.send_email)));
-
- break;
- }
- }
-
@Override
protected void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
1
0
commit 7ce301042cd9a56155b764f1e18f7396bc21b8fc
Author: bim <dsnake(a)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">
- <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";
}
1
0
[orbot/master] V3 UI Cleanup, Deprecated Stuff Under Menu + filtering of v3 user/app services
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit ec11d9db387c19c7ca6b385d44a5fcc1fed79659
Author: bim <dsnake(a)protonmail.com>
Date: Sat Nov 28 12:35:03 2020 -0500
V3 UI Cleanup, Deprecated Stuff Under Menu + filtering of v3 user/app services
---
.../ui/hiddenservices/HiddenServicesActivity.java | 14 +++--
.../ui/hiddenservices/backup/BackupUtils.java | 30 ++++-------
.../backup/{ZipIt.java => ZipUtilities.java} | 14 +++--
.../ui/v3onionservice/OnionServicesActivity.java | 52 ++++++++++++++++---
app/src/main/res/menu/orbot_main.xml | 59 +++++++---------------
app/src/main/res/values/strings.xml | 1 +
.../java/org/torproject/android/core/DiskUtils.kt | 1 -
7 files changed, 89 insertions(+), 82 deletions(-)
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 886bd27d..7436eb91 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
@@ -25,6 +25,7 @@ import org.torproject.android.core.DiskUtils;
import org.torproject.android.core.LocaleHelper;
import org.torproject.android.ui.hiddenservices.adapters.OnionListAdapter;
import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
+import org.torproject.android.ui.hiddenservices.backup.ZipUtilities;
import org.torproject.android.ui.hiddenservices.dialogs.HSActionsDialog;
import org.torproject.android.ui.hiddenservices.dialogs.HSDataDialog;
import org.torproject.android.ui.hiddenservices.permissions.PermissionManager;
@@ -43,7 +44,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
private static final String BUNDLE_KEY_SHOW_USER_SERVICES = "show_user_services";
private ContentResolver mResolver;
private OnionListAdapter mAdapter;
- private RadioButton radioShowUserServices, radioShowAppServices;
+ private RadioButton radioShowUserServices;
private FloatingActionButton fab;
private String mWhere = HSContentProvider.HiddenService.CREATED_BY_USER + "=1";
@@ -52,7 +53,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_hs_list_view);
radioShowUserServices = findViewById(R.id.radioUserServices);
- radioShowAppServices = findViewById(R.id.radioAppServices);
+ RadioButton radioShowAppServices = findViewById(R.id.radioAppServices);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -61,7 +62,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
mResolver = getContentResolver();
fab = findViewById(R.id.fab);
- fab.setOnClickListener(view -> new HSDataDialog().show(getSupportFragmentManager(), "HSDataDialog"));
+ fab.setOnClickListener(view -> new HSDataDialog().show(getSupportFragmentManager(), HSDataDialog.class.getSimpleName()));
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()));
@@ -108,7 +109,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
private void doRestoreLegacy() { // API 16, 17, 18
File backupDir = DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name));
- File[] files = backupDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
+ File[] files = backupDir.listFiles(ZipUtilities.FILTER_ZIP_FILES);
if (files != null) {
if (files.length == 0) {
Toast.makeText(this, R.string.create_a_backup_first, Toast.LENGTH_LONG).show();
@@ -140,7 +141,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_restore_backup) {
if (DiskUtils.supportsStorageAccessFramework()) {
- Intent readFile = DiskUtils.createReadFileIntent("application/zip");
+ Intent readFile = DiskUtils.createReadFileIntent(ZipUtilities.ZIP_MIME_TYPE);
startActivityForResult(readFile, REQUEST_CODE_READ_ZIP_BACKUP);
} else { // API 16, 17, 18
doRestoreLegacy();
@@ -177,12 +178,9 @@ public class HiddenServicesActivity extends AppCompatActivity {
@Override
public void onChange(boolean selfChange) {
mAdapter.changeCursor(mResolver.query(HSContentProvider.CONTENT_URI, HSContentProvider.PROJECTION, mWhere, null, null));
-
if (!PermissionManager.isLollipopOrHigher()) return;
Cursor active = mResolver.query(HSContentProvider.CONTENT_URI, HSContentProvider.PROJECTION, HSContentProvider.HiddenService.ENABLED + "=1", null, null);
-
if (active == null) return;
-
if (active.getCount() > 0) // Call only if there running services
PermissionManager.requestBatteryPermissions(HiddenServicesActivity.this, getApplicationContext());
else // Drop whe not needed
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
index e81f73a9..1dbad3cb 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
@@ -30,8 +30,8 @@ import java.nio.charset.Charset;
public class BackupUtils {
private static final String configFileName = "config.json";
- private Context mContext;
- private ContentResolver mResolver;
+ private final Context mContext;
+ private final ContentResolver mResolver;
public BackupUtils(Context context) {
mContext = context;
@@ -44,14 +44,14 @@ public class BackupUtils {
public String createV3ZipBackup(String port, Uri zipFile) {
String[] files = createFilesForZippingV3(port);
- ZipIt zip = new ZipIt(files, zipFile, mResolver);
+ ZipUtilities zip = new ZipUtilities(files, zipFile, mResolver);
if (!zip.zip()) return null;
return zipFile.getPath();
}
public String createV2ZipBackup(int port, Uri zipFile) {
String[] files = createFilesForZippingV2(port);
- ZipIt zip = new ZipIt(files, zipFile, mResolver);
+ ZipUtilities zip = new ZipUtilities(files, zipFile, mResolver);
if (!zip.zip())
return null;
@@ -84,17 +84,12 @@ public class BackupUtils {
config.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.CREATED_BY_USER)));
config.put(OnionServiceContentProvider.OnionService.ENABLED, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.ENABLED)));
- } catch (JSONException jsone) {
- jsone.printStackTrace();
- return null;
- }
- portData.close();
+ portData.close();
- try {
FileWriter fileWriter = new FileWriter(configFilePath);
fileWriter.write(config.toString());
fileWriter.close();
- } catch (IOException ioe) {
+ } catch (JSONException | IOException ioe) {
ioe.printStackTrace();
return null;
}
@@ -131,10 +126,7 @@ public class BackupUtils {
config.put(HSContentProvider.HiddenService.AUTH_COOKIE_VALUE, portData.getString(portData.getColumnIndex(HSContentProvider.HiddenService.AUTH_COOKIE_VALUE)));
config.put(HSContentProvider.HiddenService.CREATED_BY_USER, portData.getInt(portData.getColumnIndex(HSContentProvider.HiddenService.CREATED_BY_USER)));
config.put(HSContentProvider.HiddenService.ENABLED, portData.getInt(portData.getColumnIndex(HSContentProvider.HiddenService.ENABLED)));
- } catch (JSONException e) {
- e.printStackTrace();
- return null;
- } catch (NullPointerException e) {
+ } catch (JSONException | NullPointerException e) {
e.printStackTrace();
return null;
}
@@ -261,7 +253,7 @@ public class BackupUtils {
public void restoreZipBackupV2Legacy(File zipFile) {
String backupName = zipFile.getName();
- ZipIt zip = new ZipIt(null, null, mResolver);
+ ZipUtilities zip = new ZipUtilities(null, null, mResolver);
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
File hsPath = new File(getHSBasePath().getAbsolutePath(), hsDir);
if (zip.unzipLegacy(hsPath.getAbsolutePath(), zipFile))
@@ -272,7 +264,7 @@ public class BackupUtils {
public void restoreZipBackupV3Legacy(File zipFile) {
String backupName = zipFile.getName();
- ZipIt zip = new ZipIt(null, null, mResolver);
+ ZipUtilities zip = new ZipUtilities(null, null, mResolver);
String v3Dir = backupName.substring(0, backupName.lastIndexOf('.'));
File v3Path = new File(getV3BasePath().getAbsolutePath(), v3Dir);
if (zip.unzipLegacy(v3Path.getAbsolutePath(), zipFile))
@@ -291,7 +283,7 @@ public class BackupUtils {
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
File hsPath = new File(getHSBasePath().getAbsolutePath(), hsDir);
- if (new ZipIt(null, zipUri, mResolver).unzip(hsPath.getAbsolutePath()))
+ if (new ZipUtilities(null, zipUri, mResolver).unzip(hsPath.getAbsolutePath()))
extractConfigFromUnzippedBackupV2(backupName);
else
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
@@ -306,7 +298,7 @@ public class BackupUtils {
String v3Dir = backupName.substring(0, backupName.lastIndexOf('.'));
File v3Paath = new File(getV3BasePath().getAbsolutePath(), v3Dir);
- if (new ZipIt(null, zipUri, mResolver).unzip(v3Paath.getAbsolutePath()))
+ if (new ZipUtilities(null, zipUri, mResolver).unzip(v3Paath.getAbsolutePath()))
extractConfigFromUnzippedBackupV3(backupName);
else
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipUtilities.java
similarity index 88%
rename from app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java
rename to app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipUtilities.java
index 5c264b8e..11fd1743 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipIt.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/ZipUtilities.java
@@ -10,22 +10,26 @@ import androidx.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-public class ZipIt {
+public class ZipUtilities {
private static final int BUFFER = 2048;
+ public static final String ZIP_MIME_TYPE = "application/zip";
+ public static final FilenameFilter FILTER_ZIP_FILES = (dir, name) -> name.toLowerCase().endsWith(".zip");
- private String[] files;
- private Uri zipFile;
- private ContentResolver contentResolver;
+ private final String[] files;
+ private final Uri zipFile;
+ private final ContentResolver contentResolver;
- public ZipIt(@Nullable String[] files, @NonNull Uri zipFile, @NonNull ContentResolver contentResolver) {
+ public ZipUtilities(@Nullable String[] files, @NonNull Uri zipFile, @NonNull ContentResolver contentResolver) {
this.files = files;
this.zipFile = zipFile;
this.contentResolver = contentResolver;
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
index a51ef37c..ba06b7c0 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
@@ -9,10 +9,12 @@ import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.View;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
@@ -23,15 +25,17 @@ import org.torproject.android.R;
import org.torproject.android.core.DiskUtils;
import org.torproject.android.core.LocaleHelper;
import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
+import org.torproject.android.ui.hiddenservices.backup.ZipUtilities;
import java.io.File;
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 static final String BASE_WHERE_SELECTION_CLAUSE = OnionServiceContentProvider.OnionService.CREATED_BY_USER + "=";
+ private static final String BUNDLE_KEY_SHOW_USER_SERVICES = "show_user_key";
private static final int REQUEST_CODE_READ_ZIP_BACKUP = 347;
- private RadioButton radioShowUserServices, radioShowAppServices;
+ private RadioButton radioShowUserServices;
private FloatingActionButton fab;
private ContentResolver mContentResolver;
private OnionV3ListAdapter mAdapter;
@@ -46,13 +50,20 @@ public class OnionServicesActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
fab = findViewById(R.id.fab);
- fab.setOnClickListener(v -> new NewOnionServiceDialogFragment().show(getSupportFragmentManager(), "NewOnionServiceDialogFragment"));
+ fab.setOnClickListener(v -> new NewOnionServiceDialogFragment().show(getSupportFragmentManager(), NewOnionServiceDialogFragment.class.getSimpleName()));
mContentResolver = getContentResolver();
- mAdapter = new OnionV3ListAdapter(this, mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, WHERE_SELECTION_CLAUSE, null, null), 0);
+ mAdapter = new OnionV3ListAdapter(this, mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, BASE_WHERE_SELECTION_CLAUSE + '1', null, null), 0);
mContentResolver.registerContentObserver(OnionServiceContentProvider.CONTENT_URI, true, new OnionServiceObserver(new Handler()));
ListView onionList = findViewById(R.id.onion_list);
+
+ radioShowUserServices = findViewById(R.id.radioUserServices);
+ RadioButton radioShowAppServices = findViewById(R.id.radioAppServices);
+ boolean showUserServices = radioShowAppServices.isChecked() || bundle == null || bundle.getBoolean(BUNDLE_KEY_SHOW_USER_SERVICES, false);
+ if (showUserServices) radioShowUserServices.setChecked(true);
+ else radioShowAppServices.setChecked(true);
+ filterServices(showUserServices);
onionList.setAdapter(mAdapter);
onionList.setOnItemClickListener((parent, view, position, id) -> {
Cursor item = (Cursor) parent.getItemAtPosition(position);
@@ -65,6 +76,19 @@ public class OnionServicesActivity extends AppCompatActivity {
});
}
+ private void filterServices(boolean showUserServices) {
+ String predicate;
+ if (showUserServices) {
+ predicate = "1";
+ fab.show();
+ } else {
+ predicate = "0";
+ fab.hide();
+ }
+ mAdapter.changeCursor(mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION,
+ BASE_WHERE_SELECTION_CLAUSE + predicate, null, null));
+ }
+
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleHelper.onAttach(base));
@@ -76,11 +100,17 @@ public class OnionServicesActivity extends AppCompatActivity {
return true;
}
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle icicle) {
+ super.onSaveInstanceState(icicle);
+ icicle.putBoolean(BUNDLE_KEY_SHOW_USER_SERVICES, radioShowUserServices.isChecked());
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_restore_backup) {
if (DiskUtils.supportsStorageAccessFramework()) {
- Intent readFileIntent = DiskUtils.createReadFileIntent("application/zip");
+ Intent readFileIntent = DiskUtils.createReadFileIntent(ZipUtilities.ZIP_MIME_TYPE);
startActivityForResult(readFileIntent, REQUEST_CODE_READ_ZIP_BACKUP);
} else { // APIs 16, 17, 18
doRestoreLegacy();
@@ -91,7 +121,7 @@ public class OnionServicesActivity extends AppCompatActivity {
private void doRestoreLegacy() { // APIs 16, 17, 18
File backupDir = DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name));
- File[] files = backupDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
+ File[] files = backupDir.listFiles(ZipUtilities.FILTER_ZIP_FILES);
if (files == null) return;
if (files.length == 0) {
Toast.makeText(this, R.string.create_a_backup_first, Toast.LENGTH_LONG).show();
@@ -115,6 +145,14 @@ public class OnionServicesActivity extends AppCompatActivity {
}
}
+ public void onRadioButtonClick(View view) {
+ int id = view.getId();
+ if (id == R.id.radioUserServices)
+ filterServices(true);
+ else if (id == R.id.radioAppServices)
+ filterServices(false);
+ }
+
private class OnionServiceObserver extends ContentObserver {
OnionServiceObserver(Handler handler) {
@@ -123,7 +161,7 @@ public class OnionServicesActivity extends AppCompatActivity {
@Override
public void onChange(boolean selfChange) {
- mAdapter.changeCursor(mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, WHERE_SELECTION_CLAUSE, null, null));
+ mAdapter.changeCursor(mContentResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION, BASE_WHERE_SELECTION_CLAUSE + '1', null, null));
// todo battery optimization stuff if lollipop or higher and running onion services
}
}
diff --git a/app/src/main/res/menu/orbot_main.xml b/app/src/main/res/menu/orbot_main.xml
index 2fb0ad4e..c0133d44 100644
--- a/app/src/main/res/menu/orbot_main.xml
+++ b/app/src/main/res/menu/orbot_main.xml
@@ -1,25 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-/*
- * Copyright (C) 2008 Esmertec AG.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
+<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto">
-
<item
android:id="@+id/menu_newnym"
android:icon="@drawable/ic_refresh_white_24dp"
@@ -56,44 +38,37 @@
<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" />
+ android:title="@string/v2_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>
+ </item>
</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"
android:icon="@drawable/ic_menu_about"
android:title="@string/menu_about"
- yourapp:showAsAction="never"
-
- />
+ yourapp:showAsAction="never" />
<item
android:id="@+id/menu_exit"
android:icon="@drawable/ic_menu_exit"
android:title="@string/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 0501adf8..ef8d918f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -169,6 +169,7 @@
<string name="vpn_default_world">Global (Auto)</string>
<string name="hidden_services">Onion Services</string>
+ <string name="v2_hidden_services">V2 Onion Services (Deprecated)</string>
<string name="title_activity_hidden_services">Onion Services</string>
<string name="menu_hidden_services">Onion Services</string>
<string name="save">Save</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 1a9551b5..8ac067b7 100644
--- a/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt
+++ b/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt
@@ -21,7 +21,6 @@ object DiskUtils {
@Throws(IOException::class)
fun readFileFromAssets(assetFilename: String, context: Context): String {
val reader = BufferedReader(InputStreamReader(context.assets.open(assetFilename)))
- // do reading, usually loop until end of file reading
val sb = StringBuilder()
var mLine = reader.readLine()
while (mLine != null) {
1
0
[orbot/master] V3 Backup and Restore working with Storage Access Framework
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit 30e1442f80a2b36f71b9cbf07140de06bf87e024
Author: bim <dsnake(a)protonmail.com>
Date: Fri Nov 27 13:10:25 2020 -0500
V3 Backup and Restore working with Storage Access Framework
---
.../ui/hiddenservices/ClientCookiesActivity.java | 2 +-
.../ui/hiddenservices/HiddenServicesActivity.java | 8 +-
.../ui/hiddenservices/backup/BackupUtils.java | 128 +++++++++++++++++++--
.../dialogs/CookieActionsDialog.java | 2 +-
.../ui/hiddenservices/dialogs/HSActionsDialog.java | 4 +-
.../OnionServiceActionsDialogFragment.java | 6 +-
.../ui/v3onionservice/OnionServicesActivity.java | 14 ++-
.../java/org/torproject/android/core/DiskUtils.kt | 4 +-
8 files changed, 144 insertions(+), 24 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java
index 4c43d897..93443678 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/ClientCookiesActivity.java
@@ -113,7 +113,7 @@ public class ClientCookiesActivity extends AppCompatActivity {
}
private void restoreBackupLegacy() {
- File backupDir = DiskUtils.getOrCreateLegacyBackupDir();
+ File backupDir = DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name));
try {
File[] files = backupDir.listFiles((dir, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(".json"));
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 d7429181..7a943093 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
@@ -107,8 +107,8 @@ public class HiddenServicesActivity extends AppCompatActivity {
}
private void doRestoreLegacy() { // API 16, 17, 18
- File backupDir = DiskUtils.getOrCreateLegacyBackupDir();
- File[] files = backupDir.listFiles((dir, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(".zip"));
+ File backupDir = DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name));
+ File[] files = backupDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
if (files != null) {
if (files.length == 0) {
Toast.makeText(this, R.string.create_a_backup_first, Toast.LENGTH_LONG).show();
@@ -120,7 +120,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
new AlertDialog.Builder(this)
.setTitle(R.string.restore_backup)
- .setItems(fileNames, (dialog, which) -> new BackupUtils(HiddenServicesActivity.this).restoreZipBackupLegacy(files[which]))
+ .setItems(fileNames, (dialog, which) -> new BackupUtils(HiddenServicesActivity.this).restoreZipBackupV2Legacy(files[which]))
.show();
}
@@ -132,7 +132,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
if (request == REQUEST_CODE_READ_ZIP_BACKUP) {
if (response != RESULT_OK) return;
BackupUtils backupUtils = new BackupUtils(this);
- backupUtils.restoreZipBackup(data.getData());
+ backupUtils.restoreZipBackupV2(data.getData());
}
}
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
index a10dd7ff..96ffdf5c 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java
@@ -15,6 +15,7 @@ import org.torproject.android.R;
import org.torproject.android.service.TorServiceConstants;
import org.torproject.android.ui.hiddenservices.providers.CookieContentProvider;
import org.torproject.android.ui.hiddenservices.providers.HSContentProvider;
+import org.torproject.android.ui.v3onionservice.OnionServiceContentProvider;
import java.io.File;
import java.io.FileInputStream;
@@ -37,8 +38,19 @@ public class BackupUtils {
mResolver = mContext.getContentResolver();
}
- public String createZipBackup(int port, Uri zipFile) {
- String[] files = createFilesForZipping(port);
+ public static boolean isV2OnionAddressValid(String onionToTest) {
+ return onionToTest.matches("([a-z0-9]{16}).onion");
+ }
+
+ public String createV3ZipBackup(String port, Uri zipFile) {
+ String[] files = createFilesForZippingV3(port);
+ ZipIt zip = new ZipIt(files, zipFile, mResolver);
+ if (!zip.zip()) return null;
+ return zipFile.getPath();
+ }
+
+ public String createV2ZipBackup(int port, Uri zipFile) {
+ String[] files = createFilesForZippingV2(port);
ZipIt zip = new ZipIt(files, zipFile, mResolver);
if (!zip.zip())
@@ -47,11 +59,50 @@ public class BackupUtils {
return zipFile.getPath();
}
- public static boolean isV2OnionAddressValid(String onionToTest) {
- return onionToTest.matches("([a-z0-9]{16}).onion");
+ // todo also write out authorized clients...
+ private String[] createFilesForZippingV3(String port) {
+ final String v3BasePath = getV3BasePath() + "/v3" + port + "/";
+ final String hostnamePath = v3BasePath + "hostname",
+ configFilePath = v3BasePath + configFileName,
+ privKeyPath = v3BasePath + "hs_ed25519_secret_key",
+ pubKeyPath = v3BasePath + "hs_ed25519_public_key";
+
+ Cursor portData = mResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION,
+ OnionServiceContentProvider.OnionService.PORT + "=" + port, null, null);
+
+ JSONObject config = new JSONObject();
+ try {
+ if (portData == null || portData.getCount() != 1)
+ return null;
+ portData.moveToNext();
+
+
+ config.put(OnionServiceContentProvider.OnionService.NAME, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.NAME)));
+ config.put(OnionServiceContentProvider.OnionService.PORT, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.PORT)));
+ config.put(OnionServiceContentProvider.OnionService.ONION_PORT, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.ONION_PORT)));
+ config.put(OnionServiceContentProvider.OnionService.DOMAIN, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.DOMAIN)));
+ config.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.CREATED_BY_USER)));
+ config.put(OnionServiceContentProvider.OnionService.ENABLED, portData.getString(portData.getColumnIndex(OnionServiceContentProvider.OnionService.ENABLED)));
+
+ } catch (JSONException jsone) {
+ jsone.printStackTrace();
+ return null;
+ }
+ portData.close();
+
+ try {
+ FileWriter fileWriter = new FileWriter(configFilePath);
+ fileWriter.write(config.toString());
+ fileWriter.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ return null;
+ }
+
+ return new String[]{hostnamePath, configFilePath, privKeyPath, pubKeyPath};
}
- private String[] createFilesForZipping(int port) {
+ private String[] createFilesForZippingV2(int port) {
File hsBasePath = getHSBasePath();
String configFilePath = hsBasePath + "/hs" + port + "/" + configFileName;
String hostnameFilePath = hsBasePath + "/hs" + port + "/hostname";
@@ -101,7 +152,45 @@ public class BackupUtils {
return new String[]{hostnameFilePath, keyFilePath, configFilePath};
}
- private void extractConfigFromUnzippedBackup(String backupName) {
+ private void extractConfigFromUnzippedBackupV3(String backupName) {
+ File v3BasePath = getV3BasePath();
+ String v3Dir = backupName.substring(0, backupName.lastIndexOf('.'));
+ String configFilePath = v3BasePath + "/" + v3Dir + "/" + configFileName;
+ File v3Path = new File(v3BasePath.getAbsolutePath(), v3Dir);
+ if (!v3Path.isDirectory()) v3Path.mkdirs();
+
+ File configFile = new File(configFilePath);
+ try {
+ FileInputStream fis = new FileInputStream(configFile);
+ FileChannel fc = fis.getChannel();
+ MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+ String jsonString = Charset.defaultCharset().decode(bb).toString();
+ JSONObject savedValues = new JSONObject(jsonString);
+ ContentValues fields = new ContentValues();
+
+ int port = savedValues.getInt(OnionServiceContentProvider.OnionService.PORT);
+ fields.put(OnionServiceContentProvider.OnionService.PORT, port);
+ fields.put(OnionServiceContentProvider.OnionService.NAME, savedValues.getString(OnionServiceContentProvider.OnionService.NAME));
+ fields.put(OnionServiceContentProvider.OnionService.ONION_PORT, savedValues.getInt(OnionServiceContentProvider.OnionService.ONION_PORT));
+ fields.put(OnionServiceContentProvider.OnionService.DOMAIN, savedValues.getString(OnionServiceContentProvider.OnionService.DOMAIN));
+ fields.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, savedValues.getInt(OnionServiceContentProvider.OnionService.CREATED_BY_USER));
+ fields.put(OnionServiceContentProvider.OnionService.ENABLED, savedValues.getInt(OnionServiceContentProvider.OnionService.ENABLED));
+
+ Cursor dbService = mResolver.query(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.PROJECTION,
+ OnionServiceContentProvider.OnionService.PORT + "=" + port, null, null);
+ if (dbService == null || dbService.getCount() == 0)
+ mResolver.insert(OnionServiceContentProvider.CONTENT_URI, fields);
+ else
+ mResolver.update(OnionServiceContentProvider.CONTENT_URI, fields, OnionServiceContentProvider.OnionService.PORT + "=" + port, null);
+ dbService.close();
+ Toast.makeText(mContext, R.string.backup_restored, Toast.LENGTH_LONG).show();
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private void extractConfigFromUnzippedBackupV2(String backupName) {
File mHSBasePath = getHSBasePath();
int port;
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
@@ -166,18 +255,22 @@ public class BackupUtils {
return new File(mContext.getFilesDir().getAbsolutePath(), TorServiceConstants.HIDDEN_SERVICES_DIR);
}
- public void restoreZipBackupLegacy(File zipFile) {
+ private File getV3BasePath() {
+ return new File(mContext.getFilesDir().getAbsolutePath(), TorServiceConstants.ONION_SERVICES_DIR);
+ }
+
+ public void restoreZipBackupV2Legacy(File zipFile) {
String backupName = zipFile.getName();
ZipIt zip = new ZipIt(null, null, mResolver);
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
File hsPath = new File(getHSBasePath().getAbsolutePath(), hsDir);
if (zip.unzipLegacy(hsPath.getAbsolutePath(), zipFile))
- extractConfigFromUnzippedBackup(backupName);
+ extractConfigFromUnzippedBackupV2(backupName);
else
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
}
- public void restoreZipBackup(Uri zipUri) {
+ public void restoreZipBackupV2(Uri zipUri) {
Cursor returnCursor = mResolver.query(zipUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
@@ -187,12 +280,27 @@ public class BackupUtils {
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
File hsPath = new File(getHSBasePath().getAbsolutePath(), hsDir);
if (new ZipIt(null, zipUri, mResolver).unzip(hsPath.getAbsolutePath()))
- extractConfigFromUnzippedBackup(backupName);
+ extractConfigFromUnzippedBackupV2(backupName);
else
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
+ }
+ public void restoreZipBackupV3(Uri zipUri) {
+ Cursor returnCursor = mResolver.query(zipUri, null, null, null, null);
+ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ returnCursor.moveToFirst();
+ String backupName = returnCursor.getString(nameIndex);
+ returnCursor.close();
+
+ String v3Dir = backupName.substring(0, backupName.lastIndexOf('.'));
+ File v3Paath = new File(getV3BasePath().getAbsolutePath(), v3Dir);
+ if (new ZipIt(null, zipUri, mResolver).unzip(v3Paath.getAbsolutePath()))
+ extractConfigFromUnzippedBackupV3(backupName);
+ else
+ Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
}
+
public void restoreKeyBackup(int hsPort, Uri hsKeyPath) {
File mHSBasePath = new File(
mContext.getFilesDir().getAbsolutePath(),
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/CookieActionsDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/CookieActionsDialog.java
index 8c5ef304..d3286ab1 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/CookieActionsDialog.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/CookieActionsDialog.java
@@ -73,7 +73,7 @@ public class CookieActionsDialog extends DialogFragment {
} else { // API 16, 17, and 18
int msg = R.string.backup_saved_at_external_storage;
try {
- File externalStorage = DiskUtils.getOrCreateLegacyBackupDir();
+ File externalStorage = DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name));
String backupFile = externalStorage.getAbsolutePath() + "/" + filename;
String data = createBackupData();
FileWriter writer = new FileWriter(backupFile);
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java
index 76932c88..1d2e7844 100644
--- a/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java
+++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSActionsDialog.java
@@ -92,7 +92,7 @@ public class HSActionsDialog extends DialogFragment {
Intent createFile = DiskUtils.createWriteFileIntent(filename, "application/zip");
startActivityForResult(createFile, REQUEST_CODE_WRITE_FILE);
} else { // API 16, 17, 18
- attemptToWriteBackup(Uri.fromFile(new File(DiskUtils.getOrCreateLegacyBackupDir(), filename)));
+ attemptToWriteBackup(Uri.fromFile(new File(DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name)), filename)));
}
}
@@ -107,7 +107,7 @@ public class HSActionsDialog extends DialogFragment {
private void attemptToWriteBackup(Uri outputFile) {
BackupUtils backupUtils = new BackupUtils(getContext());
- String backup = backupUtils.createZipBackup(port, outputFile);
+ String backup = backupUtils.createV2ZipBackup(port, outputFile);
Toast.makeText(getContext(), backup != null ? R.string.backup_saved_at_external_storage : R.string.error, Toast.LENGTH_LONG).show();
dismiss();
}
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
index 822a45f2..4d26270d 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActionsDialogFragment.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActionsDialogFragment.java
@@ -61,7 +61,7 @@ public class OnionServiceActionsDialogFragment extends DialogFragment {
}
private void doBackup(Bundle arguments, Context context) {
- String filename = "onion_service" + arguments.getInt(OnionServicesActivity.BUNDLE_KEY_PORT) + ".zip";
+ String filename = "onion_service" + arguments.getString(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;
@@ -70,7 +70,7 @@ public class OnionServiceActionsDialogFragment extends DialogFragment {
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)));
+ attemptToWriteBackup(Uri.fromFile(new File(DiskUtils.getOrCreateLegacyBackupDir(getString(R.string.app_name)), filename)));
}
}
@@ -85,7 +85,7 @@ public class OnionServiceActionsDialogFragment extends DialogFragment {
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
+ String backup = backupUtils.createV3ZipBackup(getArguments().getString(OnionServicesActivity.BUNDLE_KEY_PORT), outputFile);
Toast.makeText(getContext(), backup != null ? R.string.backup_saved_at_external_storage : R.string.error, Toast.LENGTH_LONG).show();
dismiss();
}
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
index 3be04731..eed43a71 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServicesActivity.java
@@ -2,6 +2,7 @@ package org.torproject.android.ui.v3onionservice;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
@@ -19,11 +20,13 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.torproject.android.R;
import org.torproject.android.core.DiskUtils;
import org.torproject.android.core.LocaleHelper;
+import org.torproject.android.ui.hiddenservices.backup.BackupUtils;
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 static final int REQUEST_CODE_READ_ZIP_BACKUP = 347;
private RadioButton radioShowUserServices, radioShowAppServices;
private FloatingActionButton fab;
private ContentResolver mContentResolver;
@@ -73,7 +76,8 @@ public class OnionServicesActivity extends AppCompatActivity {
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_restore_backup) {
if (DiskUtils.supportsStorageAccessFramework()) {
-
+ Intent readFileIntent = DiskUtils.createReadFileIntent("application/zip");
+ startActivityForResult(readFileIntent, REQUEST_CODE_READ_ZIP_BACKUP);
} else { // 16, 17, 18
}
@@ -81,6 +85,14 @@ public class OnionServicesActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
+ @Override
+ protected void onActivityResult(int requestCode, int result, Intent data) {
+ super.onActivityResult(requestCode, result, data);
+ if (requestCode == REQUEST_CODE_READ_ZIP_BACKUP && result == RESULT_OK) {
+ new BackupUtils(this).restoreZipBackupV3(data.getData());
+ }
+ }
+
private class OnionServiceObserver extends ContentObserver {
OnionServiceObserver(Handler handler) {
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 be74aa4e..1a9551b5 100644
--- a/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt
+++ b/appcore/src/main/java/org/torproject/android/core/DiskUtils.kt
@@ -66,9 +66,9 @@ object DiskUtils {
fun readFile(contentResolver: ContentResolver, file: File): String = readFileFromInputStream(contentResolver, Uri.fromFile(file))
@JvmStatic
- fun getOrCreateLegacyBackupDir(): File? {
+ fun getOrCreateLegacyBackupDir(directoryName: String): File? {
if (Environment.MEDIA_MOUNTED != Environment.getExternalStorageState()) return null
- val dir = File(Environment.getExternalStorageDirectory(), )
+ val dir = File(Environment.getExternalStorageDirectory(), directoryName)
return if (!dir.isDirectory && !dir.mkdirs()) null else dir
}
1
0
commit feb3de3b4b907bcbd9c78522197027355036965b
Author: bim <dsnake(a)protonmail.com>
Date: Sat Nov 28 12:55:46 2020 -0500
removed unused interface
---
.../main/java/org/torproject/android/MainConstants.java | 15 ---------------
.../java/org/torproject/android/OrbotMainActivity.java | 5 +++--
.../android/ui/onboarding/CustomBridgesActivity.java | 6 +++---
3 files changed, 6 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/MainConstants.java b/app/src/main/java/org/torproject/android/MainConstants.java
deleted file mode 100644
index e08f4e4b..00000000
--- a/app/src/main/java/org/torproject/android/MainConstants.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.torproject.android;
-
-public interface MainConstants {
-
- //EXIT COUNTRY CODES
- String[] COUNTRY_CODES = {"DE", "AT", "SE", "CH", "IS", "CA", "US", "ES", "FR", "BG", "PL", "AU", "BR", "CZ", "DK", "FI", "GB", "HU", "NL", "JP", "RO", "RU", "SG", "SK"};
-
- //path to check Tor against
- String URL_TOR_CHECK = "https://check.torproject.org";
-
- String URL_TOR_BRIDGES = "https://bridges.torproject.org/bridges";
-
- String EMAIL_TOR_BRIDGES = "bridges(a)torproject.org";
-
-}
diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
index abc87cc0..83f321e9 100644
--- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java
+++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
@@ -90,8 +90,6 @@ import java.util.StringTokenizer;
import pl.bclogic.pulsator4droid.library.PulsatorLayout;
import static androidx.core.content.FileProvider.getUriForFile;
-import static org.torproject.android.MainConstants.COUNTRY_CODES;
-import static org.torproject.android.MainConstants.URL_TOR_CHECK;
import static org.torproject.android.service.TorServiceConstants.ACTION_START;
import static org.torproject.android.service.TorServiceConstants.ACTION_START_VPN;
import static org.torproject.android.service.TorServiceConstants.ACTION_STOP_VPN;
@@ -115,6 +113,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;
+ private static final String[] COUNTRY_CODES = {"DE", "AT", "SE", "CH", "IS", "CA", "US", "ES", "FR", "BG", "PL", "AU", "BR", "CZ", "DK", "FI", "GB", "HU", "NL", "JP", "RO", "RU", "SG", "SK"};
+ private static final String URL_TOR_CHECK = "https://check.torproject.org";
+ ;
// 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);
diff --git a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
index 6fce9852..f20ba4ff 100644
--- a/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/onboarding/CustomBridgesActivity.java
@@ -37,11 +37,11 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
-import static org.torproject.android.MainConstants.EMAIL_TOR_BRIDGES;
-import static org.torproject.android.MainConstants.URL_TOR_BRIDGES;
-
public class CustomBridgesActivity extends AppCompatActivity implements TextWatcher {
+ private static final String EMAIL_TOR_BRIDGES = "bridges(a)torproject.org";
+ private static final String URL_TOR_BRIDGES = "https://bridges.torproject.org/bridges";
+
private EditText mEtPastedBridges;
// configures an EditText we assume to be multiline and nested in a ScrollView to be independently scrollable
1
0
[orbot/master] V3 and V2 onions can coexist, Orbot ready to receive V3s from netcipher
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit a26c18e1c95a488213467a937d0ba96fce2b1d63
Author: bim <dsnake(a)protonmail.com>
Date: Sat Nov 28 23:56:12 2020 -0500
V3 and V2 onions can coexist, Orbot ready to receive V3s from netcipher
---
.../org/torproject/android/OrbotMainActivity.java | 124 ++++++++++++---------
app/src/main/res/values/strings.xml | 2 +-
.../torproject/android/service/OrbotService.java | 4 +-
3 files changed, 75 insertions(+), 55 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
index 83f321e9..a2922af7 100644
--- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java
+++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
@@ -10,7 +10,6 @@ import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -74,6 +73,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.OnionServiceContentProvider;
import org.torproject.android.ui.v3onionservice.OnionServicesActivity;
import java.io.File;
@@ -102,13 +102,14 @@ import static org.torproject.android.service.vpn.VpnPrefs.PREFS_KEY_TORIFIED;
public class OrbotMainActivity extends AppCompatActivity implements OrbotConstants {
- 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";
- private final static int REQUEST_VPN = 8888;
- private final static int REQUEST_SETTINGS = 0x9874;
- private final static int REQUEST_VPN_APPS_SELECT = 8889;
+ private static final String INTENT_ACTION_REQUEST_HIDDEN_SERVICE = "org.torproject.android.REQUEST_HS_PORT";
+ private static final String INTENT_ACTION_REQUEST_V3_ONION_SERVICE = "org.torproject.android.REQUEST_V3_ONION_SERVICE";
+ private static final String INTENT_ACTION_REQUEST_START_TOR = "org.torproject.android.START_TOR";
+ private static final int REQUEST_VPN = 8888;
+ private static final int REQUEST_SETTINGS = 0x9874;
+ private static final int REQUEST_VPN_APPS_SELECT = 8889;
// message types for mStatusUpdateHandler
- private final static int STATUS_UPDATE = 1;
+ private static final int STATUS_UPDATE = 1;
private static final int MESSAGE_TRAFFIC_COUNT = 2;
private static final int MESSAGE_PORTS = 3;
private static final float ROTATE_FROM = 0.0f;
@@ -120,18 +121,18 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
// 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;
+ AlertDialog aDialog;
/* Useful UI bits */
- private TextView lblStatus = null; //the main text display widget
- private TextView lblPorts = null;
- private ImageView imgStatus = null; //the main touchable image for activating Orbot
- private TextView downloadText = null;
- private TextView uploadText = null;
- private TextView mTxtOrbotLog = null;
- private Button mBtnStart = null;
- private SwitchCompat mBtnVPN = null;
- private SwitchCompat mBtnBridges = null;
- private Spinner spnCountries = null;
+ private TextView lblStatus; //the main text display widget
+ private TextView lblPorts;
+ private ImageView imgStatus; //the main touchable image for activating Orbot
+ private TextView downloadText;
+ private TextView uploadText;
+ private TextView mTxtOrbotLog;
+ private Button mBtnStart;
+ private SwitchCompat mBtnVPN;
+ private SwitchCompat mBtnBridges;
+ private Spinner spnCountries;
private DrawerLayout mDrawer;
/* Some tracking bits */
private String torStatus = null; //latest status reported from the tor service
@@ -538,8 +539,30 @@ 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 enableV3OnionServiceOnV3(int localPort, int onionPort, String name) {
+ ContentValues fields = new ContentValues();
+ fields.put(OnionServiceContentProvider.OnionService.PORT, localPort);
+ fields.put(OrbotService.OnionService.NAME, name);
+ fields.put(OnionServiceContentProvider.OnionService.PORT, onionPort);
+ fields.put(OnionServiceContentProvider.OnionService.ENABLED, 1);
+ fields.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, 0);
+
+ ContentResolver contentResolver = getContentResolver();
+ contentResolver.insert(OnionServiceContentProvider.CONTENT_URI, fields);
+
+ 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();
+ }
+
+
+
+ }
+
+ private void enableHiddenServicePortV2(String hsName, final int hsPort, int hsRemotePort,
+ final String backupToPackage, final Uri hsKeyPath, final Boolean authCookie) {
String onionHostname = null;
if (hsName == null)
@@ -582,9 +605,7 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
startTor();
} else {
stopTor();
- Toast.makeText(
- this, R.string.start_tor_again_for_finish_the_process, Toast.LENGTH_LONG
- ).show();
+ Toast.makeText(this, R.string.start_tor_again_for_finish_the_process, Toast.LENGTH_LONG).show();
}
new Thread() {
@@ -668,41 +689,44 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
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 Boolean authCookie = intent.getBooleanExtra("hs_auth_cookie", false);
- final Uri mKeyUri = intent.getData();
-
- DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- enableHiddenServicePort(
- hiddenServiceName, hiddenServicePort,
- hiddenServiceRemotePort, backupToPackage,
- mKeyUri, authCookie
- );
- }
- };
-
- String requestMsg = getString(R.string.hidden_service_request, String.valueOf(hiddenServicePort));
- new AlertDialog.Builder(this).setMessage(requestMsg)
- .setPositiveButton(R.string.allow, dialogClickListener)
- .setNegativeButton(R.string.deny, dialogClickListener).show();
+ case INTENT_ACTION_REQUEST_V3_ONION_SERVICE:
+ final int v3LocalPort = intent.getIntExtra("localPort", -1);
+ final int v3onionPort = intent.getIntExtra("onionPort", v3LocalPort);
+ String name = intent.getStringExtra("name") ;
+ if (name == null) name = "v3" + v3LocalPort;
+ final String finalName = name;
+ new AlertDialog.Builder(this)
+ .setMessage(getString(R.string.hidden_service_request, String.valueOf(v3LocalPort)))
+ .setPositiveButton(R.string.allow, (d, w) -> enableV3OnionServiceOnV3(v3LocalPort, v3onionPort, finalName))
+ .setNegativeButton(R.string.deny, (d, w) -> d.dismiss())
+ .show();
+ return;
+ case INTENT_ACTION_REQUEST_HIDDEN_SERVICE:
+ final int v2hiddenServicePort = intent.getIntExtra("hs_port", -1);
+ final int v2hiddenServiceRemotePort = intent.getIntExtra("hs_onion_port", -1);
+ final String v2hiddenServiceName = intent.getStringExtra("hs_name");
+ final String v2backupToPackage = intent.getStringExtra("hs_backup_to_package");
+ final Boolean v2authCookie = intent.getBooleanExtra("hs_auth_cookie", false);
+ final Uri v2KeyUri = intent.getData();
+
+ String v2RequestMsg = getString(R.string.hidden_service_request, String.valueOf(v2hiddenServicePort));
+ new AlertDialog.Builder(this).setMessage(v2RequestMsg)
+ .setPositiveButton(R.string.allow, (dialog, which) -> enableHiddenServicePortV2(
+ v2hiddenServiceName, v2hiddenServicePort,
+ v2hiddenServiceRemotePort, v2backupToPackage,
+ v2KeyUri, v2authCookie))
+ .setNegativeButton(R.string.deny, (d, w) -> d.dismiss()).show();
return; //don't null the setIntent() as we need it later
case INTENT_ACTION_REQUEST_START_TOR:
autoStartFromIntent = true;
startTor();
-
break;
+
case Intent.ACTION_VIEW:
String urlString = intent.getDataString();
-
if (urlString != null) {
-
if (urlString.toLowerCase(Locale.ENGLISH).startsWith("bridge://")) {
String newBridgeValue = urlString.substring(9); //remove the bridge protocol piece
try {
@@ -712,17 +736,13 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
}
showAlert(getString(R.string.bridges_updated), getString(R.string.restart_orbot_to_use_this_bridge_) + newBridgeValue, false);
-
setNewBridges(newBridgeValue);
}
}
break;
}
-
updateStatus(null, torStatus);
-
setIntent(null);
-
}
private void setNewBridges(String newBridgeValue) {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ef8d918f..c888c856 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,7 +100,7 @@
<string name="libevent_version">LibEvent: http://www.monkey.org/~provos/libevent/</string>
<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="hidden_service_request">An app wants to open onion server on 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>
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 10acf5de..b9dd34a1 100644
--- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java
+++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java
@@ -1370,8 +1370,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
ContentResolver contentResolver = getApplicationContext().getContentResolver();
addV3OnionServicesToTorrc(extraLines, contentResolver);
-// addV2HiddenServicesToTorrc(extraLines, contentResolver);
-// addV2ClientCookiesToTorrc(extraLines, contentResolver);
+ addV2HiddenServicesToTorrc(extraLines, contentResolver);
+ addV2ClientCookiesToTorrc(extraLines, contentResolver);
return extraLines;
}
1
0
[orbot/master] generate nonsense named auth_privates locally when OrbotService is running
by n8fr8@torproject.org 22 Dec '21
by n8fr8@torproject.org 22 Dec '21
22 Dec '21
commit f13b53b8384eff025501efcb187c45ad3140e801
Author: bim <dsnake(a)protonmail.com>
Date: Thu Jan 28 16:04:26 2021 -0500
generate nonsense named auth_privates locally when OrbotService is running
---
.../src/main/java/org/torproject/android/service/OrbotService.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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 9a401ac6..7f6612a9 100644
--- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java
+++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java
@@ -1452,10 +1452,11 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
}
torrc.append("ClientOnionAuthDir " + mV3AuthBasePath.getAbsolutePath()).append('\n');
try {
+ int i = 0;
while (v3auths.moveToNext()) {
String domain = v3auths.getString(v3auths.getColumnIndex(V3ClientAuth.DOMAIN));
String hash = v3auths.getString(v3auths.getColumnIndex(V3ClientAuth.HASH));
- File authFile = new File(mV3AuthBasePath, domain + ".auth_private");
+ File authFile = new File(mV3AuthBasePath, (i++) + ".auth_private");
authFile.createNewFile();
FileOutputStream fos = new FileOutputStream(authFile);
fos.write(buildV3ClientAuthFile(domain, hash).getBytes());
1
0
commit 23b86e518fc269eb180f931d7d08308ad654a1ce
Author: bim <dsnake(a)protonmail.com>
Date: Sun Dec 13 14:13:32 2020 -0500
missing netcipher integration stuff
---
app/src/main/AndroidManifest.xml | 6 ++++--
app/src/main/java/org/torproject/android/OrbotMainActivity.java | 6 +++---
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7b81951f..0f69c722 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -39,7 +39,6 @@
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
-
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
@@ -52,9 +51,12 @@
</intent-filter>
<intent-filter>
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
-
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <intent-filter>
+ <action android:name="org.torproject.android.REQUEST_V3_ONION_SERVICE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
<intent-filter>
<action android:name="org.torproject.android.START_TOR" />
diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
index a2922af7..773c7fa6 100644
--- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java
+++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java
@@ -539,11 +539,11 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
sendIntentToService(ACTION_START_VPN);
}
- private void enableV3OnionServiceOnV3(int localPort, int onionPort, String name) {
+ private void enableV3OnionService(int localPort, int onionPort, String name) {
ContentValues fields = new ContentValues();
fields.put(OnionServiceContentProvider.OnionService.PORT, localPort);
fields.put(OrbotService.OnionService.NAME, name);
- fields.put(OnionServiceContentProvider.OnionService.PORT, onionPort);
+ fields.put(OnionServiceContentProvider.OnionService.ONION_PORT, onionPort);
fields.put(OnionServiceContentProvider.OnionService.ENABLED, 1);
fields.put(OnionServiceContentProvider.OnionService.CREATED_BY_USER, 0);
@@ -697,7 +697,7 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan
final String finalName = name;
new AlertDialog.Builder(this)
.setMessage(getString(R.string.hidden_service_request, String.valueOf(v3LocalPort)))
- .setPositiveButton(R.string.allow, (d, w) -> enableV3OnionServiceOnV3(v3LocalPort, v3onionPort, finalName))
+ .setPositiveButton(R.string.allow, (d, w) -> enableV3OnionService(v3LocalPort, v3onionPort, finalName))
.setNegativeButton(R.string.deny, (d, w) -> d.dismiss())
.show();
return;
1
0