tor-android/app/src/main/java/org/torproject/android/ui/hiddenservices/backup/BackupUtils.java

337 lines
12 KiB
Java

package org.torproject.android.ui.hiddenservices.backup;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.widget.Toast;
import org.json.JSONException;
import org.json.JSONObject;
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.hiddenservices.storage.ExternalStorage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
public class BackupUtils {
private final String configFileName = "config.json";
private Context mContext;
private ContentResolver mResolver;
public BackupUtils(Context context) {
mContext = context;
mResolver = mContext.getContentResolver();
}
public String createZipBackup(Integer port) {
File mHSBasePath = new File(
mContext.getFilesDir().getAbsolutePath(),
TorServiceConstants.HIDDEN_SERVICES_DIR
);
String configFilePath = mHSBasePath + "/hs" + port + "/" + configFileName;
String hostnameFilePath = mHSBasePath + "/hs" + port + "/hostname";
String keyFilePath = mHSBasePath + "/hs" + port + "/private_key";
File storage_path = ExternalStorage.getOrCreateBackupDir();
if (storage_path == null)
return null;
Cursor portData = mResolver.query(
HSContentProvider.CONTENT_URI,
HSContentProvider.PROJECTION,
HSContentProvider.HiddenService.PORT + "=" + port,
null,
null
);
JSONObject config = new JSONObject();
try {
if (portData == null || portData.getCount() != 1)
return null;
portData.moveToNext();
config.put(
HSContentProvider.HiddenService.NAME,
portData.getString(portData.getColumnIndex(HSContentProvider.HiddenService.NAME))
);
config.put(
HSContentProvider.HiddenService.PORT,
portData.getInt(portData.getColumnIndex(HSContentProvider.HiddenService.PORT))
);
config.put(
HSContentProvider.HiddenService.ONION_PORT,
portData.getInt(portData.getColumnIndex(HSContentProvider.HiddenService.ONION_PORT))
);
config.put(
HSContentProvider.HiddenService.DOMAIN,
portData.getString(portData.getColumnIndex(HSContentProvider.HiddenService.DOMAIN))
);
config.put(
HSContentProvider.HiddenService.AUTH_COOKIE,
portData.getInt(portData.getColumnIndex(HSContentProvider.HiddenService.AUTH_COOKIE))
);
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) {
e.printStackTrace();
return null;
}
portData.close();
try {
FileWriter file = new FileWriter(configFilePath);
file.write(config.toString());
file.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
String zip_path = storage_path.getAbsolutePath() + "/hs" + port + ".zip";
String files[] = {hostnameFilePath, keyFilePath, configFilePath};
ZipIt zip = new ZipIt(files, zip_path);
if (!zip.zip())
return null;
return zip_path;
}
public void restoreZipBackup(File backup) {
File mHSBasePath = new File(
mContext.getFilesDir().getAbsolutePath(),
TorServiceConstants.HIDDEN_SERVICES_DIR
);
int port;
Cursor service;
String backupName = backup.getName();
String hsDir = backupName.substring(0, backupName.lastIndexOf('.'));
String configFilePath = mHSBasePath + "/" + hsDir + "/" + configFileName;
String jString = null;
File hsPath = new File(mHSBasePath.getAbsolutePath(), hsDir);
if (!hsPath.isDirectory())
hsPath.mkdirs();
ZipIt zip = new ZipIt(null, backup.getAbsolutePath());
zip.unzip(hsPath.getAbsolutePath());
File config = new File(configFilePath);
FileInputStream stream;
try {
stream = new FileInputStream(config);
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
jString = Charset.defaultCharset().decode(bb).toString();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (jString == null)
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
try {
JSONObject savedValues = new JSONObject(jString);
ContentValues fields = new ContentValues();
fields.put(
HSContentProvider.HiddenService.NAME,
savedValues.getString(HSContentProvider.HiddenService.NAME)
);
fields.put(
HSContentProvider.HiddenService.ONION_PORT,
savedValues.getInt(HSContentProvider.HiddenService.ONION_PORT)
);
fields.put(
HSContentProvider.HiddenService.DOMAIN,
savedValues.getString(HSContentProvider.HiddenService.DOMAIN)
);
fields.put(
HSContentProvider.HiddenService.AUTH_COOKIE,
savedValues.getInt(HSContentProvider.HiddenService.AUTH_COOKIE)
);
fields.put(
HSContentProvider.HiddenService.CREATED_BY_USER,
savedValues.getInt(HSContentProvider.HiddenService.CREATED_BY_USER)
);
fields.put(
HSContentProvider.HiddenService.ENABLED,
savedValues.getInt(HSContentProvider.HiddenService.ENABLED)
);
port = savedValues.getInt(HSContentProvider.HiddenService.PORT);
fields.put(HSContentProvider.HiddenService.PORT, port);
service = mResolver.query(
HSContentProvider.CONTENT_URI,
HSContentProvider.PROJECTION,
HSContentProvider.HiddenService.PORT + "=" + port,
null,
null
);
if (service == null || service.getCount() == 0) {
mResolver.insert(HSContentProvider.CONTENT_URI, fields);
} else {
mResolver.update(
HSContentProvider.CONTENT_URI,
fields,
HSContentProvider.HiddenService.PORT + "=" + port,
null
);
service.close();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
}
Toast.makeText(mContext, R.string.backup_restored, Toast.LENGTH_LONG).show();
}
public void restoreKeyBackup(int hsPort, Uri hsKeyPath) {
File mHSBasePath = new File(
mContext.getFilesDir().getAbsolutePath(),
TorServiceConstants.HIDDEN_SERVICES_DIR
);
File serviceDir = new File(mHSBasePath, "hs" + hsPort);
if (!serviceDir.isDirectory())
serviceDir.mkdirs();
try {
ParcelFileDescriptor mInputPFD = mContext.getContentResolver().openFileDescriptor(hsKeyPath, "r");
InputStream fileStream = new FileInputStream(mInputPFD.getFileDescriptor());
OutputStream file = new FileOutputStream(serviceDir.getAbsolutePath() + "/private_key");
byte[] buffer = new byte[1024];
int length;
while ((length = fileStream.read(buffer)) > 0) {
file.write(buffer, 0, length);
}
file.close();
} catch (IOException | NullPointerException e) {
e.printStackTrace();
}
}
public void restoreCookieBackup(File p) {
File config = new File(p.getAbsolutePath());
FileInputStream stream;
String jString = null;
try {
stream = new FileInputStream(config);
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
jString = Charset.defaultCharset().decode(bb).toString();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (jString == null)
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
try {
JSONObject savedValues = new JSONObject(jString);
ContentValues fields = new ContentValues();
fields.put(
CookieContentProvider.ClientCookie.DOMAIN,
savedValues.getString(CookieContentProvider.ClientCookie.DOMAIN)
);
fields.put(
CookieContentProvider.ClientCookie.AUTH_COOKIE_VALUE,
savedValues.getString(CookieContentProvider.ClientCookie.AUTH_COOKIE_VALUE)
);
fields.put(
CookieContentProvider.ClientCookie.ENABLED,
savedValues.getInt(CookieContentProvider.ClientCookie.ENABLED)
);
mResolver.insert(CookieContentProvider.CONTENT_URI, fields);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(mContext, R.string.error, Toast.LENGTH_LONG).show();
}
Toast.makeText(mContext, R.string.backup_restored, Toast.LENGTH_LONG).show();
}
public String createCookieBackup(String domain, String cookie, Integer enabled) {
File storage_path = ExternalStorage.getOrCreateBackupDir();
String backupFile = storage_path.getAbsolutePath() + '/' + domain.replace(".onion", ".json");
JSONObject backup = new JSONObject();
try {
backup.put(CookieContentProvider.ClientCookie.DOMAIN, domain);
backup.put(CookieContentProvider.ClientCookie.AUTH_COOKIE_VALUE, cookie);
backup.put(CookieContentProvider.ClientCookie.ENABLED, enabled);
FileWriter file = new FileWriter(backupFile);
file.write(backup.toString());
file.close();
} catch (JSONException | IOException e) {
e.printStackTrace();
return null;
}
return backupFile;
}
}