aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2013-09-15 14:16:29 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2013-09-15 14:16:29 +0200
commit1e188ee2fa0c0573d523bf78811fa05c3e5bbea5 (patch)
tree627be2a11f8effae4ce7ee37c2daf8a80866d66a
parent9023226e39b344608191078555b051c67859d18f (diff)
downloadopen-keychain-1e188ee2fa0c0573d523bf78811fa05c3e5bbea5.tar.gz
open-keychain-1e188ee2fa0c0573d523bf78811fa05c3e5bbea5.tar.bz2
open-keychain-1e188ee2fa0c0573d523bf78811fa05c3e5bbea5.zip
Define abstract remote service
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java15
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java218
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteApiService.java281
3 files changed, 293 insertions, 221 deletions
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index b2bfaf84d..18dee5b9e 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -239,8 +239,7 @@ public class ProviderHelper {
}
try {
- context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY,
- operations);
+ context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
} catch (RemoteException e) {
Log.e(Constants.TAG, "applyBatch failed!", e);
} catch (OperationApplicationException e) {
@@ -296,8 +295,7 @@ public class ProviderHelper {
}
try {
- context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY,
- operations);
+ context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
} catch (RemoteException e) {
Log.e(Constants.TAG, "applyBatch failed!", e);
} catch (OperationApplicationException e) {
@@ -765,12 +763,11 @@ public class ProviderHelper {
}
public static AppSettings getApiAppSettings(Context context, Uri uri) {
- AppSettings settings = new AppSettings();
+ AppSettings settings = null;
+
Cursor cur = context.getContentResolver().query(uri, null, null, null, null);
- if (cur == null) {
- return null;
- }
- if (cur.moveToFirst()) {
+ if (cur != null && cur.moveToFirst()) {
+ settings = new AppSettings();
settings.setPackageName(cur.getString(cur
.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID)));
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
index b848c8b52..7955a7f48 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
@@ -22,8 +22,6 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import org.openintents.openpgp.IOpenPgpCallback;
@@ -36,19 +34,14 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.PgpMain;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor;
-import android.app.Service;
-import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -56,31 +49,11 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-public class OpenPgpService extends Service {
- Context mContext;
-
- final ArrayBlockingQueue<Runnable> mPoolQueue = new ArrayBlockingQueue<Runnable>(100);
- // TODO: Are these parameters okay?
- PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10,
- TimeUnit.SECONDS, mPoolQueue);
-
- final Object userInputLock = new Object();
-
- private class MyBaseCallback implements Handler.Callback {
- public static final int OKAY = 1;
- public static final int CANCEL = 0;
-
- @Override
- public boolean handleMessage(Message msg) {
- return false;
- }
-
- }
+public class OpenPgpService extends RemoteApiService {
@Override
public void onCreate() {
super.onCreate();
- mContext = this;
Log.d(Constants.TAG, "CryptoService, onCreate()");
}
@@ -127,7 +100,7 @@ public class OpenPgpService extends Service {
return passphrase;
}
- public class PassphraseActivityCallback extends MyBaseCallback {
+ public class PassphraseActivityCallback extends UserInputCallback {
private boolean success = false;
@@ -136,19 +109,12 @@ public class OpenPgpService extends Service {
}
@Override
- public boolean handleMessage(Message msg) {
+ public void handleUserInput(Message msg) {
if (msg.arg1 == OKAY) {
success = true;
} else {
success = false;
}
-
- // resume
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- return true;
}
};
@@ -222,7 +188,7 @@ public class OpenPgpService extends Service {
return keyIdsArray;
}
- public class SelectPubKeysActivityCallback extends MyBaseCallback {
+ public class SelectPubKeysActivityCallback extends UserInputCallback {
public static final String PUB_KEY_IDS = "pub_key_ids";
private boolean success = false;
@@ -237,20 +203,13 @@ public class OpenPgpService extends Service {
}
@Override
- public boolean handleMessage(Message msg) {
+ public void handleUserInput(Message msg) {
if (msg.arg1 == OKAY) {
success = true;
pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS);
} else {
success = false;
}
-
- // resume
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- return true;
}
};
@@ -472,7 +431,7 @@ public class OpenPgpService extends Service {
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS);
boolean signatureUnknown = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
-
+
int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
if (signatureSuccess) {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS;
@@ -586,169 +545,4 @@ public class OpenPgpService extends Service {
};
- private void checkAndEnqueue(Runnable r) {
- if (isCallerAllowed(false)) {
- mThreadPool.execute(r);
-
- Log.d(Constants.TAG, "Enqueued runnable…");
- } else {
- String[] callingPackages = getPackageManager()
- .getPackagesForUid(Binder.getCallingUid());
-
- Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!");
- Bundle extras = new Bundle();
- // TODO: currently simply uses first entry
- extras.putString(OpenPgpServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]);
-
- RegisterActivityCallback callback = new RegisterActivityCallback();
- Messenger messenger = new Messenger(new Handler(getMainLooper(), callback));
-
- pauseQueueAndStartServiceActivity(OpenPgpServiceActivity.ACTION_REGISTER, messenger,
- extras);
-
- if (callback.isAllowed()) {
- mThreadPool.execute(r);
- Log.d(Constants.TAG, "Enqueued runnable…");
- } else {
- Log.d(Constants.TAG, "User disallowed app!");
- }
- }
- }
-
- public class RegisterActivityCallback extends MyBaseCallback {
- public static final String PACKAGE_NAME = "package_name";
-
- private boolean allowed = false;
- private String packageName;
-
- public boolean isAllowed() {
- return allowed;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- if (msg.arg1 == OKAY) {
- allowed = true;
- packageName = msg.getData().getString(PACKAGE_NAME);
-
- // resume threads
- if (isPackageAllowed(packageName, false)) {
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- } else {
- // Should not happen!
- Log.e(Constants.TAG, "Should not happen! Emergency shutdown!");
- mThreadPool.shutdownNow();
- }
- } else {
- allowed = false;
-
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- }
- return true;
- }
-
- }
-
- /**
- * Checks if process that binds to this service (i.e. the package name corresponding to the
- * process) is in the list of allowed package names.
- *
- * @param allowOnlySelf
- * allow only Keychain app itself
- * @return true if process is allowed to use this service
- */
- private boolean isCallerAllowed(boolean allowOnlySelf) {
- String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
-
- // is calling package allowed to use this service?
- for (int i = 0; i < callingPackages.length; i++) {
- String currentPkg = callingPackages[i];
-
- if (isPackageAllowed(currentPkg, allowOnlySelf)) {
- return true;
- }
- }
-
- Log.d(Constants.TAG, "Caller is NOT allowed!");
- return false;
- }
-
- private AppSettings getAppSettings() {
- String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
-
- // is calling package allowed to use this service?
- for (int i = 0; i < callingPackages.length; i++) {
- String currentPkg = callingPackages[i];
-
- Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg);
-
- AppSettings settings = ProviderHelper.getApiAppSettings(this, uri);
-
- return settings;
- }
-
- return null;
- }
-
- /**
- * Checks if packageName is a registered app for the API.
- *
- * @param packageName
- * @param allowOnlySelf
- * allow only Keychain app itself
- * @return
- */
- private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) {
- Log.d(Constants.TAG, "packageName: " + packageName);
-
- ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext);
- Log.d(Constants.TAG, "allowed: " + allowedPkgs);
-
- // check if package is allowed to use our service
- if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) {
- Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName);
-
- return true;
- } else if (Constants.PACKAGE_NAME.equals(packageName)) {
- Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!");
-
- return true;
- }
-
- return false;
- }
-
- private void pauseQueueAndStartServiceActivity(String action, Messenger messenger, Bundle extras) {
- synchronized (userInputLock) {
- mThreadPool.pause();
-
- Log.d(Constants.TAG, "starting activity...");
- Intent intent = new Intent(getBaseContext(), OpenPgpServiceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction(action);
-
- extras.putParcelable(OpenPgpServiceActivity.EXTRA_MESSENGER, messenger);
- intent.putExtras(extras);
-
- startActivity(intent);
-
- // lock current thread for user input
- try {
- userInputLock.wait();
- } catch (InterruptedException e) {
- Log.e(Constants.TAG, "CryptoService", e);
- }
- }
-
- }
}
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteApiService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteApiService.java
new file mode 100644
index 000000000..898aad90e
--- /dev/null
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteApiService.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service.remote;
+
+import java.util.ArrayList;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+
+/**
+ * Abstract service for remote APIs that handle app registration and user input.
+ */
+public abstract class RemoteApiService extends Service {
+ Context mContext;
+
+ final ArrayBlockingQueue<Runnable> mPoolQueue = new ArrayBlockingQueue<Runnable>(100);
+ // TODO: Are these parameters okay?
+ PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10,
+ TimeUnit.SECONDS, mPoolQueue);
+
+ private final Object userInputLock = new Object();
+
+ /**
+ * Override handleUserInput() to handle OKAY (1) and CANCEL (0). After handling the waiting
+ * threads will be notified and the queue resumed
+ */
+ protected class UserInputCallback extends BaseCallback {
+
+ public void handleUserInput(Message msg) {
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ handleUserInput(msg);
+
+ // resume
+ synchronized (userInputLock) {
+ userInputLock.notifyAll();
+ }
+ mThreadPool.resume();
+ return true;
+ }
+
+ }
+
+ /**
+ * Extends Handler.Callback with OKAY (1), CANCEL (0) variables
+ */
+ private class BaseCallback implements Handler.Callback {
+ public static final int OKAY = 1;
+ public static final int CANCEL = 0;
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ return false;
+ }
+
+ }
+
+ /**
+ * Should be used from Stub implementations of AIDL interfaces to enqueue a runnable for
+ * execution
+ *
+ * @param r
+ */
+ protected void checkAndEnqueue(Runnable r) {
+ if (isCallerAllowed(false)) {
+ mThreadPool.execute(r);
+
+ Log.d(Constants.TAG, "Enqueued runnable…");
+ } else {
+ String[] callingPackages = getPackageManager()
+ .getPackagesForUid(Binder.getCallingUid());
+
+ Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!");
+ Bundle extras = new Bundle();
+ // TODO: currently simply uses first entry
+ extras.putString(OpenPgpServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]);
+
+ RegisterActivityCallback callback = new RegisterActivityCallback();
+ Messenger messenger = new Messenger(new Handler(getMainLooper(), callback));
+
+ pauseQueueAndStartServiceActivity(OpenPgpServiceActivity.ACTION_REGISTER, messenger,
+ extras);
+
+ if (callback.isAllowed()) {
+ mThreadPool.execute(r);
+ Log.d(Constants.TAG, "Enqueued runnable…");
+ } else {
+ Log.d(Constants.TAG, "User disallowed app!");
+ }
+ }
+ }
+
+ /**
+ * Locks current thread and pauses execution of runnables and starts activity for user input
+ *
+ * @param action
+ * @param messenger
+ * @param extras
+ */
+ protected void pauseQueueAndStartServiceActivity(String action, Messenger messenger,
+ Bundle extras) {
+ synchronized (userInputLock) {
+ mThreadPool.pause();
+
+ Log.d(Constants.TAG, "starting activity...");
+ Intent intent = new Intent(getBaseContext(), OpenPgpServiceActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setAction(action);
+
+ extras.putParcelable(OpenPgpServiceActivity.EXTRA_MESSENGER, messenger);
+ intent.putExtras(extras);
+
+ startActivity(intent);
+
+ // lock current thread for user input
+ try {
+ userInputLock.wait();
+ } catch (InterruptedException e) {
+ Log.e(Constants.TAG, "CryptoService", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieves AppSettings from database for the application calling this remote service
+ *
+ * @return
+ */
+ protected AppSettings getAppSettings() {
+ String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+
+ // get app settings for this package
+ for (int i = 0; i < callingPackages.length; i++) {
+ String currentPkg = callingPackages[i];
+
+ Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg);
+
+ AppSettings settings = ProviderHelper.getApiAppSettings(this, uri);
+
+ if (settings != null)
+ return settings;
+ }
+
+ return null;
+ }
+
+ class RegisterActivityCallback extends BaseCallback {
+ public static final String PACKAGE_NAME = "package_name";
+
+ private boolean allowed = false;
+ private String packageName;
+
+ public boolean isAllowed() {
+ return allowed;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (msg.arg1 == OKAY) {
+ allowed = true;
+ packageName = msg.getData().getString(PACKAGE_NAME);
+
+ // resume threads
+ if (isPackageAllowed(packageName, false)) {
+ synchronized (userInputLock) {
+ userInputLock.notifyAll();
+ }
+ mThreadPool.resume();
+ } else {
+ // Should not happen!
+ Log.e(Constants.TAG, "Should not happen! Emergency shutdown!");
+ mThreadPool.shutdownNow();
+ }
+ } else {
+ allowed = false;
+
+ synchronized (userInputLock) {
+ userInputLock.notifyAll();
+ }
+ mThreadPool.resume();
+ }
+ return true;
+ }
+
+ }
+
+ /**
+ * Checks if process that binds to this service (i.e. the package name corresponding to the
+ * process) is in the list of allowed package names.
+ *
+ * @param allowOnlySelf
+ * allow only Keychain app itself
+ * @return true if process is allowed to use this service
+ */
+ private boolean isCallerAllowed(boolean allowOnlySelf) {
+ String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+
+ // is calling package allowed to use this service?
+ for (int i = 0; i < callingPackages.length; i++) {
+ String currentPkg = callingPackages[i];
+
+ if (isPackageAllowed(currentPkg, allowOnlySelf)) {
+ return true;
+ }
+ }
+
+ Log.d(Constants.TAG, "Caller is NOT allowed!");
+ return false;
+ }
+
+ /**
+ * Checks if packageName is a registered app for the API.
+ *
+ * @param packageName
+ * @param allowOnlySelf
+ * allow only Keychain app itself
+ * @return
+ */
+ private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) {
+ Log.d(Constants.TAG, "packageName: " + packageName);
+
+ ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext);
+ Log.d(Constants.TAG, "allowed: " + allowedPkgs);
+
+ // check if package is allowed to use our service
+ if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) {
+ Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName);
+
+ return true;
+ } else if (Constants.PACKAGE_NAME.equals(packageName)) {
+ Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!");
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mContext = this;
+ }
+
+}