From 4667a05c420b72a8d3c509a9e3c1cb8ab0ff92cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 07:54:58 +0200 Subject: Guess mime type like support libs FileProvider --- .../org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 6a85ce251..7a4c85178 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -70,7 +70,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URLConnection; import java.security.SignatureException; import java.util.Date; import java.util.Iterator; @@ -676,8 +675,6 @@ public class PgpDecryptVerify extends BaseOperation || literalData.getFormat() == PGPLiteralData.UTF8) { mimeType = "text/plain"; } else { - // TODO: better would be: https://github.com/open-keychain/open-keychain/issues/753 - // try to guess from file ending String extension = MimeTypeMap.getFileExtensionFromUrl(originalFilename); if (extension != null) { @@ -685,10 +682,7 @@ public class PgpDecryptVerify extends BaseOperation mimeType = mime.getMimeTypeFromExtension(extension); } if (mimeType == null) { - mimeType = URLConnection.guessContentTypeFromName(originalFilename); - } - if (mimeType == null) { - mimeType = "*/*"; + mimeType = "application/octet-stream"; } } -- cgit v1.2.3 From 5b320d01d0ceba22596789ecb1b8646f2af11619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 07:58:00 +0200 Subject: Use application/octet-stream as default type in TemporaryStorageProvider --- .../sufficientlysecure/keychain/provider/TemporaryStorageProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java index b1f1a7d9e..cbb243fad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java @@ -180,7 +180,7 @@ public class TemporaryStorageProvider extends ContentProvider { cursor.close(); } } - return "*/*"; + return "application/octet-stream"; } @Override -- cgit v1.2.3 From 99c06b085b4acd46e21fdfde0d0716ee68fa9f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 09:24:34 +0200 Subject: Add brackets in KeychainProvider --- .../keychain/provider/KeychainProvider.java | 73 +++++++++++++--------- 1 file changed, 43 insertions(+), 30 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 1351e0cbc..3ed9b1da9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -520,7 +520,6 @@ public class KeychainProvider extends ContentProvider { } break; - } case KEY_RINGS_PUBLIC: @@ -607,23 +606,26 @@ public class KeychainProvider extends ContentProvider { break; } - case API_APPS: + case API_APPS: { qb.setTables(Tables.API_APPS); break; - case API_APPS_BY_PACKAGE_NAME: + } + case API_APPS_BY_PACKAGE_NAME: { qb.setTables(Tables.API_APPS); qb.appendWhere(ApiApps.PACKAGE_NAME + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); break; - case API_ACCOUNTS: + } + case API_ACCOUNTS: { qb.setTables(Tables.API_ACCOUNTS); qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: + } + case API_ACCOUNTS_BY_ACCOUNT_NAME: { qb.setTables(Tables.API_ACCOUNTS); qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); @@ -632,14 +634,17 @@ public class KeychainProvider extends ContentProvider { qb.appendWhereEscapeString(uri.getLastPathSegment()); break; - case API_ALLOWED_KEYS: + } + case API_ALLOWED_KEYS: { qb.setTables(Tables.API_ALLOWED_KEYS); qb.appendWhere(Tables.API_ALLOWED_KEYS + "." + ApiAccounts.PACKAGE_NAME + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); break; - default: + } + default: { throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); + } } @@ -684,47 +689,47 @@ public class KeychainProvider extends ContentProvider { final int match = mUriMatcher.match(uri); switch (match) { - case KEY_RING_PUBLIC: + case KEY_RING_PUBLIC: { db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values); keyId = values.getAsLong(KeyRings.MASTER_KEY_ID); break; - - case KEY_RING_SECRET: + } + case KEY_RING_SECRET: { db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values); keyId = values.getAsLong(KeyRings.MASTER_KEY_ID); break; - - case KEY_RING_KEYS: + } + case KEY_RING_KEYS: { db.insertOrThrow(Tables.KEYS, null, values); keyId = values.getAsLong(Keys.MASTER_KEY_ID); break; - - case KEY_RING_USER_IDS: + } + case KEY_RING_USER_IDS: { // iff TYPE is null, user_id MUST be null as well - if ( ! (values.get(UserPacketsColumns.TYPE) == null + if (!(values.get(UserPacketsColumns.TYPE) == null ? (values.get(UserPacketsColumns.USER_ID) != null && values.get(UserPacketsColumns.ATTRIBUTE_DATA) == null) : (values.get(UserPacketsColumns.ATTRIBUTE_DATA) != null && values.get(UserPacketsColumns.USER_ID) == null) - )) { + )) { throw new AssertionError("Incorrect type for user packet! This is a bug!"); } - if (((Number)values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) { + if (((Number) values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) { throw new AssertionError("Rank 0 user packet must be a user id!"); } db.insertOrThrow(Tables.USER_PACKETS, null, values); keyId = values.getAsLong(UserPackets.MASTER_KEY_ID); break; - - case KEY_RING_CERTS: + } + case KEY_RING_CERTS: { // we replace here, keeping only the latest signature // TODO this would be better handled in savePublicKeyRing directly! db.replaceOrThrow(Tables.CERTS, null, values); keyId = values.getAsLong(Certs.MASTER_KEY_ID); break; - - case API_APPS: + } + case API_APPS: { db.insertOrThrow(Tables.API_APPS, null, values); break; - + } case API_ACCOUNTS: { // set foreign key automatically based on given uri // e.g., api_apps/com.example.app/accounts/ @@ -743,8 +748,9 @@ public class KeychainProvider extends ContentProvider { db.insertOrThrow(Tables.API_ALLOWED_KEYS, null, values); break; } - default: + default: { throw new UnsupportedOperationException("Unknown uri: " + uri); + } } if (keyId != null) { @@ -802,20 +808,24 @@ public class KeychainProvider extends ContentProvider { break; } - case API_APPS_BY_PACKAGE_NAME: + case API_APPS_BY_PACKAGE_NAME: { count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, additionalSelection), selectionArgs); break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: + } + case API_ACCOUNTS_BY_ACCOUNT_NAME: { count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection), selectionArgs); break; - case API_ALLOWED_KEYS: + } + case API_ALLOWED_KEYS: { count = db.delete(Tables.API_ALLOWED_KEYS, buildDefaultApiAllowedKeysSelection(uri, additionalSelection), selectionArgs); break; - default: + } + default: { throw new UnsupportedOperationException("Unknown uri: " + uri); + } } // notify of changes in db @@ -851,16 +861,19 @@ public class KeychainProvider extends ContentProvider { count = db.update(Tables.KEYS, values, actualSelection, selectionArgs); break; } - case API_APPS_BY_PACKAGE_NAME: + case API_APPS_BY_PACKAGE_NAME: { count = db.update(Tables.API_APPS, values, buildDefaultApiAppsSelection(uri, selection), selectionArgs); break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: + } + case API_ACCOUNTS_BY_ACCOUNT_NAME: { count = db.update(Tables.API_ACCOUNTS, values, buildDefaultApiAccountsSelection(uri, selection), selectionArgs); break; - default: + } + default: { throw new UnsupportedOperationException("Unknown uri: " + uri); + } } // notify of changes in db -- cgit v1.2.3 From 93e6b6f9b5debfc8fac3bad1390254e389f7432e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 10:54:04 +0200 Subject: Use signature-level signature for TemporaryStorageProvider and describe the security model --- .../provider/TemporaryStorageProvider.java | 61 ++++++++++++++++------ 1 file changed, 46 insertions(+), 15 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java index cbb243fad..7e9b24989 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java @@ -19,23 +19,15 @@ package org.sufficientlysecure.keychain.provider; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.UUID; - import android.content.ClipDescription; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; -import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; -import android.os.Bundle; -import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.provider.OpenableColumns; @@ -43,6 +35,30 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.DatabaseUtil; import org.sufficientlysecure.keychain.util.Log; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.UUID; + +/** + * TemporaryStorageProvider stores decrypted files inside the app's cache directory previously to + * sharing them with other applications. + * + * Security: + * - It is writable by OpenKeychain only (see Manifest), but exported for reading files + * - It uses UUIDs as identifiers which makes predicting files from outside impossible + * - Querying a number of files is not allowed, only querying single files + * -> You can only open a file if you know the Uri containing the precise UUID, this Uri is only + * revealed when the user shares a decrypted file with another app. + * + * Why is support lib's FileProvider not used? + * Because granting Uri permissions temporarily does not work correctly. See + * - https://code.google.com/p/android/issues/detail?id=76683 + * - https://github.com/nmr8acme/FileProvider-permission-bug + * - http://stackoverflow.com/q/24467696 + * - http://stackoverflow.com/q/18249007 + * - Comments at http://www.blogc.at/2014/03/23/share-private-files-with-other-apps-fileprovider/ + */ public class TemporaryStorageProvider extends ContentProvider { private static final String DB_NAME = "tempstorage.db"; @@ -143,6 +159,10 @@ public class TemporaryStorageProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + if (uri.getLastPathSegment() == null) { + throw new SecurityException("Listing temporary files is not allowed, only querying single files."); + } + File file; try { file = getFile(uri); @@ -153,9 +173,15 @@ public class TemporaryStorageProvider extends ContentProvider { new String[]{uri.getLastPathSegment()}, null, null, null); if (fileName != null) { if (fileName.moveToNext()) { - MatrixCursor cursor = - new MatrixCursor(new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, "_data"}); - cursor.newRow().add(fileName.getString(0)).add(file.length()).add(file.getAbsolutePath()); + MatrixCursor cursor = new MatrixCursor(new String[]{ + OpenableColumns.DISPLAY_NAME, + OpenableColumns.SIZE, + "_data" + }); + cursor.newRow() + .add(fileName.getString(0)) + .add(file.length()) + .add(file.getAbsolutePath()); fileName.close(); return cursor; } @@ -167,8 +193,8 @@ public class TemporaryStorageProvider extends ContentProvider { @Override public String getType(Uri uri) { Cursor cursor = db.getReadableDatabase().query(TABLE_FILES, - new String[]{ COLUMN_TYPE }, COLUMN_ID + "=?", - new String[]{ uri.getLastPathSegment() }, null, null, null); + new String[]{COLUMN_TYPE}, COLUMN_ID + "=?", + new String[]{uri.getLastPathSegment()}, null, null, null); if (cursor != null) { try { if (cursor.moveToNext()) { @@ -187,7 +213,7 @@ public class TemporaryStorageProvider extends ContentProvider { public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { String type = getType(uri); if (ClipDescription.compareMimeTypes(type, mimeTypeFilter)) { - return new String[] { type }; + return new String[]{type}; } return null; } @@ -200,9 +226,14 @@ public class TemporaryStorageProvider extends ContentProvider { String uuid = UUID.randomUUID().toString(); values.put(COLUMN_ID, uuid); int insert = (int) db.getWritableDatabase().insert(TABLE_FILES, null, values); + if (insert == -1) { + Log.e(Constants.TAG, "Insert failed!"); + return null; + } try { getFile(uuid).createNewFile(); } catch (IOException e) { + Log.e(Constants.TAG, "File creation failed!"); return null; } return Uri.withAppendedPath(BASE_URI, uuid); @@ -238,7 +269,7 @@ public class TemporaryStorageProvider extends ContentProvider { throw new UnsupportedOperationException("Update supported only for plain uri!"); } return db.getWritableDatabase().update(TABLE_FILES, values, - COLUMN_ID + " = ?", new String[]{ uri.getLastPathSegment() }); + COLUMN_ID + " = ?", new String[]{uri.getLastPathSegment()}); } @Override -- cgit v1.2.3 From 136397667a1c740578081a990882a18149a6b686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 14:01:12 +0200 Subject: Force db upgrade on app start --- .../org/sufficientlysecure/keychain/KeychainApplication.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 8d43c0155..627623f47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -33,6 +33,7 @@ import android.provider.ContactsContract; import android.widget.Toast; import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; @@ -101,7 +102,10 @@ public class KeychainApplication extends Application { TemporaryStorageProvider.cleanUp(this); - checkConsolidateRecovery(); + if (!checkConsolidateRecovery()) { + // force DB upgrade, https://github.com/open-keychain/open-keychain/issues/1334 + new KeychainDatabase(this).getReadableDatabase().close(); + } } public static HashMap qrCodeCache = new HashMap<>(); @@ -118,12 +122,15 @@ public class KeychainApplication extends Application { /** * Restart consolidate process if it has been interruped before */ - public void checkConsolidateRecovery() { + public boolean checkConsolidateRecovery() { if (Preferences.getPreferences(this).getCachedConsolidate()) { Intent consolidateIntent = new Intent(this, ConsolidateDialogActivity.class); consolidateIntent.putExtra(ConsolidateDialogActivity.EXTRA_CONSOLIDATE_RECOVERY, true); consolidateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(consolidateIntent); + return true; + } else { + return false; } } -- cgit v1.2.3 From c43e29b621d5a0d2071a10d4033df25251b3ea23 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 26 Jun 2015 22:55:11 +0200 Subject: cleanup share fragment, fix sharing of fingerprint --- .../keychain/ui/ViewKeyAdvActivity.java | 34 ++- .../keychain/ui/ViewKeyAdvShareFragment.java | 252 +++++++++------------ 2 files changed, 120 insertions(+), 166 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index 9e8a12c8a..6669f2654 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -53,13 +53,15 @@ public class ViewKeyAdvActivity extends BaseActivity implements protected Uri mDataUri; public static final String EXTRA_SELECTED_TAB = "selected_tab"; - public static final int TAB_MAIN = 0; - public static final int TAB_SHARE = 1; + public static final int TAB_SHARE = 0; + public static final int TAB_IDENTITIES = 1; + public static final int TAB_SUBKEYS = 2; + public static final int TAB_CERTS = 3; + public static final int TAB_KEYBASE = 4; // view private ViewPager mViewPager; private PagerSlidingTabStrip mSlidingTabLayout; - private PagerTabStripAdapter mTabsAdapter; private static final int LOADER_ID_UNIFIED = 0; @@ -80,11 +82,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements mViewPager = (ViewPager) findViewById(R.id.pager); mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout); - int switchToTab = TAB_MAIN; Intent intent = getIntent(); - if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { - switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); - } + int switchToTab = intent.getIntExtra(EXTRA_SELECTED_TAB, TAB_SHARE); mDataUri = getIntent().getData(); if (mDataUri == null) { @@ -102,8 +101,6 @@ public class ViewKeyAdvActivity extends BaseActivity implements } } - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); @@ -120,32 +117,32 @@ public class ViewKeyAdvActivity extends BaseActivity implements } private void initTabs(Uri dataUri) { - mTabsAdapter = new PagerTabStripAdapter(this); - mViewPager.setAdapter(mTabsAdapter); + PagerTabStripAdapter adapter = new PagerTabStripAdapter(this); + mViewPager.setAdapter(adapter); Bundle shareBundle = new Bundle(); shareBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvShareFragment.class, + adapter.addTab(ViewKeyAdvShareFragment.class, shareBundle, getString(R.string.key_view_tab_share)); Bundle userIdsBundle = new Bundle(); userIdsBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvUserIdsFragment.class, + adapter.addTab(ViewKeyAdvUserIdsFragment.class, userIdsBundle, getString(R.string.section_user_ids)); Bundle keysBundle = new Bundle(); keysBundle.putParcelable(ViewKeyAdvSubkeysFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvSubkeysFragment.class, + adapter.addTab(ViewKeyAdvSubkeysFragment.class, keysBundle, getString(R.string.key_view_tab_keys)); Bundle certsBundle = new Bundle(); certsBundle.putParcelable(ViewKeyAdvCertsFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvCertsFragment.class, + adapter.addTab(ViewKeyAdvCertsFragment.class, certsBundle, getString(R.string.key_view_tab_certs)); Bundle trustBundle = new Bundle(); trustBundle.putParcelable(ViewKeyTrustFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyTrustFragment.class, + adapter.addTab(ViewKeyTrustFragment.class, trustBundle, getString(R.string.key_view_tab_keybase)); // update layout after operations @@ -185,11 +182,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements @Override public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ // Avoid NullPointerExceptions... - if (data.getCount() == 0) { + if (data == null || data.getCount() == 0) { return; } // Swap the new cursor in. (The framework will take care of closing the 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 42abf35eb..b44e6dc78 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -17,6 +17,13 @@ package org.sufficientlysecure.keychain.ui; + +import java.io.BufferedWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStreamWriter; + +import android.app.Activity; import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; @@ -43,12 +50,10 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -57,57 +62,35 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; -import java.io.BufferedWriter; -import java.io.OutputStreamWriter; -import java.io.IOException; -import java.io.FileNotFoundException; - public class ViewKeyAdvShareFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; - private TextView mFingerprint; private ImageView mQrCode; private CardView mQrCodeLayout; - private View mFingerprintShareButton; - private View mFingerprintClipboardButton; - private View mKeyShareButton; - private View mKeyClipboardButton; - private View mKeyNfcButton; - private ImageButton mKeySafeSlingerButton; - private View mKeyUploadButton; - - ProviderHelper mProviderHelper; + private TextView mFingerprintView; + NfcHelper mNfcHelper; private static final int LOADER_ID_UNIFIED = 0; private Uri mDataUri; + private byte[] mFingerprint; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { View root = super.onCreateView(inflater, superContainer, savedInstanceState); View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer()); - mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); - mNfcHelper = new NfcHelper(getActivity(), mProviderHelper); + ProviderHelper providerHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); + mNfcHelper = new NfcHelper(getActivity(), providerHelper); - mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); + mFingerprintView = (TextView) view.findViewById(R.id.view_key_fingerprint); mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code); mQrCodeLayout = (CardView) view.findViewById(R.id.view_key_qr_code_layout); - mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); - mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); - mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); - mKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc); - mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); - mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); - mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); - - mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - mQrCodeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -115,50 +98,60 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } }); - mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { + 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 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); + View vKeyUploadButton = view.findViewById(R.id.view_key_action_upload); + vKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), + PorterDuff.Mode.SRC_IN); + + vFingerprintShareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(mDataUri, mProviderHelper, true, false); + share(true, false); } }); - mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { + vFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(mDataUri, mProviderHelper, true, true); + share(true, true); } }); - mKeyShareButton.setOnClickListener(new View.OnClickListener() { + vKeyShareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(mDataUri, mProviderHelper, false, false); + share(false, false); } }); - mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { + vKeyClipboardButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - share(mDataUri, mProviderHelper, false, true); + share(false, true); } }); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mKeyNfcButton.setVisibility(View.VISIBLE); - mKeyNfcButton.setOnClickListener(new View.OnClickListener() { + vKeyNfcButton.setVisibility(View.VISIBLE); + vKeyNfcButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mNfcHelper.invokeNfcBeam(); } }); } else { - mKeyNfcButton.setVisibility(View.GONE); + vKeyNfcButton.setVisibility(View.GONE); } - mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { + vKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startSafeSlinger(mDataUri); } }); - mKeyUploadButton.setOnClickListener(new View.OnClickListener() { + vKeyUploadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { uploadToKeyserver(); @@ -182,97 +175,79 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements startActivityForResult(safeSlingerIntent, 0); } - private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, - boolean toClipboard) { + private void share(boolean fingerprintOnly, boolean toClipboard) { + Activity activity = getActivity(); + if (activity == null || mFingerprint == null) { + return; + } + ProviderHelper providerHelper = new ProviderHelper(activity); + try { String content; - byte[] fingerprintData = (byte[]) providerHelper.getGenericData( - KeyRings.buildUnifiedKeyRingUri(dataUri), - Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); if (fingerprintOnly) { - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintData); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint); if (!toClipboard) { content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; } else { content = fingerprint; } } else { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - // get public keyring as ascii armored string - content = providerHelper.getKeyRingAsArmoredString(uri); + content = providerHelper.getKeyRingAsArmoredString( + KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri)); } if (toClipboard) { - ClipboardReflection.copyToClipboard(getActivity(), content); - String message; - if (fingerprintOnly) { - message = getResources().getString(R.string.fingerprint_copied_to_clipboard); - } else { - message = getResources().getString(R.string.key_copied_to_clipboard); - } - Notify.create(getActivity(), message, Notify.Style.OK).show(); - } else { - // 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(getActivity(), R.string.key_too_big_for_sharing, - Notify.Style.ERROR).show(); - return; - } - - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); - sendIntent.setType("text/plain"); + ClipboardReflection.copyToClipboard(activity, content); + Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard + : R.string.key_copied_to_clipboard, Notify.Style.OK).show(); + return; + } - String title; - if (fingerprintOnly) { - title = getResources().getString(R.string.title_share_fingerprint_with); - } else { - title = getResources().getString(R.string.title_share_key); - } - Intent shareChooser = Intent.createChooser(sendIntent, title); - - // Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML - // Add replacement extra to send a text/plain file instead. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - try { - String primaryUserId = UncachedKeyRing.decodeFromData(content.getBytes()). - getPublicKey().getPrimaryUserIdWithFallback(); - - TemporaryStorageProvider shareFileProv = new TemporaryStorageProvider(); - Uri contentUri = TemporaryStorageProvider.createFile(getActivity(), - primaryUserId + Constants.FILE_EXTENSION_ASC); - - BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter( - new ParcelFileDescriptor.AutoCloseOutputStream( - shareFileProv.openFile(contentUri, "w")))); - contentWriter.write(content); - contentWriter.close(); - - // create replacement extras inside try{}: - // if file creation fails, just don't add the replacements - Bundle replacements = new Bundle(); - shareChooser.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacements); - - Bundle bluetoothExtra = new Bundle(sendIntent.getExtras()); - replacements.putBundle("com.android.bluetooth", bluetoothExtra); - - bluetoothExtra.putParcelable(Intent.EXTRA_STREAM, contentUri); - } catch (FileNotFoundException e) { - Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e); - Notify.create(getActivity(), R.string.error_bluetooth_file, Notify.Style.ERROR).show(); - } - } + // 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(); + return; + } - startActivity(shareChooser); + // 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. + try { + TemporaryStorageProvider shareFileProv = new TemporaryStorageProvider(); + Uri contentUri = TemporaryStorageProvider.createFile(activity, + KeyFormattingUtils.convertFingerprintToHex(mFingerprint) + Constants.FILE_EXTENSION_ASC); + + BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter( + new ParcelFileDescriptor.AutoCloseOutputStream( + shareFileProv.openFile(contentUri, "w")))); + contentWriter.write(content); + contentWriter.close(); + + sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri); + } catch (FileNotFoundException e) { + Log.e(Constants.TAG, "error creating temporary Bluetooth 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); + Intent shareChooser = Intent.createChooser(sendIntent, title); + + startActivity(shareChooser); + } catch (PgpGeneralException | IOException e) { Log.e(Constants.TAG, "error processing key!", e); - Notify.create(getActivity(), R.string.error_key_processing, Notify.Style.ERROR).show(); + Notify.create(activity, R.string.error_key_processing, Notify.Style.ERROR).show(); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); - Notify.create(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR).show(); + Notify.create(activity, R.string.error_key_not_found, Notify.Style.ERROR).show(); } } @@ -293,8 +268,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); if (dataUri == null) { @@ -309,8 +284,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private void loadData(Uri dataUri) { mDataUri = dataUri; - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); @@ -320,19 +293,10 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } static final String[] UNIFIED_PROJECTION = new String[] { - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED, - + KeyRings._ID, KeyRings.FINGERPRINT }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_USER_ID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_ID_EXPIRED = 8; + + static final int INDEX_UNIFIED_FINGERPRINT = 1; public Loader onCreateLoader(int id, Bundle args) { setContentShown(false); @@ -348,11 +312,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ // Avoid NullPointerExceptions... - if (data.getCount() == 0) { + if (data == null || data.getCount() == 0) { return; } // Swap the new cursor in. (The framework will take care of closing the @@ -362,10 +323,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements if (data.moveToFirst()) { byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); - - loadQrCode(fingerprint); + setFingerprint(fingerprintBlob); break; } @@ -380,14 +338,16 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements * We need to make sure we are no longer using it. */ public void onLoaderReset(Loader loader) { + mFingerprint = null; } - /** - * Load QR Code asynchronously and with a fade in animation - * - * @param fingerprint - */ - private void loadQrCode(final String fingerprint) { + /** Load QR Code asynchronously and with a fade in animation */ + private void setFingerprint(byte[] fingerprintBlob) { + mFingerprint = fingerprintBlob; + + final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); + mFingerprintView.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); + AsyncTask loadTask = new AsyncTask() { protected Bitmap doInBackground(Void... unused) { -- cgit v1.2.3 From 853964670b5b52a8b26864dff9c19f2f8c3fc8c9 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 26 Jun 2015 22:55:39 +0200 Subject: instrument: add tests for adv key share fragment --- .../keychain/compatibility/ClipboardReflection.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java index 0ac27833c..403e654e4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java @@ -38,7 +38,7 @@ public class ClipboardReflection { } - public static CharSequence getClipboardText(Context context) { + public static String getClipboardText(Context context) { ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = clipboard.getPrimaryClip(); @@ -48,6 +48,10 @@ public class ClipboardReflection { } ClipData.Item item = clip.getItemAt(0); - return item.coerceToText(context); + CharSequence seq = item.coerceToText(context); + if (seq != null) { + return seq.toString(); + } + return null; } } -- cgit v1.2.3 From a9c606d49bf7d4e7a30b7265cd1fb04ff1c3c01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 20:48:11 +0200 Subject: Create key wizard for blank YubiKey --- .../keychain/remote/OpenPgpService.java | 2 +- .../service/input/RequiredInputParcel.java | 6 +- .../keychain/ui/CreateKeyActivity.java | 55 +++++++------ .../keychain/ui/CreateKeyFinalFragment.java | 93 ++++++++++++++++++---- .../keychain/ui/CreateKeyYubiKeyBlankFragment.java | 90 +++++++++++++++++++++ .../ui/CreateKeyYubiKeyImportFragment.java | 4 +- .../keychain/ui/CreateKeyYubiKeyWaitFragment.java | 2 +- .../keychain/ui/NfcOperationActivity.java | 4 +- .../keychain/ui/base/BaseNfcActivity.java | 2 +- .../keychain/ui/base/CryptoOperationFragment.java | 2 +- 10 files changed, 206 insertions(+), 54 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 0d2d3256d..ac66bd097 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -167,7 +167,7 @@ public class OpenPgpService extends RemoteService { Intent data, RequiredInputParcel requiredInput) { switch (requiredInput.mType) { - case NFC_KEYTOCARD: + case NFC_MOVE_KEY_TO_CARD: case NFC_DECRYPT: case NFC_SIGN: { // build PendingIntent for YubiKey NFC operations diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index 930c2ee4f..efe844145 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -12,7 +12,7 @@ import android.os.Parcelable; public class RequiredInputParcel implements Parcelable { public enum RequiredInputType { - PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_KEYTOCARD + PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD } public Date mSignatureTime; @@ -226,7 +226,7 @@ public class RequiredInputParcel implements Parcelable { ByteBuffer buf = ByteBuffer.wrap(mSubkeysToExport.get(0)); // We need to pass in a subkey here... - return new RequiredInputParcel(RequiredInputType.NFC_KEYTOCARD, + return new RequiredInputParcel(RequiredInputType.NFC_MOVE_KEY_TO_CARD, inputHashes, null, null, mMasterKeyId, buf.getLong()); } @@ -241,7 +241,7 @@ public class RequiredInputParcel implements Parcelable { if (!mMasterKeyId.equals(input.mMasterKeyId)) { throw new AssertionError("Master keys must match, this is a programming error!"); } - if (input.mType != RequiredInputType.NFC_KEYTOCARD) { + if (input.mType != RequiredInputType.NFC_MOVE_KEY_TO_CARD) { throw new AssertionError("Operation types must match, this is a programming error!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 68a809b69..fbe7b4066 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -17,8 +17,6 @@ package org.sufficientlysecure.keychain.ui; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -89,13 +87,19 @@ public class CreateKeyActivity extends BaseNfcActivity { String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID); byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID); - Fragment frag2 = CreateKeyYubiKeyImportFragment.createInstance( - nfcFingerprints, nfcAid, nfcUserId); - loadFragment(frag2, FragAction.START); + if (containsKeys(nfcFingerprints)) { + Fragment frag = CreateKeyYubiKeyImportFragment.newInstance( + nfcFingerprints, nfcAid, nfcUserId); + loadFragment(frag, FragAction.START); - setTitle(R.string.title_import_keys); + setTitle(R.string.title_import_keys); + } else { + Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); + loadFragment(frag, FragAction.START); + } return; } else { + // normal key creation CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); loadFragment(frag, FragAction.START); } @@ -122,16 +126,7 @@ public class CreateKeyActivity extends BaseNfcActivity { byte[] nfcAid = nfcGetAid(); String userId = nfcGetUserId(); - // If all fingerprint bytes are 0, the card contains no keys. - boolean cardContainsKeys = false; - for (byte b : scannedFingerprints) { - if (b != 0) { - cardContainsKeys = true; - break; - } - } - - if (cardContainsKeys) { + if (containsKeys(scannedFingerprints)) { try { long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints); CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId); @@ -146,25 +141,29 @@ public class CreateKeyActivity extends BaseNfcActivity { finish(); } catch (PgpKeyNotFoundException e) { - Fragment frag = CreateKeyYubiKeyImportFragment.createInstance( + Fragment frag = CreateKeyYubiKeyImportFragment.newInstance( scannedFingerprints, nfcAid, userId); loadFragment(frag, FragAction.TO_RIGHT); } } else { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.first_time_blank_smartcard_title) - .setMessage(R.string.first_time_blank_smartcard_message) - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int button) { - CreateKeyActivity.this.mUseSmartCardSettings = true; - } - }) - .setNegativeButton(android.R.string.no, null).show(); + Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); + loadFragment(frag, FragAction.TO_RIGHT); } } + private boolean containsKeys(byte[] scannedFingerprints) { + // If all fingerprint bytes are 0, the card contains no keys. + boolean cardContainsKeys = false; + for (byte b : scannedFingerprints) { + if (b != 0) { + cardContainsKeys = true; + break; + } + } + return cardContainsKeys; + } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -182,7 +181,7 @@ public class CreateKeyActivity extends BaseNfcActivity { setContentView(R.layout.create_key_activity); } - public static enum FragAction { + public enum FragAction { START, TO_RIGHT, TO_LEFT diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index ebbd01afe..09ab1e663 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -20,11 +20,11 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Messenger; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -37,19 +37,24 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainService; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; import java.util.Iterator; -public class CreateKeyFinalFragment extends Fragment { +public class CreateKeyFinalFragment extends CryptoOperationFragment { public static final int REQUEST_EDIT_KEY = 0x00008007; @@ -129,6 +134,11 @@ public class CreateKeyFinalFragment extends Fragment { } }); + // If this is a debug build, don't upload by default + if (Constants.DEBUG) { + mUploadCheckbox.setChecked(false); + } + return view; } @@ -164,6 +174,7 @@ public class CreateKeyFinalFragment extends Fragment { mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA, 2048, null, KeyFlags.AUTHENTICATION, 0L)); mEditText.setText(R.string.create_key_custom); + mEditButton.setEnabled(false); } else { mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA, 4096, null, KeyFlags.CERTIFY_OTHER, 0L)); @@ -192,8 +203,9 @@ public class CreateKeyFinalFragment extends Fragment { } } - private void createKey() { + final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity(); + Intent intent = new Intent(getActivity(), KeychainService.class); intent.setAction(KeychainService.ACTION_EDIT_KEYRING); @@ -216,25 +228,29 @@ public class CreateKeyFinalFragment extends Fragment { return; } + if (createKeyActivity.mUseSmartCardSettings) { + // save key id in between + mSaveKeyringParcel.mMasterKeyId = result.mMasterKeyId; + cryptoOperation(new CryptoInputParcel()); + return; + } + if (result.mMasterKeyId != null && mUploadCheckbox.isChecked()) { // result will be displayed after upload uploadKey(result); - } else { - Intent data = new Intent(); - data.putExtra(OperationResult.EXTRA_RESULT, result); - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); + return; } + + Intent data = new Intent(); + data.putExtra(OperationResult.EXTRA_RESULT, result); + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); } } }; - // fill values for this action Bundle data = new Bundle(); - - // get selected key entries data.putParcelable(KeychainService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel); - intent.putExtra(KeychainService.EXTRA_DATA, data); // Create a new Messenger for the communication back @@ -247,6 +263,55 @@ public class CreateKeyFinalFragment extends Fragment { getActivity().startService(intent); } + // currently only used for moveToCard + @Override + protected SaveKeyringParcel createOperationInput() { + CachedPublicKeyRing key = (new ProviderHelper(getActivity())) + .getCachedPublicKeyRing(mSaveKeyringParcel.mMasterKeyId); + + // overwrite mSaveKeyringParcel! + try { + mSaveKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint()); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "Key that should be moved to YubiKey not found in database!"); + return null; + } + + Cursor cursor = getActivity().getContentResolver().query( + KeychainContract.Keys.buildKeysUri(mSaveKeyringParcel.mMasterKeyId), + new String[]{KeychainContract.Keys.KEY_ID,}, null, null, null + ); + try { + while (cursor != null && cursor.moveToNext()) { + long subkeyId = cursor.getLong(0); + mSaveKeyringParcel.getOrCreateSubkeyChange(subkeyId).mMoveKeyToCard = true; + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return mSaveKeyringParcel; + } + + // currently only used for moveToCard + @Override + protected void onCryptoOperationSuccess(OperationResult result) { + EditKeyResult editResult = (EditKeyResult) result; + + if (editResult.mMasterKeyId != null && mUploadCheckbox.isChecked()) { + // result will be displayed after upload + uploadKey(editResult); + return; + } + + Intent data = new Intent(); + data.putExtra(OperationResult.EXTRA_RESULT, result); + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); + } + // TODO move into EditKeyOperation private void uploadKey(final EditKeyResult saveKeyResult) { // Send all information needed to service to upload key in other thread @@ -259,7 +324,6 @@ public class CreateKeyFinalFragment extends Fragment { saveKeyResult.mMasterKeyId); intent.setData(blobUri); - // fill values for this action Bundle data = new Bundle(); // upload to favorite keyserver @@ -300,7 +364,6 @@ public class CreateKeyFinalFragment extends Fragment { // start service with intent getActivity().startService(intent); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java new file mode 100644 index 000000000..6df340636 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java @@ -0,0 +1,90 @@ +/* + * 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.ui; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; + +public class CreateKeyYubiKeyBlankFragment extends Fragment { + + CreateKeyActivity mCreateKeyActivity; + View mBackButton; + View mNextButton; + + /** + * Creates new instance of this fragment + */ + public static CreateKeyYubiKeyBlankFragment newInstance() { + CreateKeyYubiKeyBlankFragment frag = new CreateKeyYubiKeyBlankFragment(); + + Bundle args = new Bundle(); + + frag.setArguments(args); + + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.create_yubi_key_blank_fragment, container, false); + + mBackButton = view.findViewById(R.id.create_key_back_button); + mNextButton = view.findViewById(R.id.create_key_next_button); + + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (getFragmentManager().getBackStackEntryCount() == 0) { + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); + } else { + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); + } + } + }); + mNextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + nextClicked(); + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + + private void nextClicked() { + mCreateKeyActivity.mUseSmartCardSettings = true; + + CreateKeyNameFragment frag = CreateKeyNameFragment.newInstance(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java index 2ab8c5967..a575dc6b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java @@ -64,7 +64,7 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe private TextView vSerNo; private TextView vUserId; - public static Fragment createInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) { + public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) { CreateKeyYubiKeyImportFragment frag = new CreateKeyYubiKeyImportFragment(); @@ -95,7 +95,7 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.create_yubikey_import_fragment, container, false); + View view = inflater.inflate(R.layout.create_yubi_key_import_fragment, container, false); vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); vUserId = (TextView) view.findViewById(R.id.yubikey_userid); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java index 0b8586c0a..0e2dd2531 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java @@ -35,7 +35,7 @@ public class CreateKeyYubiKeyWaitFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.create_yubikey_wait_fragment, container, false); + View view = inflater.inflate(R.layout.create_yubi_key_wait_fragment, container, false); mBackButton = view.findViewById(R.id.create_key_back_button); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index c5fc9abe0..addfb6a23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -63,7 +63,7 @@ public class NfcOperationActivity extends BaseNfcActivity { mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT); // obtain passphrase for this subkey - if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_KEYTOCARD) { + if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD) { obtainYubiKeyPin(mRequiredInput); } } @@ -96,7 +96,7 @@ public class NfcOperationActivity extends BaseNfcActivity { } break; } - case NFC_KEYTOCARD: { + case NFC_MOVE_KEY_TO_CARD: { ProviderHelper providerHelper = new ProviderHelper(this); CanonicalizedSecretKeyRing secretKeyRing; try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index a28a5ea59..cb250d28c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -269,7 +269,7 @@ public abstract class BaseNfcActivity extends BaseActivity { * This method is called by onNewIntent above upon discovery of an NFC tag. * It handles initialization and login to the application, subsequently * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then - * finishes the activity with an appropiate result. + * finishes the activity with an appropriate result. * * On general communication, see also * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java index 764602735..245abc21f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java @@ -52,7 +52,7 @@ public abstract class CryptoOperationFragment Date: Mon, 29 Jun 2015 21:17:12 +0200 Subject: Connect YubiKey URL to OpenKeychain --- .../keychain/ui/CreateKeyActivity.java | 28 ++++++++++++++++++---- .../keychain/ui/base/BaseNfcActivity.java | 4 ++-- 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index fbe7b4066..505638c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; +import android.nfc.NfcAdapter; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; @@ -62,6 +63,23 @@ public class CreateKeyActivity extends BaseNfcActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // React on NDEF_DISCOVERED from Manifest + // NOTE: ACTION_NDEF_DISCOVERED and not ACTION_TAG_DISCOVERED like in BaseNfcActivity + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { + try { + handleTagDiscoveredIntent(getIntent()); + } catch (CardException e) { + handleNfcError(e); + } catch (IOException e) { + handleNfcError(e); + } + + setTitle(R.string.title_manage_my_keys); + + // done + return; + } + // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore value of members from saved state @@ -96,14 +114,16 @@ public class CreateKeyActivity extends BaseNfcActivity { } else { Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); loadFragment(frag, FragAction.START); + setTitle(R.string.title_manage_my_keys); } + + // done return; - } else { - // normal key creation - CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); - loadFragment(frag, FragAction.START); } + // normal key creation + CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); + loadFragment(frag, FragAction.START); } if (mFirstTime) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index cb250d28c..bede16b2a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -94,7 +94,7 @@ public abstract class BaseNfcActivity extends BaseActivity { public void onNewIntent(Intent intent) { if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { try { - handleNdefDiscoveredIntent(intent); + handleTagDiscoveredIntent(intent); } catch (CardException e) { handleNfcError(e); } catch (IOException e) { @@ -278,7 +278,7 @@ public abstract class BaseNfcActivity extends BaseActivity { * on ISO SmartCard Systems specification. * */ - protected void handleNdefDiscoveredIntent(Intent intent) throws IOException { + protected void handleTagDiscoveredIntent(Intent intent) throws IOException { Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); -- cgit v1.2.3 From bdddeb0f41a081aad909f4d9b76a9e4aaa61f28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 21:40:07 +0200 Subject: Return metadata for cleartext sigs --- .../java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 7a4c85178..6a3031bbb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -938,7 +938,14 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_OK, indent); + OpenPgpMetadata metadata = new OpenPgpMetadata( + "", + "text/plain", + 0, + 0); + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setDecryptMetadata(metadata); result.setSignatureResult(signatureResultBuilder.build()); return result; } -- cgit v1.2.3 From 13bbda1012b556af3e17e66a32a5879e74160683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 29 Jun 2015 23:15:55 +0200 Subject: Use proper length and mod time for cleartext signature metadata --- .../java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 6a3031bbb..a6d260d22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -941,8 +941,8 @@ public class PgpDecryptVerify extends BaseOperation OpenPgpMetadata metadata = new OpenPgpMetadata( "", "text/plain", - 0, - 0); + -1, + clearText.length); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setDecryptMetadata(metadata); -- cgit v1.2.3 From 340f2e442a93e4b3ab2c223fc4ab679f09f75ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 30 Jun 2015 12:58:40 +0200 Subject: Disable YubiKey key creation for release --- .../keychain/ui/CreateKeyActivity.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 505638c7c..c72dbde16 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; @@ -112,9 +113,13 @@ public class CreateKeyActivity extends BaseNfcActivity { setTitle(R.string.title_import_keys); } else { - Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); - loadFragment(frag, FragAction.START); - setTitle(R.string.title_manage_my_keys); +// Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); +// loadFragment(frag, FragAction.START); +// setTitle(R.string.title_manage_my_keys); + Notify.create(this, + "YubiKey key creation is currently not supported. Please follow our FAQ.", + Notify.Style.ERROR + ).show(); } // done @@ -166,8 +171,12 @@ public class CreateKeyActivity extends BaseNfcActivity { loadFragment(frag, FragAction.TO_RIGHT); } } else { - Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); - loadFragment(frag, FragAction.TO_RIGHT); +// Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); +// loadFragment(frag, FragAction.TO_RIGHT); + Notify.create(this, + "YubiKey key creation is currently not supported. Please follow our FAQ.", + Notify.Style.ERROR + ).show(); } } -- cgit v1.2.3 From ddf7f5006203d0da087cc46321504530a02d6ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 30 Jun 2015 13:39:37 +0200 Subject: Revert "Disable YubiKey key creation for release" This reverts commit 340f2e442a93e4b3ab2c223fc4ab679f09f75ecd. --- .../keychain/ui/CreateKeyActivity.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index c72dbde16..505638c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -30,7 +30,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; @@ -113,13 +112,9 @@ public class CreateKeyActivity extends BaseNfcActivity { setTitle(R.string.title_import_keys); } else { -// Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); -// loadFragment(frag, FragAction.START); -// setTitle(R.string.title_manage_my_keys); - Notify.create(this, - "YubiKey key creation is currently not supported. Please follow our FAQ.", - Notify.Style.ERROR - ).show(); + Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); + loadFragment(frag, FragAction.START); + setTitle(R.string.title_manage_my_keys); } // done @@ -171,12 +166,8 @@ public class CreateKeyActivity extends BaseNfcActivity { loadFragment(frag, FragAction.TO_RIGHT); } } else { -// Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); -// loadFragment(frag, FragAction.TO_RIGHT); - Notify.create(this, - "YubiKey key creation is currently not supported. Please follow our FAQ.", - Notify.Style.ERROR - ).show(); + Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance(); + loadFragment(frag, FragAction.TO_RIGHT); } } -- cgit v1.2.3 From 27441c7d63175255d1a50e96ad6418592666a3db Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 30 Jun 2015 15:13:28 +0200 Subject: fail more gracefully on empty clipboard in DecryptActivity --- .../java/org/sufficientlysecure/keychain/ui/DecryptActivity.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 4375be740..04f54f151 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -120,7 +120,14 @@ public class DecryptActivity extends BaseActivity { case ACTION_DECRYPT_FROM_CLIPBOARD: { ClipboardManager clipMan = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + break; + } + ClipData clip = clipMan.getPrimaryClip(); + if (clip == null) { + break; + } // check if data is available as uri Uri uri = null; -- cgit v1.2.3 From f1c0c3e00c7287cdc501cd9148461f4c1ef1d8ec Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 30 Jun 2015 15:15:03 +0200 Subject: earlier error on empty clipboard --- .../ui/EncryptDecryptOverviewFragment.java | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java index 590d02c6f..44ca50e6c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java @@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; import org.sufficientlysecure.keychain.util.FileHelper; @@ -92,15 +93,30 @@ public class EncryptDecryptOverviewFragment extends Fragment { mDecryptFromClipboard.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class); - clipboardDecrypt.setAction(DecryptActivity.ACTION_DECRYPT_FROM_CLIPBOARD); - startActivityForResult(clipboardDecrypt, 0); + decryptFromClipboard(); } }); return view; } + private void decryptFromClipboard() { + + Activity activity = getActivity(); + if (activity == null) { + return; + } + + final CharSequence clipboardText = ClipboardReflection.getClipboardText(activity); + if (clipboardText == null) { + Notify.create(activity, R.string.error_clipboard_empty, Style.ERROR); + } + + Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class); + clipboardDecrypt.setAction(DecryptActivity.ACTION_DECRYPT_FROM_CLIPBOARD); + startActivityForResult(clipboardDecrypt, 0); + } + @Override public void onResume() { super.onResume(); -- cgit v1.2.3 From 473866baaf5c736de74cc8b95f8acc84631c1043 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 30 Jun 2015 15:37:02 +0200 Subject: instrument: add test for empty clipboard, fix empty clipboard error --- .../keychain/ui/EncryptDecryptOverviewFragment.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java index 44ca50e6c..779b22535 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java @@ -29,6 +29,7 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -108,8 +109,9 @@ public class EncryptDecryptOverviewFragment extends Fragment { } final CharSequence clipboardText = ClipboardReflection.getClipboardText(activity); - if (clipboardText == null) { - Notify.create(activity, R.string.error_clipboard_empty, Style.ERROR); + if (clipboardText == null || TextUtils.isEmpty(clipboardText)) { + Notify.create(activity, R.string.error_clipboard_empty, Style.ERROR).show(); + return; } Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class); -- cgit v1.2.3 From 04d7e3f155e182b0abaebd9a37b43634a20e3ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 30 Jun 2015 16:20:46 +0200 Subject: Cleanup preference code --- .../keychain/ui/SettingsActivity.java | 44 ++-------------------- 1 file changed, 3 insertions(+), 41 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 442bdf8f7..71f07d785 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2014-2015 Dominik Schürmann * Copyright (C) 2010-2014 Thialfihar * * This program is free software: you can redistribute it and/or modify @@ -17,10 +18,8 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; @@ -32,7 +31,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; @@ -91,22 +89,6 @@ public class SettingsActivity extends PreferenceActivity { initializePassphraseCacheTtl( (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - int[] valueIds = new int[]{ - CompressionAlgorithmTags.UNCOMPRESSED, - CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.BZIP2, - }; - String[] entries = new String[]{ - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")",}; - String[] values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - initializeUseDefaultYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); @@ -168,7 +150,7 @@ public class SettingsActivity extends PreferenceActivity { } /** - * This fragment shows the Cloud Search preferences in android 3.0+ + * This fragment shows the Cloud Search preferences */ public static class CloudSearchPrefsFragment extends PreferenceFragment { @@ -226,7 +208,7 @@ public class SettingsActivity extends PreferenceActivity { } /** - * This fragment shows the advanced preferences in android 3.0+ + * This fragment shows the PIN/password preferences */ public static class AdvancedPrefsFragment extends PreferenceFragment { @@ -243,25 +225,6 @@ public class SettingsActivity extends PreferenceActivity { initializePassphraseCacheTtl( (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - int[] valueIds = new int[]{ - CompressionAlgorithmTags.UNCOMPRESSED, - CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.BZIP2, - }; - - String[] entries = new String[]{ - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")", - }; - - String[] values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - initializeUseDefaultYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); @@ -270,7 +233,6 @@ public class SettingsActivity extends PreferenceActivity { } } - @TargetApi(Build.VERSION_CODES.KITKAT) protected boolean isValidFragment(String fragmentName) { return AdvancedPrefsFragment.class.getName().equals(fragmentName) || CloudSearchPrefsFragment.class.getName().equals(fragmentName) -- cgit v1.2.3 From d26379da3a4379ad260f3e68bf264d7a3530e376 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 30 Jun 2015 16:28:55 +0200 Subject: make timeout method in PassphraseCacheService more robust against nullpointers --- .../keychain/service/PassphraseCacheService.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index a0b470add..7c0b7eaef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -459,11 +459,16 @@ public class PassphraseCacheService extends Service { * Called when one specific passphrase for keyId timed out */ private void timeout(long keyId) { + CachedPassphrase cPass = mPassphraseCache.get(keyId); - // clean internal char[] from memory! - cPass.getPassphrase().removeFromMemory(); - // remove passphrase object - mPassphraseCache.remove(keyId); + if (cPass != null) { + if (cPass.getPassphrase() != null) { + // clean internal char[] from memory! + cPass.getPassphrase().removeFromMemory(); + } + // remove passphrase object + mPassphraseCache.remove(keyId); + } Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!"); -- cgit v1.2.3 From 715188ccdaf9659aec2fec348505cd7675b62f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 30 Jun 2015 17:14:12 +0200 Subject: Better settings workarounds --- .../compatibility/AppCompatPreferenceActivity.java | 127 +++++++++++++++++++++ .../keychain/ui/SettingsActivity.java | 7 +- 2 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java new file mode 100644 index 000000000..5200b8ced --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java @@ -0,0 +1,127 @@ + +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sufficientlysecure.keychain.compatibility; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.support.annotation.LayoutRes; +import android.support.annotation.Nullable; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatDelegate; +import android.support.v7.widget.Toolbar; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls + * to be used with AppCompat. + *

+ * This technique can be used with an {@link android.app.Activity} class, not just + * {@link android.preference.PreferenceActivity}. + */ +public abstract class AppCompatPreferenceActivity extends PreferenceActivity { + private AppCompatDelegate mDelegate; + + @Override + protected void onCreate(Bundle savedInstanceState) { + getDelegate().installViewFactory(); + getDelegate().onCreate(savedInstanceState); + super.onCreate(savedInstanceState); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + getDelegate().onPostCreate(savedInstanceState); + } + + public ActionBar getSupportActionBar() { + return getDelegate().getSupportActionBar(); + } + + public void setSupportActionBar(@Nullable Toolbar toolbar) { + getDelegate().setSupportActionBar(toolbar); + } + + @Override + public MenuInflater getMenuInflater() { + return getDelegate().getMenuInflater(); + } + + @Override + public void setContentView(@LayoutRes int layoutResID) { + getDelegate().setContentView(layoutResID); + } + + @Override + public void setContentView(View view) { + getDelegate().setContentView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().setContentView(view, params); + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().addContentView(view, params); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getDelegate().onPostResume(); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + super.onTitleChanged(title, color); + getDelegate().setTitle(title); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getDelegate().onConfigurationChanged(newConfig); + } + + @Override + protected void onStop() { + super.onStop(); + getDelegate().onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + getDelegate().onDestroy(); + } + + public void invalidateOptionsMenu() { + getDelegate().invalidateOptionsMenu(); + } + + private AppCompatDelegate getDelegate() { + if (mDelegate == null) { + mDelegate = AppCompatDelegate.create(this, null); + } + return mDelegate; + } +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 71f07d785..a552e1c55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; -import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.support.v7.widget.Toolbar; @@ -33,12 +32,13 @@ import android.widget.LinearLayout; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.AppCompatPreferenceActivity; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; import org.sufficientlysecure.keychain.util.Preferences; import java.util.List; -public class SettingsActivity extends PreferenceActivity { +public class SettingsActivity extends AppCompatPreferenceActivity { public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD"; public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; @@ -104,13 +104,14 @@ public class SettingsActivity extends PreferenceActivity { private void setupToolbar() { ViewGroup root = (ViewGroup) findViewById(android.R.id.content); LinearLayout content = (LinearLayout) root.getChildAt(0); - LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar_activity, null); + LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar, null); root.removeAllViews(); toolbarContainer.addView(content); root.addView(toolbarContainer); Toolbar toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar); + toolbar.setTitle(R.string.title_preferences); toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp)); toolbar.setNavigationOnClickListener(new View.OnClickListener() { -- cgit v1.2.3