commit 5465fffbe8061f890342241e0fbbabb55e883e2d
Author: bim <dsnake(a)protonmail.com>
Date: Thu Sep 23 21:53:42 2021 -0400
Fixes #523 Onion Site Backup Bags
This bug was introdued when a previous bug fix pertaining to Onion service storage in Orbot was addressed.
The old bug made it such that multiple onion services could be hosted that pointed to the same local port on the device.
This previous bug fix broke the backup logic for v2 and v3 onion services, which is fixed here.
---
.../ui/hiddenservices/HiddenServicesActivity.java | 4 +++-
.../ui/hiddenservices/backup/BackupUtils.java | 28 +++++++++++-----------
.../ui/hiddenservices/dialogs/HSActionsDialog.java | 3 ++-
.../ui/hiddenservices/dialogs/HSDeleteDialog.java | 2 +-
.../providers/HSContentProvider.java | 4 +++-
.../OnionServiceActionsDialogFragment.java | 5 +++-
.../ui/v3onionservice/OnionServiceActivity.java | 3 ++-
.../OnionServiceContentProvider.java | 5 ++--
.../OnionServiceDeleteDialogFragment.java | 2 +-
9 files changed, 33 insertions(+), 23 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 7436eb91..147c4e7e 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
@@ -39,7 +39,8 @@ public class HiddenServicesActivity extends AppCompatActivity {
BUNDLE_KEY_PORT = "port",
BUNDLE_KEY_ONION = "onion",
BUNDLE_KEY_AUTH_COOKIE = "auth_cookie",
- BUNDLE_KEY_AUTH_COOKIE_VALUE = "auth_cookie_value";
+ BUNDLE_KEY_AUTH_COOKIE_VALUE = "auth_cookie_value",
+ BUNDLE_KEY_PATH = "path";
private static final int REQUEST_CODE_READ_ZIP_BACKUP = 125;
private static final String BUNDLE_KEY_SHOW_USER_SERVICES = "show_user_services";
private ContentResolver mResolver;
@@ -83,6 +84,7 @@ public class HiddenServicesActivity extends AppCompatActivity {
arguments.putString(BUNDLE_KEY_ONION, item.getString(item.getColumnIndex(HSContentProvider.HiddenService.DOMAIN)));
arguments.putInt(BUNDLE_KEY_AUTH_COOKIE, item.getInt(item.getColumnIndex(HSContentProvider.HiddenService.AUTH_COOKIE)));
arguments.putString(BUNDLE_KEY_AUTH_COOKIE_VALUE, item.getString(item.getColumnIndex(HSContentProvider.HiddenService.AUTH_COOKIE_VALUE)));
+ arguments.putString(BUNDLE_KEY_PATH, item.getString(item.getColumnIndex(HSContentProvider.HiddenService.PATH)));
HSActionsDialog dialog = new HSActionsDialog();
dialog.setArguments(arguments);
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 d6cb091c..64ca1e8d 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
@@ -40,8 +40,8 @@ public class BackupUtils {
mResolver = mContext.getContentResolver();
}
- public String createV3ZipBackup(String port, Uri zipFile) {
- String[] files = createFilesForZippingV3(port);
+ public String createV3ZipBackup(String port, String relativePath, Uri zipFile) {
+ String[] files = createFilesForZippingV3(relativePath);
ZipUtilities zip = new ZipUtilities(files, zipFile, mResolver);
if (!zip.zip()) return null;
return zipFile.getPath();
@@ -61,8 +61,8 @@ public class BackupUtils {
return backupFile.getPath();
}
- public String createV2ZipBackup(int port, Uri zipFile) {
- String[] files = createFilesForZippingV2(port);
+ public String createV2ZipBackup(int port, String relativePath, Uri zipFile) {
+ String[] files = createFilesForZippingV2(relativePath);
ZipUtilities zip = new ZipUtilities(files, zipFile, mResolver);
if (!zip.zip())
@@ -72,15 +72,15 @@ public class BackupUtils {
}
// todo this doesn't export data for onions that orbot hosts which have authentication (not supported yet...)
- private String[] createFilesForZippingV3(String port) {
- final String v3BasePath = getV3BasePath() + "/v3" + port + "/";
+ private String[] createFilesForZippingV3(String relativePath) {
+ final String v3BasePath = getV3BasePath() + "/" + relativePath + "/";
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);
+ OnionServiceContentProvider.OnionService.PATH + "=\"" + relativePath + "\"", null, null);
JSONObject config = new JSONObject();
try {
@@ -109,16 +109,16 @@ public class BackupUtils {
return new String[]{hostnamePath, configFilePath, privKeyPath, pubKeyPath};
}
- private String[] createFilesForZippingV2(int port) {
- File hsBasePath = getHSBasePath();
- String configFilePath = hsBasePath + "/hs" + port + "/" + configFileName;
- String hostnameFilePath = hsBasePath + "/hs" + port + "/hostname";
- String keyFilePath = hsBasePath + "/hs" + port + "/private_key";
+ private String[] createFilesForZippingV2(String relativePath) {
+ final String hsBasePath = getHSBasePath() + "/" + relativePath + "/";
+ String configFilePath = hsBasePath + configFileName;
+ String hostnameFilePath = hsBasePath + "hostname";
+ String keyFilePath = hsBasePath + "private_key";
Cursor portData = mResolver.query(
HSContentProvider.CONTENT_URI,
HSContentProvider.PROJECTION,
- HSContentProvider.HiddenService.PORT + "=" + port,
+ HSContentProvider.HiddenService.PATH + "=\"" + relativePath + "\"",
null,
null
);
@@ -193,7 +193,7 @@ public class BackupUtils {
Toast.makeText(mContext, R.string.backup_restored, Toast.LENGTH_LONG).show();
} else {
// collision, clean up files
- for (File file: v3Path.listFiles())
+ for (File file : v3Path.listFiles())
file.delete();
v3Path.delete();
Toast.makeText(mContext, mContext.getString(R.string.backup_port_exist, port), Toast.LENGTH_LONG).show();
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 5a7165fe..8d319324 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
@@ -107,8 +107,9 @@ public class HSActionsDialog extends DialogFragment {
}
private void attemptToWriteBackup(Uri outputFile) {
+ String path = getArguments().getString(HiddenServicesActivity.BUNDLE_KEY_PATH);
BackupUtils backupUtils = new BackupUtils(getContext());
- String backup = backupUtils.createV2ZipBackup(port, outputFile);
+ String backup = backupUtils.createV2ZipBackup(port, path, 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/hiddenservices/dialogs/HSDeleteDialog.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/dialogs/HSDeleteDialog.java
index f4a96226..065f68e3 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
@@ -33,7 +33,7 @@ public class HSDeleteDialog extends DialogFragment {
// Delete from internal storage
String base = context.getFilesDir().getAbsolutePath() + "/" + TorServiceConstants.HIDDEN_SERVICES_DIR;
- File dir = new File(base, "hs" + arguments.getString(HiddenServicesActivity.BUNDLE_KEY_PORT));
+ File dir = new File(base, arguments.getString(HiddenServicesActivity.BUNDLE_KEY_PATH));
if (dir.isDirectory()) {
String[] children = dir.list();
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 79b566fd..bc4e16b1 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
@@ -24,7 +24,8 @@ public class HSContentProvider extends ContentProvider {
HiddenService.AUTH_COOKIE,
HiddenService.AUTH_COOKIE_VALUE,
HiddenService.CREATED_BY_USER,
- HiddenService.ENABLED
+ HiddenService.ENABLED,
+ HiddenService.PATH
};
private static final String AUTH = "org.torproject.android.ui.hiddenservices.providers";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTH + "/hs");
@@ -134,6 +135,7 @@ public class HSContentProvider extends ContentProvider {
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";
+ public static final String PATH = "filepath";
private HiddenService() {
}
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 17ce59a7..6c1a8e95 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
@@ -63,6 +63,7 @@ public class OnionServiceActionsDialogFragment extends DialogFragment {
private void doBackup(Bundle arguments, Context context) {
String filename = "onion_service" + arguments.getString(OnionServiceActivity.BUNDLE_KEY_PORT) + ".zip";
+ String relativePath = arguments.getString(OnionServiceActivity.BUNDLE_KEY_PATH);
if (arguments.getString(OnionServiceActivity.BUNDLE_KEY_DOMAIN) == null) {
Toast.makeText(context, R.string.please_restart_Orbot_to_enable_the_changes, Toast.LENGTH_LONG).show();
return;
@@ -85,8 +86,10 @@ public class OnionServiceActionsDialogFragment extends DialogFragment {
}
private void attemptToWriteBackup(Uri outputFile) {
+ String port = getArguments().getString(OnionServiceActivity.BUNDLE_KEY_PORT);
+ String relativePath = getArguments().getString(OnionServiceActivity.BUNDLE_KEY_PATH);
BackupUtils backupUtils = new BackupUtils(getContext());
- String backup = backupUtils.createV3ZipBackup(getArguments().getString(OnionServiceActivity.BUNDLE_KEY_PORT), outputFile);
+ String backup = backupUtils.createV3ZipBackup(port, relativePath, 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/OnionServiceActivity.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActivity.java
index 39db0b10..88f05564 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActivity.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceActivity.java
@@ -32,7 +32,7 @@ import java.io.File;
public class OnionServiceActivity extends AppCompatActivity {
- static final String BUNDLE_KEY_ID = "id", BUNDLE_KEY_PORT = "port", BUNDLE_KEY_DOMAIN = "domain";
+ static final String BUNDLE_KEY_ID = "id", BUNDLE_KEY_PORT = "port", BUNDLE_KEY_DOMAIN = "domain", BUNDLE_KEY_PATH = "path";
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;
@@ -72,6 +72,7 @@ public class OnionServiceActivity extends AppCompatActivity {
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)));
+ arguments.putString(BUNDLE_KEY_PATH, item.getString(item.getColumnIndex(OnionServiceContentProvider.OnionService.PATH)));
OnionServiceActionsDialogFragment dialog = new OnionServiceActionsDialogFragment(arguments);
dialog.show(getSupportFragmentManager(), OnionServiceActionsDialogFragment.class.getSimpleName());
});
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
index 61b8540a..c4ae10ec 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceContentProvider.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceContentProvider.java
@@ -21,7 +21,8 @@ public class OnionServiceContentProvider extends ContentProvider {
OnionService.DOMAIN,
OnionService.ONION_PORT,
OnionService.CREATED_BY_USER,
- OnionService.ENABLED
+ OnionService.ENABLED,
+ OnionService.PATH
};
private static final int ONIONS = 1, ONION_ID = 2;
@@ -102,7 +103,7 @@ public class OnionServiceContentProvider extends ContentProvider {
public static final String DOMAIN = "domain";
public static final String CREATED_BY_USER = "created_by_user";
public static final String ENABLED = "enabled";
-
+ public static final String PATH = "filepath";
private OnionService() { // no-op
}
}
diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDeleteDialogFragment.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDeleteDialogFragment.java
index 71111fe1..1606c2e4 100644
--- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDeleteDialogFragment.java
+++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDeleteDialogFragment.java
@@ -34,7 +34,7 @@ public class OnionServiceDeleteDialogFragment extends DialogFragment {
private void doDelete(Bundle arguments, Context context) {
context.getContentResolver().delete(OnionServiceContentProvider.CONTENT_URI, OnionServiceContentProvider.OnionService._ID + '=' + arguments.getInt(OnionServiceActivity.BUNDLE_KEY_ID), null);
String base = context.getFilesDir().getAbsolutePath() + "/" + TorServiceConstants.ONION_SERVICES_DIR;
- DiskUtils.recursivelyDeleteDirectory(new File(base, "v3" + arguments.getString(OnionServiceActivity.BUNDLE_KEY_PORT)));
+ DiskUtils.recursivelyDeleteDirectory(new File(base, arguments.getString(OnionServiceActivity.BUNDLE_KEY_PATH)));
}
}