From 53680b621320512b44e961f0453043a31c40dfee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 15 Oct 2015 21:48:01 +0200 Subject: Cleanup, fix advanced sharing --- .../keychain/operations/BackupOperation.java | 312 +++++++++++++++++++++ .../keychain/operations/ExportOperation.java | 312 --------------------- .../keychain/service/BackupKeyringParcel.java | 78 ++++++ .../keychain/service/ExportKeyringParcel.java | 79 ------ .../keychain/service/KeychainService.java | 6 +- .../keychain/ui/BackupCodeFragment.java | 8 +- .../keychain/ui/ViewKeyActivity.java | 6 +- .../keychain/ui/ViewKeyAdvActivity.java | 3 - .../keychain/ui/ViewKeyAdvShareFragment.java | 127 +++++---- .../keychain/util/ExportHelper.java | 125 --------- .../res/layout/view_key_adv_share_fragment.xml | 17 -- OpenKeychain/src/main/res/values/strings.xml | 4 +- .../keychain/operations/ExportTest.java | 12 +- 13 files changed, 476 insertions(+), 613 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java new file mode 100644 index 000000000..8f383cd3a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2010-2014 Thialfihar + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.operations; + + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; +import org.sufficientlysecure.keychain.service.BackupKeyringParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.Log; + + +/** + * An operation class which implements high level export + * operations. + * This class receives a source and/or destination of keys as input and performs + * all steps for this export. + * + * @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries() + * For the export operation, the input consists of a set of key ids and + * either the name of a file or an output uri to write to. + */ +public class BackupOperation extends BaseOperation { + + private static final String[] PROJECTION = new String[] { + KeyRings.MASTER_KEY_ID, + KeyRings.PUBKEY_DATA, + KeyRings.PRIVKEY_DATA, + KeyRings.HAS_ANY_SECRET + }; + private static final int INDEX_MASTER_KEY_ID = 0; + private static final int INDEX_PUBKEY_DATA = 1; + private static final int INDEX_SECKEY_DATA = 2; + private static final int INDEX_HAS_ANY_SECRET = 3; + + public BackupOperation(Context context, ProviderHelper providerHelper, Progressable + progressable) { + super(context, providerHelper, progressable); + } + + public BackupOperation(Context context, ProviderHelper providerHelper, + Progressable progressable, AtomicBoolean cancelled) { + super(context, providerHelper, progressable, cancelled); + } + + @NonNull + public ExportResult execute(@NonNull BackupKeyringParcel exportInput, @Nullable CryptoInputParcel cryptoInput) { + + OperationLog log = new OperationLog(); + if (exportInput.mMasterKeyIds != null) { + log.add(LogType.MSG_EXPORT, 0, exportInput.mMasterKeyIds.length); + } else { + log.add(LogType.MSG_EXPORT_ALL, 0); + } + + try { + + boolean nonEncryptedOutput = exportInput.mSymmetricPassphrase == null; + + Uri exportOutputUri = nonEncryptedOutput + ? exportInput.mOutputUri + : TemporaryFileProvider.createFile(mContext); + + int exportedDataSize; + + { // export key data, and possibly return if we don't encrypt + + DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream( + mContext.getContentResolver().openOutputStream(exportOutputUri))); + + boolean exportSuccess = exportKeysToStream( + log, exportInput.mMasterKeyIds, exportInput.mExportSecret, outStream); + + exportedDataSize = outStream.size(); + + if (!exportSuccess) { + // if there was an error, it will be in the log so we just have to return + return new ExportResult(ExportResult.RESULT_ERROR, log); + } + + if (nonEncryptedOutput) { + // log.add(LogType.MSG_EXPORT_NO_ENCRYPT, 1); + log.add(LogType.MSG_EXPORT_SUCCESS, 1); + return new ExportResult(ExportResult.RESULT_OK, log); + } + } + + PgpSignEncryptOperation pseOp = new PgpSignEncryptOperation(mContext, mProviderHelper, mProgressable, mCancelled); + + PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(); + inputParcel.setSymmetricPassphrase(exportInput.mSymmetricPassphrase); + inputParcel.setEnableAsciiArmorOutput(true); + + InputStream inStream = mContext.getContentResolver().openInputStream(exportOutputUri); + + String filename; + if (exportInput.mMasterKeyIds != null && exportInput.mMasterKeyIds.length == 1) { + filename = "backup_" + KeyFormattingUtils.convertKeyIdToHex(exportInput.mMasterKeyIds[0]); + filename += exportInput.mExportSecret ? ".sec.asc" : ".pub.asc"; + } else { + filename = "backup_" + new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); + filename += exportInput.mExportSecret ? ".asc" : ".pub.asc"; + } + + InputData inputData = new InputData(inStream, exportedDataSize, filename); + + OutputStream outStream = mContext.getContentResolver().openOutputStream(exportInput.mOutputUri); + outStream = new BufferedOutputStream(outStream); + + PgpSignEncryptResult encryptResult = pseOp.execute(inputParcel, new CryptoInputParcel(), inputData, outStream); + if (!encryptResult.success()) { + log.addByMerge(encryptResult, 1); + // log.add(LogType.MSG_EXPORT_ERROR_ENCRYPT, 1); + return new ExportResult(ExportResult.RESULT_ERROR, log); + } + + log.add(encryptResult, 1); + log.add(LogType.MSG_EXPORT_SUCCESS, 1); + return new ExportResult(ExportResult.RESULT_OK, log); + + } catch (FileNotFoundException e) { + log.add(LogType.MSG_EXPORT_ERROR_URI_OPEN, 1); + return new ExportResult(ExportResult.RESULT_ERROR, log); + + } + + } + + boolean exportKeysToStream(OperationLog log, long[] masterKeyIds, boolean exportSecret, OutputStream outStream) { + + // noinspection unused TODO use these in a log entry + int okSecret = 0, okPublic = 0; + + int progress = 0; + + Cursor cursor = queryForKeys(masterKeyIds); + + if (cursor == null || !cursor.moveToFirst()) { + log.add(LogType.MSG_EXPORT_ERROR_DB, 1); + return false; // new ExportResult(ExportResult.RESULT_ERROR, log); + } + + try { + + int numKeys = cursor.getCount(); + + updateProgress(mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, numKeys), + 0, numKeys); + + // For each public masterKey id + while (!cursor.isAfterLast()) { + + long keyId = cursor.getLong(INDEX_MASTER_KEY_ID); + log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId)); + + if (writePublicKeyToStream(log, outStream, cursor)) { + okPublic += 1; + + boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0; + if (exportSecret && hasSecret) { + log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId)); + if (writeSecretKeyToStream(log, outStream, cursor)) { + okSecret += 1; + } + } + } + + updateProgress(progress++, numKeys); + cursor.moveToNext(); + } + + updateProgress(R.string.progress_done, numKeys, numKeys); + + } catch (IOException e) { + log.add(LogType.MSG_EXPORT_ERROR_IO, 1); + return false; // new ExportResult(ExportResult.RESULT_ERROR, log); + } finally { + // Make sure the stream is closed + if (outStream != null) try { + outStream.close(); + } catch (Exception e) { + Log.e(Constants.TAG, "error closing stream", e); + } + cursor.close(); + } + + return true; + + } + + private boolean writePublicKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor) + throws IOException { + + ArmoredOutputStream arOutStream = null; + + try { + arOutStream = new ArmoredOutputStream(outStream); + byte[] data = cursor.getBlob(INDEX_PUBKEY_DATA); + CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true); + ring.encode(arOutStream); + + } catch (PgpGeneralException e) { + log.add(LogType.MSG_EXPORT_ERROR_KEY, 2); + } finally { + if (arOutStream != null) { + arOutStream.close(); + } + } + return true; + } + + private boolean writeSecretKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor) + throws IOException { + + ArmoredOutputStream arOutStream = null; + + try { + arOutStream = new ArmoredOutputStream(outStream); + byte[] data = cursor.getBlob(INDEX_SECKEY_DATA); + CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true); + ring.encode(arOutStream); + + } catch (PgpGeneralException e) { + log.add(LogType.MSG_EXPORT_ERROR_KEY, 2); + } finally { + if (arOutStream != null) { + arOutStream.close(); + } + } + return true; + } + + private Cursor queryForKeys(long[] masterKeyIds) { + + String selection = null, selectionArgs[] = null; + + if (masterKeyIds != null) { + // convert long[] to String[] + selectionArgs = new String[masterKeyIds.length]; + for (int i = 0; i < masterKeyIds.length; i++) { + selectionArgs[i] = Long.toString(masterKeyIds[i]); + } + + // generates ?,?,? as placeholders for selectionArgs + String placeholders = TextUtils.join(",", + Collections.nCopies(masterKeyIds.length, "?")); + + // put together selection string + selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + + " IN (" + placeholders + ")"; + } + + return mProviderHelper.getContentResolver().query( + KeyRings.buildUnifiedKeyRingsUri(), PROJECTION, selection, selectionArgs, + Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + ); + + } + +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java deleted file mode 100644 index 5f77a3224..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2010-2014 Thialfihar - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.operations; - - -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; -import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; -import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; -import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; -import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; -import org.sufficientlysecure.keychain.service.ExportKeyringParcel; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; - - -/** - * An operation class which implements high level export - * operations. - * This class receives a source and/or destination of keys as input and performs - * all steps for this export. - * - * @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries() - * For the export operation, the input consists of a set of key ids and - * either the name of a file or an output uri to write to. - */ -public class ExportOperation extends BaseOperation { - - private static final String[] PROJECTION = new String[] { - KeyRings.MASTER_KEY_ID, - KeyRings.PUBKEY_DATA, - KeyRings.PRIVKEY_DATA, - KeyRings.HAS_ANY_SECRET - }; - private static final int INDEX_MASTER_KEY_ID = 0; - private static final int INDEX_PUBKEY_DATA = 1; - private static final int INDEX_SECKEY_DATA = 2; - private static final int INDEX_HAS_ANY_SECRET = 3; - - public ExportOperation(Context context, ProviderHelper providerHelper, Progressable - progressable) { - super(context, providerHelper, progressable); - } - - public ExportOperation(Context context, ProviderHelper providerHelper, - Progressable progressable, AtomicBoolean cancelled) { - super(context, providerHelper, progressable, cancelled); - } - - @NonNull - public ExportResult execute(@NonNull ExportKeyringParcel exportInput, @Nullable CryptoInputParcel cryptoInput) { - - OperationLog log = new OperationLog(); - if (exportInput.mMasterKeyIds != null) { - log.add(LogType.MSG_EXPORT, 0, exportInput.mMasterKeyIds.length); - } else { - log.add(LogType.MSG_EXPORT_ALL, 0); - } - - try { - - boolean nonEncryptedOutput = exportInput.mSymmetricPassphrase == null; - - Uri exportOutputUri = nonEncryptedOutput - ? exportInput.mOutputUri - : TemporaryFileProvider.createFile(mContext); - - int exportedDataSize; - - { // export key data, and possibly return if we don't encrypt - - DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream( - mContext.getContentResolver().openOutputStream(exportOutputUri))); - - boolean exportSuccess = exportKeysToStream( - log, exportInput.mMasterKeyIds, exportInput.mExportSecret, outStream); - - exportedDataSize = outStream.size(); - - if (!exportSuccess) { - // if there was an error, it will be in the log so we just have to return - return new ExportResult(ExportResult.RESULT_ERROR, log); - } - - if (nonEncryptedOutput) { - // log.add(LogType.MSG_EXPORT_NO_ENCRYPT, 1); - log.add(LogType.MSG_EXPORT_SUCCESS, 1); - return new ExportResult(ExportResult.RESULT_OK, log); - } - } - - PgpSignEncryptOperation pseOp = new PgpSignEncryptOperation(mContext, mProviderHelper, mProgressable, mCancelled); - - PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(); - inputParcel.setSymmetricPassphrase(exportInput.mSymmetricPassphrase); - inputParcel.setEnableAsciiArmorOutput(true); - - InputStream inStream = mContext.getContentResolver().openInputStream(exportOutputUri); - - String filename; - if (exportInput.mMasterKeyIds != null && exportInput.mMasterKeyIds.length == 1) { - filename = "backup_" + KeyFormattingUtils.convertKeyIdToHex(exportInput.mMasterKeyIds[0]); - filename += exportInput.mExportSecret ? ".sec.asc" : ".pub.asc"; - } else { - filename = "backup_" + new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); - filename += exportInput.mExportSecret ? ".asc" : ".pub.asc"; - } - - InputData inputData = new InputData(inStream, exportedDataSize, filename); - - OutputStream outStream = mContext.getContentResolver().openOutputStream(exportInput.mOutputUri); - outStream = new BufferedOutputStream(outStream); - - PgpSignEncryptResult encryptResult = pseOp.execute(inputParcel, new CryptoInputParcel(), inputData, outStream); - if (!encryptResult.success()) { - log.addByMerge(encryptResult, 1); - // log.add(LogType.MSG_EXPORT_ERROR_ENCRYPT, 1); - return new ExportResult(ExportResult.RESULT_ERROR, log); - } - - log.add(encryptResult, 1); - log.add(LogType.MSG_EXPORT_SUCCESS, 1); - return new ExportResult(ExportResult.RESULT_OK, log); - - } catch (FileNotFoundException e) { - log.add(LogType.MSG_EXPORT_ERROR_URI_OPEN, 1); - return new ExportResult(ExportResult.RESULT_ERROR, log); - - } - - } - - boolean exportKeysToStream(OperationLog log, long[] masterKeyIds, boolean exportSecret, OutputStream outStream) { - - // noinspection unused TODO use these in a log entry - int okSecret = 0, okPublic = 0; - - int progress = 0; - - Cursor cursor = queryForKeys(masterKeyIds); - - if (cursor == null || !cursor.moveToFirst()) { - log.add(LogType.MSG_EXPORT_ERROR_DB, 1); - return false; // new ExportResult(ExportResult.RESULT_ERROR, log); - } - - try { - - int numKeys = cursor.getCount(); - - updateProgress(mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, numKeys), - 0, numKeys); - - // For each public masterKey id - while (!cursor.isAfterLast()) { - - long keyId = cursor.getLong(INDEX_MASTER_KEY_ID); - log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId)); - - if (writePublicKeyToStream(log, outStream, cursor)) { - okPublic += 1; - - boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0; - if (exportSecret && hasSecret) { - log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId)); - if (writeSecretKeyToStream(log, outStream, cursor)) { - okSecret += 1; - } - } - } - - updateProgress(progress++, numKeys); - cursor.moveToNext(); - } - - updateProgress(R.string.progress_done, numKeys, numKeys); - - } catch (IOException e) { - log.add(LogType.MSG_EXPORT_ERROR_IO, 1); - return false; // new ExportResult(ExportResult.RESULT_ERROR, log); - } finally { - // Make sure the stream is closed - if (outStream != null) try { - outStream.close(); - } catch (Exception e) { - Log.e(Constants.TAG, "error closing stream", e); - } - cursor.close(); - } - - return true; - - } - - private boolean writePublicKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor) - throws IOException { - - ArmoredOutputStream arOutStream = null; - - try { - arOutStream = new ArmoredOutputStream(outStream); - byte[] data = cursor.getBlob(INDEX_PUBKEY_DATA); - CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true); - ring.encode(arOutStream); - - } catch (PgpGeneralException e) { - log.add(LogType.MSG_EXPORT_ERROR_KEY, 2); - } finally { - if (arOutStream != null) { - arOutStream.close(); - } - } - return true; - } - - private boolean writeSecretKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor) - throws IOException { - - ArmoredOutputStream arOutStream = null; - - try { - arOutStream = new ArmoredOutputStream(outStream); - byte[] data = cursor.getBlob(INDEX_SECKEY_DATA); - CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true); - ring.encode(arOutStream); - - } catch (PgpGeneralException e) { - log.add(LogType.MSG_EXPORT_ERROR_KEY, 2); - } finally { - if (arOutStream != null) { - arOutStream.close(); - } - } - return true; - } - - private Cursor queryForKeys(long[] masterKeyIds) { - - String selection = null, selectionArgs[] = null; - - if (masterKeyIds != null) { - // convert long[] to String[] - selectionArgs = new String[masterKeyIds.length]; - for (int i = 0; i < masterKeyIds.length; i++) { - selectionArgs[i] = Long.toString(masterKeyIds[i]); - } - - // generates ?,?,? as placeholders for selectionArgs - String placeholders = TextUtils.join(",", - Collections.nCopies(masterKeyIds.length, "?")); - - // put together selection string - selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID - + " IN (" + placeholders + ")"; - } - - return mProviderHelper.getContentResolver().query( - KeyRings.buildUnifiedKeyRingsUri(), PROJECTION, selection, selectionArgs, - Tables.KEYS + "." + KeyRings.MASTER_KEY_ID - ); - - } - -} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java new file mode 100644 index 000000000..3d9626934 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.service; + +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +import org.sufficientlysecure.keychain.util.Passphrase; + + +public class BackupKeyringParcel implements Parcelable { + public Uri mCanonicalizedPublicKeyringUri; + public Passphrase mSymmetricPassphrase; + + public boolean mExportSecret; + public long mMasterKeyIds[]; + public Uri mOutputUri; + + public BackupKeyringParcel(Passphrase symmetricPassphrase, + long[] masterKeyIds, boolean exportSecret, Uri outputUri) { + mSymmetricPassphrase = symmetricPassphrase; + mMasterKeyIds = masterKeyIds; + mExportSecret = exportSecret; + mOutputUri = outputUri; + } + + protected BackupKeyringParcel(Parcel in) { + mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader()); + mExportSecret = in.readByte() != 0x00; + mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader()); + mMasterKeyIds = in.createLongArray(); + mSymmetricPassphrase = in.readParcelable(getClass().getClassLoader()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeValue(mCanonicalizedPublicKeyringUri); + dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00)); + dest.writeValue(mOutputUri); + dest.writeLongArray(mMasterKeyIds); + dest.writeParcelable(mSymmetricPassphrase, 0); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public BackupKeyringParcel createFromParcel(Parcel in) { + return new BackupKeyringParcel(in); + } + + @Override + public BackupKeyringParcel[] newArray(int size) { + return new BackupKeyringParcel[size]; + } + }; +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java deleted file mode 100644 index 9b0e5573e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * Copyright (C) 2015 Vincent Breitmoser - * Copyright (C) 2015 Adithya Abraham Philip - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.service; - -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; - -import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.util.Passphrase; - - -public class ExportKeyringParcel implements Parcelable { - public Uri mCanonicalizedPublicKeyringUri; - public Passphrase mSymmetricPassphrase; - - public boolean mExportSecret; - public long mMasterKeyIds[]; - public Uri mOutputUri; - - public ExportKeyringParcel(Passphrase symmetricPassphrase, - long[] masterKeyIds, boolean exportSecret, Uri outputUri) { - mSymmetricPassphrase = symmetricPassphrase; - mMasterKeyIds = masterKeyIds; - mExportSecret = exportSecret; - mOutputUri = outputUri; - } - - protected ExportKeyringParcel(Parcel in) { - mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader()); - mExportSecret = in.readByte() != 0x00; - mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader()); - mMasterKeyIds = in.createLongArray(); - mSymmetricPassphrase = in.readParcelable(getClass().getClassLoader()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeValue(mCanonicalizedPublicKeyringUri); - dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00)); - dest.writeValue(mOutputUri); - dest.writeLongArray(mMasterKeyIds); - dest.writeParcelable(mSymmetricPassphrase, 0); - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public ExportKeyringParcel createFromParcel(Parcel in) { - return new ExportKeyringParcel(in); - } - - @Override - public ExportKeyringParcel[] newArray(int size) { - return new ExportKeyringParcel[size]; - } - }; -} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java index 981a76203..ee953b060 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java @@ -33,7 +33,7 @@ import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.ConsolidateOperation; import org.sufficientlysecure.keychain.operations.DeleteOperation; import org.sufficientlysecure.keychain.operations.EditKeyOperation; -import org.sufficientlysecure.keychain.operations.ExportOperation; +import org.sufficientlysecure.keychain.operations.BackupOperation; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation; import org.sufficientlysecure.keychain.operations.InputDataOperation; @@ -125,8 +125,8 @@ public class KeychainService extends Service implements Progressable { op = new PromoteKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); } else if (inputParcel instanceof ImportKeyringParcel) { op = new ImportOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); - } else if (inputParcel instanceof ExportKeyringParcel) { - op = new ExportOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); + } else if (inputParcel instanceof BackupKeyringParcel) { + op = new BackupOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); } else if (inputParcel instanceof UploadKeyringParcel) { op = new UploadOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); } else if (inputParcel instanceof ConsolidateInputParcel) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java index 09447ec32..87f9052a7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java @@ -52,7 +52,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; -import org.sufficientlysecure.keychain.service.ExportKeyringParcel; +import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; @@ -61,7 +61,7 @@ import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.Passphrase; -public class BackupCodeFragment extends CryptoOperationFragment +public class BackupCodeFragment extends CryptoOperationFragment implements OnBackStackChangedListener { public static final String ARG_BACKUP_CODE = "backup_code"; @@ -499,8 +499,8 @@ public class BackupCodeFragment extends CryptoOperationFragment { - ExportHelper mExportHelper; ProviderHelper mProviderHelper; protected Uri mDataUri; @@ -75,7 +73,6 @@ public class ViewKeyAdvActivity extends BaseActivity implements } }); - mExportHelper = new ExportHelper(this); mProviderHelper = new ProviderHelper(this); mViewPager = (ViewPager) findViewById(R.id.pager); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index dcb92bd75..c5e575e32 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -52,6 +52,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; @@ -63,7 +64,6 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; -import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; @@ -84,7 +84,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private Uri mDataUri; private byte[] mFingerprint; - private long mMasterKeyId; + private String mUserId; @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { @@ -107,7 +107,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share); - View vKeySaveButton = view.findViewById(R.id.view_key_action_key_export); View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc); View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); @@ -118,35 +117,25 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements vFingerprintShareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(true, false); + shareFingerprint(false); } }); vFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(true, true); + shareFingerprint(true); } }); vKeyShareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(false, false); - } - }); - // Show save only on Android >= 4.4 (Document Provider) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - vKeySaveButton.setVisibility(View.GONE); - } - vKeySaveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - exportToFile(); + shareKey(false); } }); vKeyClipboardButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(false, true); + shareKey(true); } }); @@ -178,11 +167,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements return root; } - private void exportToFile() { - new ExportHelper(getActivity()).showExportKeysDialog( - mMasterKeyId, Constants.Path.APP_DIR_FILE, false); - } - private void startSafeSlinger(Uri dataUri) { long keyId = 0; try { @@ -197,7 +181,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements startActivityForResult(safeSlingerIntent, 0); } - private void share(boolean fingerprintOnly, boolean toClipboard) { + private void shareKey(boolean toClipboard) { Activity activity = getActivity(); if (activity == null || mFingerprint == null) { return; @@ -205,18 +189,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements ProviderHelper providerHelper = new ProviderHelper(activity); try { - String content; - if (fingerprintOnly) { - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint); - if (!toClipboard) { - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - } else { - content = fingerprint; - } - } else { - content = providerHelper.getKeyRingAsArmoredString( - KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri)); - } + String content = providerHelper.getKeyRingAsArmoredString( + KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri)); if (toClipboard) { ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); @@ -228,29 +202,26 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content); clipMan.setPrimaryClip(clip); - Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard - : R.string.key_copied_to_clipboard, Notify.Style.OK).show(); - return; - } - - // Android will fail with android.os.TransactionTooLargeException if key is too big - // see http://www.lonestarprod.com/?p=34 - if (content.length() >= 86389) { - Notify.create(activity, R.string.key_too_big_for_sharing, Notify.Style.ERROR).show(); + Notify.create(activity, R.string.key_copied_to_clipboard, Notify.Style.OK).show(); return; } // let user choose application Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); sendIntent.setType("text/plain"); - // Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML - // Add replacement extra to send a text/plain file instead. + // NOTE: Don't use Intent.EXTRA_TEXT to send the key + // better send it via a Uri! + // example: Bluetooth Share will convert text/plain sent via Intent.EXTRA_TEXT to HTML try { TemporaryFileProvider shareFileProv = new TemporaryFileProvider(); - Uri contentUri = TemporaryFileProvider.createFile(activity, - KeyFormattingUtils.convertFingerprintToHex(mFingerprint) + Constants.FILE_EXTENSION_ASC); + + String filename = KeyFormattingUtils.convertFingerprintToHex(mFingerprint); + KeyRing.UserId mainUserId = KeyRing.splitUserId(mUserId); + if (mainUserId.name != null) { + filename = mainUserId.name; + } + Uri contentUri = TemporaryFileProvider.createFile(activity, filename + Constants.FILE_EXTENSION_ASC); BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter( new ParcelFileDescriptor.AutoCloseOutputStream( @@ -260,18 +231,15 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri); } catch (FileNotFoundException e) { - Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e); + Log.e(Constants.TAG, "Error creating temporary key share file!", e); // no need for a snackbar because one sharing option doesn't work // Notify.create(getActivity(), R.string.error_temp_file, Notify.Style.ERROR).show(); } - - String title = getString(fingerprintOnly - ? R.string.title_share_fingerprint_with : R.string.title_share_key); + String title = getString(R.string.title_share_key); Intent shareChooser = Intent.createChooser(sendIntent, title); startActivity(shareChooser); - } catch (PgpGeneralException | IOException e) { Log.e(Constants.TAG, "error processing key!", e); Notify.create(activity, R.string.error_key_processing, Notify.Style.ERROR).show(); @@ -281,6 +249,45 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } } + private void shareFingerprint(boolean toClipboard) { + Activity activity = getActivity(); + if (activity == null || mFingerprint == null) { + return; + } + + String content; + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint); + if (!toClipboard) { + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + } else { + content = fingerprint; + } + + if (toClipboard) { + ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR); + return; + } + + ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content); + clipMan.setPrimaryClip(clip); + + Notify.create(activity, R.string.fingerprint_copied_to_clipboard, Notify.Style.OK).show(); + return; + } + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, content); + sendIntent.setType("text/plain"); + + String title = getString(R.string.title_share_fingerprint_with); + Intent shareChooser = Intent.createChooser(sendIntent, title); + + startActivity(shareChooser); + } + private void showQrCodeDialog() { Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); @@ -322,11 +329,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mNfcHelper.initNfc(mDataUri); } - static final String[] UNIFIED_PROJECTION = new String[] { - KeyRings._ID, KeyRings.FINGERPRINT + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.FINGERPRINT, KeyRings.USER_ID }; static final int INDEX_UNIFIED_FINGERPRINT = 1; + static final int INDEX_UNIFIED_USER_ID = 2; public Loader onCreateLoader(int id, Bundle args) { setContentShown(false); @@ -355,6 +363,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); setFingerprint(fingerprintBlob); + mUserId = data.getString(INDEX_UNIFIED_USER_ID); + break; } } @@ -371,10 +381,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mFingerprint = null; } - /** Load QR Code asynchronously and with a fade in animation */ + /** + * Load QR Code asynchronously and with a fade in animation + */ private void setFingerprint(byte[] fingerprintBlob) { mFingerprint = fingerprintBlob; - mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(fingerprintBlob); final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); mFingerprintView.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java deleted file mode 100644 index cc90c173f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.util; - - -import java.io.File; - -import android.content.Intent; -import android.net.Uri; -import android.support.v4.app.FragmentActivity; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.service.ExportKeyringParcel; -import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; - -public class ExportHelper - implements CryptoOperationHelper.Callback { - protected File mExportFile; - - FragmentActivity mActivity; - - private boolean mExportSecret; - private long[] mMasterKeyIds; - - public ExportHelper(FragmentActivity activity) { - super(); - this.mActivity = activity; - } - - /** Show dialog where to export keys */ - public void showExportKeysDialog(final Long masterKeyId, final File exportFile, - final boolean exportSecret) { - mExportFile = exportFile; - - String title; - if (masterKeyId == null) { - // export all keys - title = mActivity.getString(R.string.title_export_keys); - } else { - // export only key specified at data uri - title = mActivity.getString(R.string.title_export_key); - } - - String message; - if (exportSecret) { - message = mActivity.getString(masterKeyId == null - ? R.string.specify_backup_dest_secret - : R.string.specify_backup_dest_secret_single); - } else { - message = mActivity.getString(masterKeyId == null - ? R.string.specify_backup_dest - : R.string.specify_backup_dest_single); - } - - // TODO: for valodim -// FileHelper.saveDocumentDialog(new FileHelper.FileDialogCallback() { -// @Override -// public void onFileSelected(File file, boolean checked) { -// mExportFile = file; -// exportKeys(masterKeyId == null ? null : new long[] { masterKeyId }, exportSecret); -// } -// }, mActivity.getSupportFragmentManager(), title, message, exportFile, null); - } - - // TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using - // TODO: this class should be able to call mExportOpHelper.handleActivity - - /** - * Export keys - */ - public void exportKeys(long[] masterKeyIds, boolean exportSecret) { - Log.d(Constants.TAG, "exportKeys started"); - mExportSecret = exportSecret; - mMasterKeyIds = masterKeyIds; // if masterKeyIds is null it means export all - - CryptoOperationHelper exportOpHelper = - new CryptoOperationHelper<>(1, mActivity, this, R.string.progress_exporting); - exportOpHelper.cryptoOperation(); - } - - @Override - public ExportKeyringParcel createOperationInput() { - return new ExportKeyringParcel(null, mMasterKeyIds, mExportSecret, Uri.fromFile(mExportFile)); - } - - @Override - final public void onCryptoOperationSuccess(ExportResult result) { - // trigger scan of the created 'media' file so it shows up on MTP - // http://stackoverflow.com/questions/13737261/nexus-4-not-showing-files-via-mtp - mActivity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mExportFile))); - result.createNotify(mActivity).show(); - } - - @Override - public void onCryptoOperationCancelled() { - - } - - @Override - public void onCryptoOperationError(ExportResult result) { - result.createNotify(mActivity).show(); - } - - @Override - public boolean onCryptoSetProgress(String msg, int progress, int max) { - return false; - } -} diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml index d82506e74..c08d66cc1 100644 --- a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml +++ b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml @@ -125,23 +125,6 @@ android:layout_marginTop="8dp" android:background="?android:attr/listDivider" /> - - - - "No compatible file manager installed." "The passwords didn't match." "Please enter a password." - "Symmetric encryption." + "Enter password" + "Enter backup code" "Enter password for '%s'" "Enter PIN for '%s'" "Enter PIN to access YubiKey for '%s'" @@ -337,7 +338,6 @@ "Key has been copied to the clipboard!" "Fingerprint has been copied to the clipboard!" "Please select a key to be used for confirmation!" - "Key is too big to be shared this way!" "Text has been copied to the clipboard!"