From 5ee0b8bb71b28e836775d371c5cc3c18866f72c2 Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Fri, 25 May 2012 10:04:12 -0700 Subject: [PATCH] Bug 757646 - Throw from NSSBridge if Master password is set. r=rnewman,gbrown --- build/mobile/robocop/Actions.java.in | 7 ++++ .../robocop/FennecNativeActions.java.in | 15 +++++++ mobile/android/base/NSSBridge.java | 40 +++++++------------ mobile/android/base/db/GeckoProvider.java.in | 6 --- .../android/base/db/PasswordsProvider.java.in | 23 ++++++++--- .../base/tests/testPasswordEncrypt.java.in | 39 ++++++++++++++++++ 6 files changed, 92 insertions(+), 38 deletions(-) diff --git a/build/mobile/robocop/Actions.java.in b/build/mobile/robocop/Actions.java.in index 34e32f94fdec..63ecd08c959c 100644 --- a/build/mobile/robocop/Actions.java.in +++ b/build/mobile/robocop/Actions.java.in @@ -29,6 +29,13 @@ public interface Actions { public void blockUntilClear(long millis); } + /** + * Sends an event to Gecko. + * + * @param geckoEvent The geckoEvent JSONObject's type + */ + void sendGeckoEvent(String geckoEvent, String data); + /** * Listens for a gecko event to be sent from the Gecko instance. * The returned object can be used to test if the event has been diff --git a/build/mobile/robocop/FennecNativeActions.java.in b/build/mobile/robocop/FennecNativeActions.java.in index 96527f9a20aa..7656d139db4c 100644 --- a/build/mobile/robocop/FennecNativeActions.java.in +++ b/build/mobile/robocop/FennecNativeActions.java.in @@ -13,6 +13,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.Long; +import java.lang.NoSuchMethodException; import java.util.concurrent.SynchronousQueue; import java.util.ArrayList; @@ -180,6 +181,20 @@ public class FennecNativeActions implements Actions { return null; } + public void sendGeckoEvent(String geckoEvent, String data) { + try { + Method cbe = mGe.getMethod("createBroadcastEvent", String.class, String.class); + Object event = cbe.invoke(null, geckoEvent, data); + mSendGE.invoke(null, event); + } catch (NoSuchMethodException e) { + FennecNativeDriver.log(LogLevel.ERROR, e); + } catch (IllegalAccessException e) { + FennecNativeDriver.log(LogLevel.ERROR, e); + } catch (InvocationTargetException e) { + FennecNativeDriver.log(LogLevel.ERROR, e); + } + } + class DrawListenerProxy implements InvocationHandler { private final PaintExpecter mPaintExpecter; diff --git a/mobile/android/base/NSSBridge.java b/mobile/android/base/NSSBridge.java index d3b11dd15aab..5cebab919a49 100644 --- a/mobile/android/base/NSSBridge.java +++ b/mobile/android/base/NSSBridge.java @@ -15,49 +15,37 @@ public class NSSBridge { private static native String nativeEncrypt(String aDb, String aValue); private static native String nativeDecrypt(String aDb, String aValue); - static public String encrypt(Context context, String aValue) { + static public String encrypt(Context context, String aValue) + throws Exception { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadNSSLibs(context, resourcePath); - String res = ""; - try { - String path = GeckoProfile.get(context).getDir().toString(); - res = nativeEncrypt(path, aValue); - } catch(Exception ex) { } - return res; + String path = GeckoProfile.get(context).getDir().toString(); + return nativeEncrypt(path, aValue); } - static public String encrypt(Context context, String profilePath, String aValue) { + static public String encrypt(Context context, String profilePath, String aValue) + throws Exception { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadNSSLibs(context, resourcePath); - String res = ""; - try { - res = nativeEncrypt(profilePath, aValue); - } catch(Exception ex) { } - return res; + return nativeEncrypt(profilePath, aValue); } - static public String decrypt(Context context, String aValue) { + static public String decrypt(Context context, String aValue) + throws Exception { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadNSSLibs(context, resourcePath); - String res = ""; - try { - String path = GeckoProfile.get(context).getDir().toString(); - res = nativeDecrypt(path, aValue); - } catch(Exception ex) { } - return res; + String path = GeckoProfile.get(context).getDir().toString(); + return nativeDecrypt(path, aValue); } - static public String decrypt(Context context, String profilePath, String aValue) { + static public String decrypt(Context context, String profilePath, String aValue) + throws Exception { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadNSSLibs(context, resourcePath); - String res = ""; - try { - res = nativeDecrypt(profilePath, aValue); - } catch(Exception ex) { } - return res; + return nativeDecrypt(profilePath, aValue); } } diff --git a/mobile/android/base/db/GeckoProvider.java.in b/mobile/android/base/db/GeckoProvider.java.in index 39277ff25c8a..ddf7477cfd2e 100644 --- a/mobile/android/base/db/GeckoProvider.java.in +++ b/mobile/android/base/db/GeckoProvider.java.in @@ -142,7 +142,6 @@ public abstract class GeckoProvider extends ContentProvider { // call to Gecko. Gecko will handle building the database file correctly, as well as any // migrations that are necessary if (dbNeedsSetup) { - Log.i(mLogTag, "Sending init to gecko"); bridge = null; initGecko(); } @@ -154,7 +153,6 @@ public abstract class GeckoProvider extends ContentProvider { private SQLiteBridge getDatabaseForProfile(String profile) { if (TextUtils.isEmpty(profile)) { - Log.d(mLogTag, "No profile provided, using default"); profile = BrowserContract.DEFAULT_PROFILE; } @@ -167,7 +165,6 @@ public abstract class GeckoProvider extends ContentProvider { } } - Log.d(mLogTag, "Successfully created database helper for profile: " + profile); return db; } @@ -181,18 +178,15 @@ public abstract class GeckoProvider extends ContentProvider { } } - Log.d(mLogTag, "Successfully created database helper for path: " + profilePath); return db; } private String getDatabasePathForProfile(String profile) { File profileDir = GeckoProfile.get(mContext, profile).getDir(); if (profileDir == null) { - Log.d(mLogTag, "Couldn't find directory for profile: " + profile); return null; } - Log.d(mLogTag, "Using path: " + profileDir.getPath()); String databasePath = new File(profileDir, mDBName).getAbsolutePath(); return databasePath; } diff --git a/mobile/android/base/db/PasswordsProvider.java.in b/mobile/android/base/db/PasswordsProvider.java.in index 146991152769..5f9e9e12d4e0 100644 --- a/mobile/android/base/db/PasswordsProvider.java.in +++ b/mobile/android/base/db/PasswordsProvider.java.in @@ -203,12 +203,23 @@ public class PasswordsProvider extends GeckoProvider { } String result = ""; - if (encrypt) { - if (profilePath != null) result = NSSBridge.encrypt(mContext, profilePath, initialValue); - else result = NSSBridge.encrypt(mContext, initialValue); - } else { - if (profilePath != null) result = NSSBridge.decrypt(mContext, profilePath, initialValue); - else result = NSSBridge.decrypt(mContext, initialValue); + try { + if (encrypt) { + if (profilePath != null) { + result = NSSBridge.encrypt(mContext, profilePath, initialValue); + } else { + result = NSSBridge.encrypt(mContext, initialValue); + } + } else { + if (profilePath != null) { + result = NSSBridge.decrypt(mContext, profilePath, initialValue); + } else { + result = NSSBridge.decrypt(mContext, initialValue); + } + } + } catch (Exception ex) { + Log.e(getLogTag(), "Error in NSSBridge"); + throw new RuntimeException(ex); } return result; } diff --git a/mobile/android/base/tests/testPasswordEncrypt.java.in b/mobile/android/base/tests/testPasswordEncrypt.java.in index dc05ff74611e..425857211c42 100644 --- a/mobile/android/base/tests/testPasswordEncrypt.java.in +++ b/mobile/android/base/tests/testPasswordEncrypt.java.in @@ -11,11 +11,16 @@ import android.net.Uri; import java.io.File; import java.lang.reflect.Method; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + public class testPasswordEncrypt extends BaseTest { public void testPasswordEncrypt() { setTestType("mochitest"); Context context = (Context)getActivity(); ContentResolver cr = context.getContentResolver(); + mAsserter.isnot(cr, null, "Found a content resolver"); ContentValues cvs = new ContentValues(); Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready"); @@ -77,6 +82,24 @@ public class testPasswordEncrypt extends BaseTest { list.moveToFirst(); decryptedP = (String)decrypt.invoke(null, context, mProfile, list.getString(0)); mAsserter.is(decryptedP, "password2", "Password was encrypted when updating"); + + // Trying to store a password while master password is enabled should throw, + // but because Android can't send Exceptions across processes + // it just results in a null uri/cursor being returned. + toggleMasterPassword("password"); + try { + uri = cr.insert(passwordUri, cvs); + mAsserter.is(uri, null, "Storing a password while MP was set should fail"); + + Cursor c = cr.query(passwordUri, null, null, null, null); + mAsserter.is(c, null, "Querying passwords while MP was set should fail"); + } catch (Exception ex) { + // Password provider currently can not throw across process + // so we should not catch this exception here + mAsserter.ok(false, "Caught exception", ex.toString()); + } + toggleMasterPassword("password"); + } catch(ClassNotFoundException ex) { mAsserter.ok(false, "Error getting class", ex.toString()); return; @@ -95,6 +118,22 @@ public class testPasswordEncrypt extends BaseTest { } } + private void toggleMasterPassword(String passwd) { + JSONObject jsonPref = new JSONObject(); + try { + jsonPref.put("name", "privacy.masterpassword.enabled"); + jsonPref.put("type", "string"); + jsonPref.put("value", passwd); + mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString()); + } catch (Exception ex) { } + + JSONArray getPrefData = new JSONArray(); + getPrefData.put("privacy.masterpassword.enabled"); + Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Preferences:Data"); + mActions.sendGeckoEvent("Preferences:Get", getPrefData.toString()); + contentEventExpecter.blockForEvent(); + } + public void tearDown() throws Exception { super.tearDown();