From 7384fa7f2b4ff158e65cda787a58b64dc306691c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 15 Oct 2015 19:37:08 +0200 Subject: [PATCH] Rename TemporaryStorageProvider to TemporaryFileProvider, use interface for db contract --- .../ui/SymmetricTextOperationTests.java | 4 +- .../keychain/ui/ViewKeyAdvShareTest.java | 6 +- OpenKeychain/src/main/AndroidManifest.xml | 2 +- .../keychain/KeychainApplication.java | 4 +- .../keychain/operations/ExportOperation.java | 4 +- .../operations/InputDataOperation.java | 10 +-- ...ovider.java => TemporaryFileProvider.java} | 68 +++++++++++-------- .../keychain/ui/BackupCodeFragment.java | 4 +- .../keychain/ui/DecryptActivity.java | 4 +- .../keychain/ui/EncryptFilesFragment.java | 6 +- .../keychain/ui/LogDisplayFragment.java | 4 +- .../keychain/ui/ViewKeyAdvShareFragment.java | 6 +- .../keychain/operations/ExportTest.java | 4 +- .../keychain/pgp/InputDataOperationTest.java | 8 +-- 14 files changed, 71 insertions(+), 63 deletions(-) rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/{TemporaryStorageProvider.java => TemporaryFileProvider.java} (82%) diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java index 498df7299..ba5eb7491 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java @@ -32,7 +32,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import static android.support.test.InstrumentationRegistry.getInstrumentation; @@ -133,7 +133,7 @@ public class SymmetricTextOperationTests { hasExtra(equalTo(Intent.EXTRA_INTENT), allOf( hasAction(Intent.ACTION_VIEW), hasFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION), - hasData(allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY))), + hasData(allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY))), hasType("text/plain") )) )).respondWith(new ActivityResult(Activity.RESULT_OK, null)); diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java index 63c7dc6de..edc5571fe 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java @@ -34,7 +34,7 @@ import org.junit.runners.MethodSorters; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import static android.support.test.espresso.Espresso.onView; @@ -96,7 +96,7 @@ public class ViewKeyAdvShareTest { hasType("text/plain"), hasExtra(is(Intent.EXTRA_TEXT), is("openpgp4fpr:c619d53f7a5f96f391a84ca79d604d2f310716a3")), hasExtra(is(Intent.EXTRA_STREAM), - allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY))) + allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY))) )) )).respondWith(new ActivityResult(Activity.RESULT_OK, null)); onView(withId(R.id.view_key_action_fingerprint_share)).perform(click()); @@ -113,7 +113,7 @@ public class ViewKeyAdvShareTest { hasType("text/plain"), hasExtra(is(Intent.EXTRA_TEXT), startsWith("----")), hasExtra(is(Intent.EXTRA_STREAM), - allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY))) + allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY))) )) )).respondWith(new ActivityResult(Activity.RESULT_OK, null)); onView(withId(R.id.view_key_action_key_share)).perform(click()); diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 2f31d6d63..3cac4ed10 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -845,7 +845,7 @@ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index ebd48b9a5..5d97dac8a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -33,7 +33,7 @@ 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.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; @@ -102,7 +102,7 @@ public class KeychainApplication extends Application { TlsHelper.addPinnedCertificate("pgp.mit.edu", getAssets(), "pgp.mit.edu.cer"); TlsHelper.addPinnedCertificate("api.keybase.io", getAssets(), "api.keybase.io.CA.cer"); - TemporaryStorageProvider.cleanUp(this); + TemporaryFileProvider.cleanUp(this); if (!checkConsolidateRecovery()) { // force DB upgrade, https://github.com/open-keychain/open-keychain/issues/1334 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java index ecff9f5ae..5f77a3224 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java @@ -54,7 +54,7 @@ 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.TemporaryStorageProvider; +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; @@ -111,7 +111,7 @@ public class ExportOperation extends BaseOperation { Uri exportOutputUri = nonEncryptedOutput ? exportInput.mOutputUri - : TemporaryStorageProvider.createFile(mContext); + : TemporaryFileProvider.createFile(mContext); int exportedDataSize; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java index c48ccc500..2b91cd06c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java @@ -48,7 +48,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.InputDataParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -101,7 +101,7 @@ public class InputDataOperation extends BaseOperation { decryptInput.setInputUri(input.getInputUri()); - currentInputUri = TemporaryStorageProvider.createFile(mContext); + currentInputUri = TemporaryFileProvider.createFile(mContext); decryptInput.setOutputUri(currentInputUri); decryptResult = op.execute(decryptInput, cryptoInput); @@ -117,7 +117,7 @@ public class InputDataOperation extends BaseOperation { // inform the storage provider about the mime type for this uri if (decryptResult.getDecryptionMetadata() != null) { - TemporaryStorageProvider.setMimeType(mContext, currentInputUri, + TemporaryFileProvider.setMimeType(mContext, currentInputUri, decryptResult.getDecryptionMetadata().getMimeType()); } @@ -195,7 +195,7 @@ public class InputDataOperation extends BaseOperation { log.add(LogType.MSG_DATA_DETACHED_RAW, 3); - uncheckedSignedDataUri = TemporaryStorageProvider.createFile(mContext, mFilename, "text/plain"); + uncheckedSignedDataUri = TemporaryFileProvider.createFile(mContext, mFilename, "text/plain"); OutputStream out = mContext.getContentResolver().openOutputStream(uncheckedSignedDataUri, "w"); if (out == null) { @@ -297,7 +297,7 @@ public class InputDataOperation extends BaseOperation { log.add(LogType.MSG_DATA_MIME_FILENAME, 3, mFilename); } - Uri uri = TemporaryStorageProvider.createFile(mContext, mFilename, bd.getMimeType()); + Uri uri = TemporaryFileProvider.createFile(mContext, mFilename, bd.getMimeType()); OutputStream out = mContext.getContentResolver().openOutputStream(uri, "w"); if (out == null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java similarity index 82% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java index 67f2c36bc..2995ae88a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java @@ -43,14 +43,14 @@ 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 @@ -59,30 +59,33 @@ import java.util.UUID; * - 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 { +public class TemporaryFileProvider extends ContentProvider { private static final String DB_NAME = "tempstorage.db"; private static final String TABLE_FILES = "files"; - private static final String COLUMN_ID = "id"; - private static final String COLUMN_NAME = "name"; - private static final String COLUMN_TIME = "time"; - private static final String COLUMN_TYPE = "mimetype"; public static final String AUTHORITY = Constants.TEMPSTORAGE_AUTHORITY; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); private static final int DB_VERSION = 3; + interface TemporaryFileColumns { + String COLUMN_UUID = "id"; + String COLUMN_NAME = "name"; + String COLUMN_TIME = "time"; + String COLUMN_TYPE = "mimetype"; + } + private static File cacheDir; public static Uri createFile(Context context, String targetName, String mimeType) { ContentValues contentValues = new ContentValues(); - contentValues.put(COLUMN_NAME, targetName); - contentValues.put(COLUMN_TYPE, mimeType); + contentValues.put(TemporaryFileColumns.COLUMN_NAME, targetName); + contentValues.put(TemporaryFileColumns.COLUMN_TYPE, mimeType); return context.getContentResolver().insert(CONTENT_URI, contentValues); } public static Uri createFile(Context context, String targetName) { ContentValues contentValues = new ContentValues(); - contentValues.put(COLUMN_NAME, targetName); + contentValues.put(TemporaryFileColumns.COLUMN_NAME, targetName); return context.getContentResolver().insert(CONTENT_URI, contentValues); } @@ -93,13 +96,16 @@ public class TemporaryStorageProvider extends ContentProvider { public static int setMimeType(Context context, Uri uri, String mimetype) { ContentValues values = new ContentValues(); - values.put(COLUMN_TYPE, mimetype); + values.put(TemporaryFileColumns.COLUMN_TYPE, mimetype); return context.getContentResolver().update(uri, values, null, null); } public static int cleanUp(Context context) { - return context.getContentResolver().delete(CONTENT_URI, COLUMN_TIME + "< ?", - new String[]{Long.toString(System.currentTimeMillis() - Constants.TEMPFILE_TTL)}); + return context.getContentResolver().delete( + CONTENT_URI, + TemporaryFileColumns.COLUMN_TIME + "< ?", + new String[]{Long.toString(System.currentTimeMillis() - Constants.TEMPFILE_TTL)} + ); } private class TemporaryStorageDatabase extends SQLiteOpenHelper { @@ -111,10 +117,10 @@ public class TemporaryStorageProvider extends ContentProvider { @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_FILES + " (" + - COLUMN_ID + " TEXT PRIMARY KEY, " + - COLUMN_NAME + " TEXT, " + - COLUMN_TYPE + " TEXT, " + - COLUMN_TIME + " INTEGER" + + TemporaryFileColumns.COLUMN_UUID + " TEXT PRIMARY KEY, " + + TemporaryFileColumns.COLUMN_NAME + " TEXT, " + + TemporaryFileColumns.COLUMN_TYPE + " TEXT, " + + TemporaryFileColumns.COLUMN_TIME + " INTEGER" + ");"); } @@ -126,12 +132,12 @@ public class TemporaryStorageProvider extends ContentProvider { case 1: db.execSQL("DROP TABLE IF EXISTS files"); db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_FILES + " (" + - COLUMN_ID + " TEXT PRIMARY KEY, " + - COLUMN_NAME + " TEXT, " + - COLUMN_TIME + " INTEGER" + + TemporaryFileColumns.COLUMN_UUID + " TEXT PRIMARY KEY, " + + TemporaryFileColumns.COLUMN_NAME + " TEXT, " + + TemporaryFileColumns.COLUMN_TIME + " INTEGER" + ");"); case 2: - db.execSQL("ALTER TABLE files ADD COLUMN " + COLUMN_TYPE + " TEXT"); + db.execSQL("ALTER TABLE files ADD COLUMN " + TemporaryFileColumns.COLUMN_TYPE + " TEXT"); } } } @@ -176,7 +182,9 @@ public class TemporaryStorageProvider extends ContentProvider { return null; } - Cursor fileName = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_NAME}, COLUMN_ID + "=?", + Cursor fileName = db.getReadableDatabase().query(TABLE_FILES, + new String[]{TemporaryFileColumns.COLUMN_NAME}, + TemporaryFileColumns.COLUMN_UUID + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); if (fileName != null) { if (fileName.moveToNext()) { @@ -200,7 +208,7 @@ 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[]{TemporaryFileColumns.COLUMN_TYPE}, TemporaryFileColumns.COLUMN_UUID + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); if (cursor != null) { try { @@ -227,11 +235,11 @@ public class TemporaryStorageProvider extends ContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { - if (!values.containsKey(COLUMN_TIME)) { - values.put(COLUMN_TIME, System.currentTimeMillis()); + if (!values.containsKey(TemporaryFileColumns.COLUMN_TIME)) { + values.put(TemporaryFileColumns.COLUMN_TIME, System.currentTimeMillis()); } String uuid = UUID.randomUUID().toString(); - values.put(COLUMN_ID, uuid); + values.put(TemporaryFileColumns.COLUMN_UUID, uuid); int insert = (int) db.getWritableDatabase().insert(TABLE_FILES, null, values); if (insert == -1) { Log.e(Constants.TAG, "Insert failed!"); @@ -252,10 +260,10 @@ public class TemporaryStorageProvider extends ContentProvider { return 0; } - selection = DatabaseUtil.concatenateWhere(selection, COLUMN_ID + "=?"); + selection = DatabaseUtil.concatenateWhere(selection, TemporaryFileColumns.COLUMN_UUID + "=?"); selectionArgs = DatabaseUtil.appendSelectionArgs(selectionArgs, new String[]{uri.getLastPathSegment()}); - Cursor files = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_ID}, selection, + Cursor files = db.getReadableDatabase().query(TABLE_FILES, new String[]{TemporaryFileColumns.COLUMN_UUID}, selection, selectionArgs, null, null, null); if (files != null) { while (files.moveToNext()) { @@ -269,14 +277,14 @@ public class TemporaryStorageProvider extends ContentProvider { @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - if (values.size() != 1 || !values.containsKey(COLUMN_TYPE)) { + if (values.size() != 1 || !values.containsKey(TemporaryFileColumns.COLUMN_TYPE)) { throw new UnsupportedOperationException("Update supported only for type field!"); } if (selection != null || selectionArgs != null) { throw new UnsupportedOperationException("Update supported only for plain uri!"); } return db.getWritableDatabase().update(TABLE_FILES, values, - COLUMN_ID + " = ?", new String[]{uri.getLastPathSegment()}); + TemporaryFileColumns.COLUMN_UUID + " = ?", new String[]{uri.getLastPathSegment()}); } @Override 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 ea548e95b..50ad95540 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java @@ -51,7 +51,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.ExportKeyringParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -427,7 +427,7 @@ public class BackupCodeFragment extends CryptoOperationFragment