diff options
author | Markus Doits <markus.doits@googlemail.com> | 2011-11-04 21:22:49 +0100 |
---|---|---|
committer | Markus Doits <markus.doits@googlemail.com> | 2011-11-04 21:22:49 +0100 |
commit | ad1657465778c05cef7a7ba9d25f97943cf68144 (patch) | |
tree | 3fadab61a099b49f8a9ac49f3d3abe5240f8996e /src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java | |
parent | a7294d50b1f6a7f0ab30118602a1fcbdad0b8169 (diff) | |
download | open-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.tar.gz open-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.tar.bz2 open-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.zip |
Allow to pass large blobs and a new content provider to simplify this
Since AIDL is not for passing large data, a blob can be passed to APG by
a Uri. This Uri is opened as a file by APG and read/written to. Note the
file is overwritten by APG, so make sure it is a copy if you want to
keep the original.
With the ApgServiceBlobProvider, Apg has an own ContentProvider that can
be used like mentioned above. For now the data is stored in the dir
where APG stores other files and NOT DELETED after en/decryption. This
is tbd. It can only be accessed by an application with the permission
"org.thialfihar.android.apg.permission.STORE_BLOBS".
ApgCon has been updated accordingly and can handle blobs with `setBlob`
and `getBlobResult`. That is a really easy way to en/decrypt large data.
Note that encrypting by blob should only be used for large files (1MB+).
On all other cases, the data should be passed as as String through the
AIDl-Interface, so no temporary file must be created.
See ApgCon for a complete example of how to connect to the AIDL and use
it. Or use it in your own project!
Diffstat (limited to 'src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java')
-rw-r--r-- | src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java b/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java new file mode 100644 index 000000000..fd4145f4c --- /dev/null +++ b/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java @@ -0,0 +1,138 @@ +package org.thialfihar.android.apg.provider; + +import org.thialfihar.android.apg.ApgService; +import org.thialfihar.android.apg.Constants; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class ApgServiceBlobProvider extends ContentProvider { + + private static final String TAG = "ApgServiceBlobProvider"; + + public static final Uri CONTENT_URI = Uri.parse("content://org.thialfihar.android.apg.provider.apgserviceblobprovider"); + + private static final String COLUMN_KEY = "key"; + + private static final String STORE_PATH = Constants.path.app_dir+"/ApgServiceBlobs"; + + private ApgServiceBlobDatabase mDb = null; + + public ApgServiceBlobProvider() { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "Constructor called"); + File dir = new File(STORE_PATH); + dir.mkdirs(); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "Constructor finished"); + } + + @Override + public int delete(Uri arg0, String arg1, String[] arg2) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "delete() called"); + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getType(Uri arg0) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "getType() called"); + // not needed for now + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues ignored) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "insert() called"); + // ContentValues are actually ignored, because we want to store a blob with no more information + // but have to create an record with the password generated here first + + ContentValues vals = new ContentValues(); + + // Insert a random key in the database. This has to provided by the caller when updating or + // getting the blob + String password = UUID.randomUUID().toString(); + vals.put(COLUMN_KEY, password); + + Uri insertedUri = mDb.insert(vals); + return Uri.withAppendedPath(insertedUri, password); + } + + @Override + public boolean onCreate() { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "onCreate() called"); + mDb = new ApgServiceBlobDatabase(getContext()); + // TODO Auto-generated method stub + return true; + } + + @Override + public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "query() called"); + // TODO Auto-generated method stub + return null; + } + + @Override + public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "update() called"); + // TODO Auto-generated method stub + return 0; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, FileNotFoundException { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "openFile() called"); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... with uri: "+uri.toString()); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... with mode: "+mode); + + List<String> segments = uri.getPathSegments(); + if(segments.size() < 2) { + throw new SecurityException("Password not found in URI"); + } + String id = segments.get(0); + String key = segments.get(1); + + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... got id: "+id); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... and key: "+key); + + // get the data + Cursor result = mDb.query(id, key); + + if(result.getCount() == 0) { + // either the key is wrong or no id exists + throw new FileNotFoundException("No file found with that ID and/or password"); + } + + File targetFile = new File(STORE_PATH, id); + if(mode.equals("w")) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... will try to open file w"); + if( !targetFile.exists() ) { + try { + targetFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "... got IEOException on creating new file", e); + throw new FileNotFoundException("Could not create file to write to"); + } + } + return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE ); + } else if(mode.equals("r")) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... will try to open file r"); + if( !targetFile.exists() ) { + throw new FileNotFoundException("Error: Could not find the file requested"); + } + return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); + } + + return null; + } + +} |