diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index d6012d5a..85dc0280 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -29,6 +29,7 @@ import org.torproject.android.ui.PromoAppsActivity; import org.torproject.android.ui.Rotate3dAnimation; import org.torproject.android.ui.hs.providers.HSContentProvider; import org.torproject.android.vpn.VPNEnableActivity; +import org.torproject.android.hsutils.HiddenServiceUtils; import android.annotation.SuppressLint; import android.app.ActivityManager; @@ -596,25 +597,23 @@ public class OrbotMainActivity extends AppCompatActivity stopVpnService(); } - private void enableHiddenServicePort (String hsName, int hsPort, int hsRemotePort) throws RemoteException, InterruptedException + private void enableHiddenServicePort (String hsName, final int hsPort, int hsRemotePort, final boolean doBackup) throws RemoteException, InterruptedException { String onionHostname = null; - final int mHsPort = hsPort; - if(hsName == null) - hsName = "hs" + mHsPort; + hsName = "hs" + hsPort; if(hsRemotePort == -1) - hsRemotePort = mHsPort; + hsRemotePort = hsPort; ContentValues fields = new ContentValues(); fields.put("name", hsName); - fields.put("port", mHsPort); + fields.put("port", hsPort); fields.put("onion_port", hsRemotePort); ContentResolver cr = getContentResolver(); - Cursor row = cr.query(HSContentProvider.CONTENT_URI, mProjection, "port=" + mHsPort, null, null); + Cursor row = cr.query(HSContentProvider.CONTENT_URI, mProjection, "port=" + hsPort, null, null); if(row == null) { cr.insert(HSContentProvider.CONTENT_URI, fields); @@ -632,6 +631,7 @@ public class OrbotMainActivity extends AppCompatActivity public void run () { String hostname = null; + String backupPath = null; while (hostname == null) { @@ -643,16 +643,22 @@ public class OrbotMainActivity extends AppCompatActivity e.printStackTrace(); } - Cursor onion = getContentResolver().query(HSContentProvider.CONTENT_URI, mProjection, "port=" + mHsPort, null, null); + Cursor onion = getContentResolver().query(HSContentProvider.CONTENT_URI, mProjection, "port=" + hsPort, null, null); if(onion != null) { hostname = onion.getString(onion.getColumnIndex(HSContentProvider.HiddenService.NAME)); + if(doBackup) { + HiddenServiceUtils hsutils = new HiddenServiceUtils(getApplicationContext()); + backupPath = hsutils.createOnionBackup(hsPort); + } onion.close(); } } Intent nResult = new Intent(); nResult.putExtra("hs_host", hostname); - // TODO: Add key + if(doBackup && backupPath != null) { + nResult.putExtra("hs_backup_path", backupPath); + } setResult(RESULT_OK, nResult); finish(); } @@ -685,9 +691,10 @@ public class OrbotMainActivity extends AppCompatActivity if (action.equals(INTENT_ACTION_REQUEST_HIDDEN_SERVICE)) { - final int hiddenServicePort = getIntent().getIntExtra("hs_port", -1); - final int hiddenServiceRemotePort = getIntent().getIntExtra("hs_onion_port", -1); - final String hiddenServiceName = getIntent().getStringExtra("hs_name"); + 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 Boolean createBackup = intent.getBooleanExtra("hs_backup",false); DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @@ -697,7 +704,8 @@ public class OrbotMainActivity extends AppCompatActivity try { enableHiddenServicePort ( - hiddenServiceName, hiddenServicePort, hiddenServiceRemotePort + hiddenServiceName, hiddenServicePort, + hiddenServiceRemotePort, createBackup ); } catch (RemoteException e) { // TODO Auto-generated catch block diff --git a/app/src/main/java/org/torproject/android/hsutils/ExternalStorage.java b/app/src/main/java/org/torproject/android/hsutils/ExternalStorage.java new file mode 100644 index 00000000..400f39ae --- /dev/null +++ b/app/src/main/java/org/torproject/android/hsutils/ExternalStorage.java @@ -0,0 +1,42 @@ +package org.torproject.android.hsutils; + +import android.os.Environment; + +import java.io.File; + +public class ExternalStorage { + private final String BACKUPS_DIR = "Orbot-HiddenServices"; + + public String createBackupDir() { + if (!isExternalStorageWritable()) { + return null; + } + + File path = Environment.getExternalStoragePublicDirectory(BACKUPS_DIR); + + if (!path.mkdirs()) { + return null; + } + + return path.getAbsolutePath(); + } + + /* Checks if external storage is available for read and write */ + public boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; + } + + /* Checks if external storage is available to at least read */ + public boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; + } +} diff --git a/app/src/main/java/org/torproject/android/hsutils/HiddenServiceUtils.java b/app/src/main/java/org/torproject/android/hsutils/HiddenServiceUtils.java new file mode 100644 index 00000000..2eb434c9 --- /dev/null +++ b/app/src/main/java/org/torproject/android/hsutils/HiddenServiceUtils.java @@ -0,0 +1,43 @@ +package org.torproject.android.hsutils; + +import android.app.Application; +import android.content.Context; + +import org.torproject.android.service.TorServiceConstants; + +import java.io.File; + +public class HiddenServiceUtils { + private static File appCacheHome; + + public HiddenServiceUtils(Context context) { + appCacheHome = context.getDir(TorServiceConstants.DIRECTORY_TOR_DATA, Application.MODE_PRIVATE); + } + + public String createOnionBackup(Integer port) { + + ExternalStorage storage = new ExternalStorage(); + String storage_path = storage.createBackupDir(); + if (storage_path == null) { + return null; + } + + String zip_path = storage_path + "/hs" + port + ".zip"; + String files[] = { + appCacheHome + "/hs" + port + "/hostname", + appCacheHome + "/hs" + port + "/private_key" + }; + + ZipIt zip = new ZipIt(files, zip_path); + + if (!zip.zip()) { + return null; + } + + return zip_path; + } + + public void restoreOnionBackup(String path) { + + } +} diff --git a/app/src/main/java/org/torproject/android/hsutils/ZipIt.java b/app/src/main/java/org/torproject/android/hsutils/ZipIt.java new file mode 100644 index 00000000..39544ec4 --- /dev/null +++ b/app/src/main/java/org/torproject/android/hsutils/ZipIt.java @@ -0,0 +1,50 @@ +package org.torproject.android.hsutils; + + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipIt { + private static final int BUFFER = 2048; + + private String[] _files; + private String _zipFile; + + public ZipIt(String[] files, String zipFile) { + _files = files; + _zipFile = zipFile; + } + + public boolean zip() { + try { + BufferedInputStream origin = null; + FileOutputStream dest = new FileOutputStream(_zipFile); + + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); + + byte data[] = new byte[BUFFER]; + + for (String _file : _files) { + FileInputStream fi = new FileInputStream(_file); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1)); + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + origin.close(); + } + + out.close(); + } catch (Exception e) { + return false; + } + + return true; + } +} \ No newline at end of file