aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src
diff options
context:
space:
mode:
authormar-v-in <github@rvin.mooo.com>2014-07-01 14:50:15 +0200
committermar-v-in <github@rvin.mooo.com>2014-07-01 14:50:15 +0200
commit35647734104471a6d35bc26a77682dd5531dd5e3 (patch)
tree0a70b9789fdf5d723ad9268f0f7621d6983547fa /OpenKeychain/src
parent50e72b196fa8bc97edc63198a9ad73c24770b9df (diff)
downloadopen-keychain-35647734104471a6d35bc26a77682dd5531dd5e3.tar.gz
open-keychain-35647734104471a6d35bc26a77682dd5531dd5e3.tar.bz2
open-keychain-35647734104471a6d35bc26a77682dd5531dd5e3.zip
Add temporary file storage as discussed in #665
Writable from OpenKeychain, readable worldwide. Should be used to write shared files to it by first creating the file using TemporaryStorageProvider.createFile and then write to the Uri returned.
Diffstat (limited to 'OpenKeychain/src')
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java151
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/DatabaseUtil.java36
5 files changed, 201 insertions, 0 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 3ce200008..6a67ac9bf 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -49,6 +49,9 @@
android:name="android.hardware.touchscreen"
android:required="false" />
+ <permission android:name="org.sufficientlysecure.keychain.WRITE_TEMPORARY_STORAGE"/>
+ <uses-permission android:name="org.sufficientlysecure.keychain.WRITE_TEMPORARY_STORAGE"/>
+
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC" />
@@ -484,6 +487,12 @@
android:resource="@xml/custom_pgp_contacts_structure"/>
</service>
+ <provider
+ android:name=".provider.TemporaryStorageProvider"
+ android:authorities="org.sufficientlysecure.keychain.tempstorage"
+ android:writePermission="org.sufficientlysecure.keychain.WRITE_TEMPORARY_STORAGE"
+ android:exported="true"/>
+
</application>
</manifest>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index eeb9fa389..956019605 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -53,6 +53,8 @@ public final class Constants {
public static boolean KITKAT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+ public static int TEMPFILE_TTL = 24*60*60*1000; // 1 day
+
public static final class Path {
public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), "OpenKeychain");
public static final File APP_DIR_FILE = new File(APP_DIR, "export.asc");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index be9c1e405..125573b53 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -28,6 +28,7 @@ import android.os.Environment;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.helper.TlsHelper;
+import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes;
@@ -85,6 +86,8 @@ public class KeychainApplication extends Application {
Preferences.getPreferences(this).updateKeyServers();
TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");
+
+ TemporaryStorageProvider.cleanUp(this);
}
public static void setupAccountAsNeeded(Context context) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
new file mode 100644
index 000000000..9e745215d
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
@@ -0,0 +1,151 @@
+package org.sufficientlysecure.keychain.provider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+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.ParcelFileDescriptor;
+import android.provider.OpenableColumns;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.util.DatabaseUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public class TemporaryStorageProvider 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 Uri BASE_URI = Uri.parse("content://org.sufficientlysecure.keychain.tempstorage/");
+ private static final int DB_VERSION = 1;
+
+ public static Uri createFile(Context context, String targetName) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(COLUMN_NAME, targetName);
+ return context.getContentResolver().insert(BASE_URI, contentValues);
+ }
+
+ public static int cleanUp(Context context) {
+ return context.getContentResolver().delete(BASE_URI, COLUMN_TIME + "< ?",
+ new String[]{Long.toString(System.currentTimeMillis() - Constants.TEMPFILE_TTL)});
+ }
+
+ private class TemporaryStorageDatabase extends SQLiteOpenHelper {
+
+ public TemporaryStorageDatabase(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_FILES + " (" +
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ COLUMN_NAME + " TEXT, " +
+ COLUMN_TIME + " INTEGER" +
+ ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+ }
+ }
+
+ private TemporaryStorageDatabase db;
+
+ private File getFile(Uri uri) throws FileNotFoundException {
+ try {
+ return getFile(Integer.parseInt(uri.getLastPathSegment()));
+ } catch (NumberFormatException e) {
+ throw new FileNotFoundException();
+ }
+ }
+
+ private File getFile(int id) {
+ return new File(getContext().getCacheDir(), "temp/" + id);
+ }
+
+ @Override
+ public boolean onCreate() {
+ db = new TemporaryStorageDatabase(getContext());
+ return new File(getContext().getCacheDir(), "temp").mkdirs();
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ File file;
+ try {
+ file = getFile(uri);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ Cursor fileName = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_NAME}, COLUMN_ID + "=?",
+ 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());
+ fileName.close();
+ return cursor;
+ }
+ fileName.close();
+ }
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "*/*";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (!values.containsKey(COLUMN_TIME)) {
+ values.put(COLUMN_TIME, System.currentTimeMillis());
+ }
+ int insert = (int) db.getWritableDatabase().insert(TABLE_FILES, null, values);
+ try {
+ getFile(insert).createNewFile();
+ } catch (IOException e) {
+ return null;
+ }
+ return Uri.withAppendedPath(BASE_URI, Long.toString(insert));
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (uri.getLastPathSegment() != null) {
+ selection = DatabaseUtil.concatenateWhere(selection, COLUMN_ID + "=?");
+ selectionArgs = DatabaseUtil.appendSelectionArgs(selectionArgs, new String[]{uri.getLastPathSegment()});
+ }
+ Cursor files = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_ID}, selection,
+ selectionArgs, null, null, null);
+ if (files != null) {
+ while (files.moveToNext()) {
+ getFile(files.getInt(0)).delete();
+ }
+ files.close();
+ return db.getWritableDatabase().delete(TABLE_FILES, selection, selectionArgs);
+ }
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("Update not supported");
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ return openFileHelper(uri, mode);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/DatabaseUtil.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/DatabaseUtil.java
new file mode 100644
index 000000000..c18e5cabd
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/DatabaseUtil.java
@@ -0,0 +1,36 @@
+package org.sufficientlysecure.keychain.util;
+
+import android.text.TextUtils;
+
+/**
+ * Shamelessly copied from android.database.DatabaseUtils
+ */
+public class DatabaseUtil {
+ /**
+ * Concatenates two SQL WHERE clauses, handling empty or null values.
+ */
+ public static String concatenateWhere(String a, String b) {
+ if (TextUtils.isEmpty(a)) {
+ return b;
+ }
+ if (TextUtils.isEmpty(b)) {
+ return a;
+ }
+
+ return "(" + a + ") AND (" + b + ")";
+ }
+
+ /**
+ * Appends one set of selection args to another. This is useful when adding a selection
+ * argument to a user provided set.
+ */
+ public static String[] appendSelectionArgs(String[] originalValues, String[] newValues) {
+ if (originalValues == null || originalValues.length == 0) {
+ return newValues;
+ }
+ String[] result = new String[originalValues.length + newValues.length ];
+ System.arraycopy(originalValues, 0, result, 0, originalValues.length);
+ System.arraycopy(newValues, 0, result, originalValues.length, newValues.length);
+ return result;
+ }
+}