db-overhaul: fix key export (and some export-related ui changes)

This commit is contained in:
Vincent Breitmoser 2014-04-04 18:49:45 +02:00
parent cf76a8553a
commit d7c2488a0f
8 changed files with 76 additions and 80 deletions

View File

@ -61,8 +61,8 @@ public class ExportHelper {
/** /**
* Show dialog where to export keys * Show dialog where to export keys
*/ */
public void showExportKeysDialog(final long[] masterKeyIds, final int keyType, public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename,
final String exportFilename, final String checkboxString) { final boolean showSecretCheckbox) {
mExportFilename = exportFilename; mExportFilename = exportFilename;
// Message is received after file is selected // Message is received after file is selected
@ -71,14 +71,9 @@ public class ExportHelper {
public void handleMessage(Message message) { public void handleMessage(Message message) {
if (message.what == FileDialogFragment.MESSAGE_OKAY) { if (message.what == FileDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData(); Bundle data = message.getData();
int type = keyType;
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
if (data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)) { exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
type = Id.type.public_secret_key;
}
exportKeys(masterKeyIds, type);
} }
} }
}; };
@ -98,9 +93,11 @@ public class ExportHelper {
} }
String message = mActivity.getString(R.string.specify_file_to_export_to); String message = mActivity.getString(R.string.specify_file_to_export_to);
String checkMsg = showSecretCheckbox ?
mActivity.getString(R.string.also_export_secret_keys) : null;
mFileDialog = FileDialogFragment.newInstance(messenger, title, message, mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
exportFilename, checkboxString); exportFilename, checkMsg);
mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog"); mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
} }
@ -110,7 +107,7 @@ public class ExportHelper {
/** /**
* Export keys * Export keys
*/ */
public void exportKeys(long[] masterKeyIds, int keyType) { public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
Log.d(Constants.TAG, "exportKeys started"); Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread // Send all information needed to service to export key in other thread
@ -122,7 +119,7 @@ public class ExportHelper {
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret);
if (masterKeyIds == null) { if (masterKeyIds == null) {
data.putBoolean(KeychainIntentService.EXPORT_ALL, true); data.putBoolean(KeychainIntentService.EXPORT_ALL, true);

View File

@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.service;
import android.app.IntentService; import android.app.IntentService;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.HkpKeyServer;
@ -147,7 +150,7 @@ public class KeychainIntentService extends IntentService
// export key // export key
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream"; public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
public static final String EXPORT_FILENAME = "export_filename"; public static final String EXPORT_FILENAME = "export_filename";
public static final String EXPORT_KEY_TYPE = "export_key_type"; public static final String EXPORT_SECRET = "export_secret";
public static final String EXPORT_ALL = "export_all"; 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_MASTER_KEY_ID = "export_key_ring_id";
@ -635,19 +638,13 @@ public class KeychainIntentService extends IntentService
} else if (ACTION_EXPORT_KEYRING.equals(action)) { } else if (ACTION_EXPORT_KEYRING.equals(action)) {
try { try {
/* Input */ boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
int keyType = Id.type.public_key;
if (data.containsKey(EXPORT_KEY_TYPE)) {
keyType = data.getInt(EXPORT_KEY_TYPE);
}
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
String outputFile = data.getString(EXPORT_FILENAME); String outputFile = data.getString(EXPORT_FILENAME);
// If not exporting all keys get the masterKeyIds 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); boolean exportAll = data.getBoolean(EXPORT_ALL);
/* Operation */
// check if storage is ready // check if storage is ready
if (!FileHelper.isStorageMounted(outputFile)) { if (!FileHelper.isStorageMounted(outputFile)) {
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready)); throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
@ -655,31 +652,30 @@ public class KeychainIntentService extends IntentService
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>(); ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>(); ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
// TODO redo
ArrayList<Long> allPublicMasterKeyIds = null; // ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
ArrayList<Long> allSecretMasterKeyIds = null; // ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
if (exportAll) { String selection = null;
// get all public key ring MasterKey ids if(!exportAll) {
if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) { selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( ";
publicMasterKeyIds = allPublicMasterKeyIds; for(long l : masterKeyIds) {
selection += Long.toString(l) + ",";
} }
// get all secret key ring MasterKey ids selection = selection.substring(0, selection.length()-1) + " )";
if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) { }
secretMasterKeyIds = allSecretMasterKeyIds;
}
} else {
for (long masterKeyId : masterKeyIds) { Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key) new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET },
&& allPublicMasterKeyIds.contains(masterKeyId)) { selection, null, null);
publicMasterKeyIds.add(masterKeyId); try {
} cursor.moveToFirst();
if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) do {
&& allSecretMasterKeyIds.contains(masterKeyId)) { // export public either way
secretMasterKeyIds.add(masterKeyId); publicMasterKeyIds.add(cursor.getLong(0));
} // add secret if available (and requested)
} if(exportSecret && cursor.getInt(1) != 0)
secretMasterKeyIds.add(cursor.getLong(0));
} while(cursor.moveToNext());
} finally {
cursor.close();
} }
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);

View File

@ -339,9 +339,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show(); Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
} else { } else {
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
long[] ids = new long[]{masterKeyId}; mExportHelper.showExportKeysDialog(
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, new long[] { masterKeyId }, Constants.Path.APP_DIR_FILE_SEC, true);
null);
return true; return true;
} }
return true; return true;

View File

