aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
+ }
+}