Fix export for new unified key list #409

This commit is contained in:
uberspot 2014-03-15 01:51:01 +02:00
parent efab1d27ac
commit e387dd7c54
9 changed files with 113 additions and 80 deletions

View File

@ -119,6 +119,7 @@ public final class Id {
public static final int secret_key = 0x21070002;
public static final int user_id = 0x21070003;
public static final int key = 0x21070004;
public static final int public_secret_key = 0x21070005;
}
public static final class choice {

View File

@ -30,12 +30,18 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.lang.reflect.Array;
import java.security.Provider;
import java.util.ArrayList;
public class ExportHelper {
protected FileDialogFragment mFileDialog;
protected String mExportFilename;
@ -62,8 +68,8 @@ public class ExportHelper {
/**
* Show dialog where to export keys
*/
public void showExportKeysDialog(final long[] rowIds, final int keyType,
final String exportFilename) {
public void showExportKeysDialog(final long[] masterKeyIds, final int keyType,
final String exportFilename, final String checkboxString) {
mExportFilename = exportFilename;
// Message is received after file is selected
@ -72,9 +78,14 @@ public class ExportHelper {
public void handleMessage(Message message) {
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData();
int type = keyType;
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
exportKeys(rowIds, keyType);
if( data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED) ) {
type = Id.type.public_secret_key;
}
exportKeys(masterKeyIds, type);
}
}
};
@ -85,7 +96,7 @@ public class ExportHelper {
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
public void run() {
String title = null;
if (rowIds == null) {
if (masterKeyIds == null) {
// export all keys
title = mActivity.getString(R.string.title_export_keys);
} else {
@ -93,15 +104,10 @@ public class ExportHelper {
title = mActivity.getString(R.string.title_export_key);
}
String message = null;
if (keyType == Id.type.public_key) {
message = mActivity.getString(R.string.specify_file_to_export_to);
} else {
message = mActivity.getString(R.string.specify_file_to_export_secret_keys_to);
}
String message = mActivity.getString(R.string.specify_file_to_export_to);
mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
exportFilename, null);
exportFilename, checkboxString);
mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
}
@ -111,7 +117,7 @@ public class ExportHelper {
/**
* Export keys
*/
public void exportKeys(long[] rowIds, int keyType) {
public void exportKeys(long[] masterKeyIds, int keyType) {
Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread
@ -125,10 +131,10 @@ public class ExportHelper {
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType);
if (rowIds == null) {
if (masterKeyIds == null) {
data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
} else {
data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_ROW_ID, rowIds);
data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, masterKeyIds);
}
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

View File

@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.Provider;
import java.util.ArrayList;
import java.util.List;
@ -158,60 +159,68 @@ public class PgpImportExport {
return returnData;
}
public Bundle exportKeyRings(ArrayList<Long> keyRingRowIds, int keyType,
public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds, ArrayList<Long> secretKeyRingMasterIds,
OutputStream outStream) throws PgpGeneralException,
PGPException, IOException {
Bundle returnData = new Bundle();
int rowIdsSize = keyRingRowIds.size();
int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size();
int progress = 0;
updateProgress(
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
rowIdsSize), 0, 100);
masterKeyIdsSize), 0, 100);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new PgpGeneralException(
mContext.getString(R.string.error_external_storage_not_ready));
}
// For each row id
for (int i = 0; i < rowIdsSize; ++i) {
// For each public masterKey id
for (long pubKeyMasterId : publicKeyRingMasterIds) {
progress++;
// Create an output stream
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
// If the keyType is secret get the PGPSecretKeyRing
// based on the row id and encode it to the output
if (keyType == Id.type.secret_key) {
updateProgress(i * 100 / rowIdsSize / 2, 100);
PGPSecretKeyRing secretKeyRing =
ProviderHelper.getPGPSecretKeyRingByRowId(mContext, keyRingRowIds.get(i));
updateProgress(progress * 100 / masterKeyIdsSize, 100);
PGPPublicKeyRing publicKeyRing =
ProviderHelper.getPGPPublicKeyRingByMasterKeyId(mContext, pubKeyMasterId);
if (secretKeyRing != null) {
secretKeyRing.encode(arOutStream);
}
if (mKeychainServiceListener.hasServiceStopped()) {
arOutStream.close();
return null;
}
} else {
updateProgress(i * 100 / rowIdsSize, 100);
PGPPublicKeyRing publicKeyRing =
ProviderHelper.getPGPPublicKeyRingByRowId(mContext, keyRingRowIds.get(i));
if (publicKeyRing != null) {
publicKeyRing.encode(arOutStream);
}
if (publicKeyRing != null) {
publicKeyRing.encode(arOutStream);
}
if (mKeychainServiceListener.hasServiceStopped()) {
arOutStream.close();
return null;
}
if (mKeychainServiceListener.hasServiceStopped()) {
arOutStream.close();
return null;
}
arOutStream.close();
}
returnData.putInt(KeychainIntentService.RESULT_EXPORT, rowIdsSize);
// For each secret masterKey id
for (long secretKeyMasterId : secretKeyRingMasterIds) {
progress++;
// Create an output stream
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
updateProgress(progress * 100 / masterKeyIdsSize, 100);
PGPSecretKeyRing secretKeyRing =
ProviderHelper.getPGPSecretKeyRingByMasterKeyId(mContext, secretKeyMasterId);
if (secretKeyRing != null) {
secretKeyRing.encode(arOutStream);
}
if (mKeychainServiceListener.hasServiceStopped()) {
arOutStream.close();
return null;
}
arOutStream.close();
}
returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize);
updateProgress(R.string.progress_done, 100, 100);

View File

@ -131,7 +131,6 @@ public class KeychainIntentService extends IntentService
public static final String EXPORT_KEY_TYPE = "export_key_type";
public static final String EXPORT_ALL = "export_all";
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
public static final String EXPORT_KEY_RING_ROW_ID = "export_key_rind_row_id";
// upload key
public static final String UPLOAD_KEY_SERVER = "upload_key_server";
@ -660,16 +659,11 @@ public class KeychainIntentService extends IntentService
if (data.containsKey(EXPORT_KEY_TYPE)) {
keyType = data.getInt(EXPORT_KEY_TYPE);
}
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
String outputFile = data.getString(EXPORT_FILENAME);
long[] rowIds = new long[0];
// If not exporting all keys get the rowIds of the keys to export from the intent
// If not exporting all keys get the masterKeyIds of the keys to export from the intent
boolean exportAll = data.getBoolean(EXPORT_ALL);
if (!exportAll) {
rowIds = data.getLongArray(EXPORT_KEY_RING_ROW_ID);
}
/* Operation */
@ -678,30 +672,38 @@ public class KeychainIntentService extends IntentService
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
}
// OutputStream
FileOutputStream outStream = new FileOutputStream(outputFile);
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
ArrayList<Long> allPublicMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
ArrayList<Long> allSecretMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
ArrayList<Long> keyRingRowIds = new ArrayList<Long>();
if (exportAll) {
// get all key ring row ids based on export type
if (keyType == Id.type.public_key) {
keyRingRowIds = ProviderHelper.getPublicKeyRingsRowIds(this);
} else {
keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this);
// get all public key ring MasterKey ids
if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) {
publicMasterKeyIds = allPublicMasterKeyIds;
}
// get all secret key ring MasterKey ids
if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) {
secretMasterKeyIds = allSecretMasterKeyIds;
}
} else {
for (long rowId : rowIds) {
keyRingRowIds.add(rowId);
for (long masterKeyId : masterKeyIds) {
if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key)
&& allPublicMasterKeyIds.contains(masterKeyId)) {
publicMasterKeyIds.add(masterKeyId);
}
if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key)
&& allSecretMasterKeyIds.contains(masterKeyId)) {
secretMasterKeyIds.add(masterKeyId);
}
}
}
Bundle resultData;
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
resultData = pgpImportExport
.exportKeyRings(keyRingRowIds, keyType, outStream);
Bundle resultData = pgpImportExport
.exportKeyRings(publicMasterKeyIds, secretMasterKeyIds,
new FileOutputStream(outputFile));
if (mIsCanceled) {
boolean isDeleted = new File(outputFile).delete();

View File

@ -322,8 +322,10 @@ public class EditKeyActivity extends ActionBarActivity {
cancelClicked();
return true;
case R.id.menu_key_edit_export_file:
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC);
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
long[] ids = new long[]{masterKeyId};
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
null);
return true;
case R.id.menu_key_edit_delete: {
// Message is received after key is deleted

View File

@ -58,8 +58,7 @@ public class KeyListActivity extends DrawerActivity {
return true;
case R.id.menu_key_list_export:
// TODO fix this for unified keylist
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB);
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
return true;
case R.id.menu_key_list_create:
@ -71,7 +70,7 @@ public class KeyListActivity extends DrawerActivity {
return true;
case R.id.menu_key_list_secret_export:
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC);
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, null);
return true;
default:

View File

@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
@ -183,13 +184,22 @@ public class KeyListFragment extends Fragment
break;
}
case R.id.menu_key_list_multi_export: {
// todo: public/secret needs to be handled differently here
ids = mStickyList.getWrappedList().getCheckedItemIds();
long[] masterKeyIds = new long[2*ids.length];
ArrayList<Long> allPubRowIds =
ProviderHelper.getPublicKeyRingsRowIds(getActivity());
for (int i = 0; i < ids.length; i++) {
if (allPubRowIds.contains(ids[i])) {
masterKeyIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]);
} else {
masterKeyIds[i] = ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]);
}
}
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
mExportHelper
.showExportKeysDialog(ids,
Id.type.public_key,
Constants.Path.APP_DIR_FILE_PUB);
.showExportKeysDialog(masterKeyIds, Id.type.public_key,
Constants.Path.APP_DIR_FILE_PUB,
getString(R.string.also_export_secret_keys));
break;
}
case R.id.menu_key_list_multi_select_all: {

View File

@ -124,8 +124,11 @@ public class ViewKeyActivity extends ActionBarActivity {
uploadToKeyserver(mDataUri);
return true;
case R.id.menu_key_view_export_file:
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB);
long masterKeyId =
ProviderHelper.getPublicMasterKeyId(this, Long.valueOf(mDataUri.getLastPathSegment()));
long[] ids = new long[]{masterKeyId};
mExportHelper.showExportKeysDialog(ids, Id.type.public_key,
Constants.Path.APP_DIR_FILE_PUB, null);
return true;
case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true);

View File

@ -219,6 +219,7 @@
<string name="key_deletion_confirmation">Do you really want to delete the key \'%s\'?\nYou can\'t undo this!</string>
<string name="key_deletion_confirmation_multi">Do you really want to delete all selected keys?\nYou can\'t undo this!</string>
<string name="secret_key_deletion_confirmation">Do you really want to delete the SECRET key \'%s\'?\nYou can\'t undo this!</string>
<string name="also_export_secret_keys">Also export secret keys?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">Successfully added %d key</item>