@ -23,7 +23,6 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.helper.ExportHelper;
@ -55,26 +54,20 @@ public class KeyListActivity extends DrawerActivity {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_key_list_import: case R.id.menu_key_list_import:
callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS); callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
return true; return true;
case R.id.menu_key_list_create: case R.id.menu_key_list_create:
createKey(); createKey();
return true; return true;
case R.id.menu_key_list_create_expert: case R.id.menu_key_list_create_expert:
createKeyExpert(); createKeyExpert();
return true; return true;
case R.id.menu_key_list_export_public:
mExportHelper.showExportKeysDialog(null,
Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
case R.id.menu_key_list_export:
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE_PUB, true);
return true; return true;
case R.id.menu_key_list_secret_export:
mExportHelper.showExportKeysDialog(null, Id.type.secret_key,
Constants.Path.APP_DIR_FILE_SEC, null);
return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }

View File

@ -60,7 +60,6 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter; import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@ -68,7 +67,6 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
/** /**
@ -194,10 +192,8 @@ public class KeyListFragment extends Fragment
case R.id.menu_key_list_multi_export: { case R.id.menu_key_list_multi_export: {
ids = mAdapter.getCurrentSelectedMasterKeyIds(); ids = mAdapter.getCurrentSelectedMasterKeyIds();
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
mExportHelper mExportHelper.showExportKeysDialog(
.showExportKeysDialog(ids, Id.type.public_key, ids, Constants.Path.APP_DIR_FILE_PUB, mAdapter.isAnySecretSelected());
Constants.Path.APP_DIR_FILE_PUB,
getString(R.string.also_export_secret_keys));
break; break;
} }
case R.id.menu_key_list_multi_select_all: { case R.id.menu_key_list_multi_select_all: {
@ -525,6 +521,13 @@ public class KeyListFragment extends Fragment
} }
public boolean isSecretAvailable(int id) {
if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id);
}
return mCursor.getInt(INDEX_HAS_SECRET) != 0;
}
public long getMasterKeyId(int id) { public long getMasterKeyId(int id) {
if (!mCursor.moveToPosition(id)) { if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id); throw new IllegalStateException("couldn't move cursor to position " + id);
@ -633,6 +636,14 @@ public class KeyListFragment extends Fragment
notifyDataSetChanged(); notifyDataSetChanged();
} }
public boolean isAnySecretSelected() {
for (int pos : mSelection.keySet()) {
if(mAdapter.isSecretAvailable(pos))
return true;
}
return false;
}
public long[] getCurrentSelectedMasterKeyIds() { public long[] getCurrentSelectedMasterKeyIds() {
long[] ids = new long[mSelection.size()]; long[] ids = new long[mSelection.size()];
int i = 0; int i = 0;

View File

@ -42,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
@ -120,10 +119,12 @@ public class ViewKeyActivity extends ActionBarActivity {
uploadToKeyserver(mDataUri); uploadToKeyserver(mDataUri);
return true; return true;
case R.id.menu_key_view_export_file: case R.id.menu_key_view_export_file:
long masterKeyId = Long.valueOf(mDataUri.getLastPathSegment()); long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
long[] ids = new long[]{masterKeyId}; mExportHelper.showExportKeysDialog(
mExportHelper.showExportKeysDialog(ids, Id.type.public_key, new long[] { masterKeyId } , Constants.Path.APP_DIR_FILE_PUB,
Constants.Path.APP_DIR_FILE_PUB, null); // TODO this doesn't work?
((ViewKeyMainFragment) mTabsAdapter.getItem(0)).isSecretAvailable()
);
return true; return true;
case R.id.menu_key_view_share_default_fingerprint: case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true); shareKey(mDataUri, true);

View File

@ -81,6 +81,9 @@ public class ViewKeyMainFragment extends Fragment implements
private Uri mDataUri; private Uri mDataUri;
// for activity
private boolean mSecretAvailable = false;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
@ -227,9 +230,9 @@ public class ViewKeyMainFragment extends Fragment implements
mEmail.setText(mainUserId[1]); mEmail.setText(mainUserId[1]);
mComment.setText(mainUserId[2]); mComment.setText(mainUserId[2]);
if (data.getInt(INDEX_UNIFIED_HAS_SECRET) > 0) { if (data.getInt(INDEX_UNIFIED_HAS_SECRET) != 0) {
// set this attribute. this is a LITTLE unclean, but we have the info available mSecretAvailable = true;
// right here, so why not.
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
mSecretKey.setText(R.string.secret_key_yes); mSecretKey.setText(R.string.secret_key_yes);
@ -244,6 +247,8 @@ public class ViewKeyMainFragment extends Fragment implements
} }
}); });
} else { } else {
mSecretAvailable = false;
mSecretKey.setTextColor(Color.BLACK); mSecretKey.setTextColor(Color.BLACK);
mSecretKey.setText(getResources().getString(R.string.secret_key_no)); mSecretKey.setText(getResources().getString(R.string.secret_key_no));
@ -332,6 +337,11 @@ public class ViewKeyMainFragment extends Fragment implements
} }
} }
/** Returns true if the key current displayed is known to have a secret key. */
public boolean isSecretAvailable() {
return mSecretAvailable;
}
private void encryptToContact(Uri dataUri) { private void encryptToContact(Uri dataUri) {
// TODO preselect from uri? should be feasible without trivial query // TODO preselect from uri? should be feasible without trivial query
long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);

View File

@ -38,17 +38,6 @@
app:showAsAction="ifRoom|withText" app:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_action_import_export" android:icon="@drawable/ic_action_import_export"
android:title="@string/menu_export_keys"> android:title="@string/menu_export_keys">
<menu>
<item
android:id="@+id/menu_key_list_export_public"
app:showAsAction="never"
android:title="@string/menu_export_public_keys" />
<item
android:id="@+id/menu_key_list_secret_export"
app:showAsAction="never"
android:title="@string/menu_export_secret_keys" />
</menu>
</item> </item>
</menu> </menu>