/// <summary> /// Sends a broadcast to all potential plugins prompting them to request access to our app. /// </summary> public static void TriggerRequests(Context ctx) { PluginDatabase pluginDatabase = new PluginDatabase(ctx); foreach (string pkg in GetAllPlugins(ctx)) { TriggerRequest(ctx, pkg, pluginDatabase); } }
public static void TriggerRequest(Context ctx, string pkgName, PluginDatabase pluginDatabase) { try { Intent triggerIntent = new Intent(Strings.ActionTriggerRequestAccess); triggerIntent.SetPackage(pkgName); triggerIntent.PutExtra(Strings.ExtraSender, ctx.PackageName); triggerIntent.PutExtra(Strings.ExtraRequestToken, pluginDatabase.GetRequestToken(pkgName)); ctx.SendBroadcast(triggerIntent); } catch (Exception e) { } }
public static void TriggerRequest(Context ctx, string pkgName, PluginDatabase pluginDatabase) { try { Intent triggerIntent = new Intent(Strings.ActionTriggerRequestAccess); triggerIntent.SetPackage(pkgName); triggerIntent.PutExtra(Strings.ExtraSender, ctx.PackageName); string requestToken = pluginDatabase.GetRequestToken(pkgName); triggerIntent.PutExtra(Strings.ExtraRequestToken, requestToken); Android.Util.Log.Debug(_tag, "Request token: " + requestToken); ctx.SendBroadcast(triggerIntent); } catch (Exception e) { } }
protected override void OnResume() { base.OnResume(); PluginDatabase pluginDb = new PluginDatabase(this); _items = (from pluginPackage in pluginDb.GetAllPluginPackages() let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName let enabledStatus = pluginDb.IsEnabled(pluginPackage) ? GetString(Resource.String.plugin_enabled) : GetString(Resource.String.plugin_disabled) select new PluginItem(pluginPackage, enabledStatus, this)).ToList(); /* { new PluginItem("PluginA", Resource.Drawable.Icon, "keepass2android.plugina", "connected"), new PluginItem("KeepassNFC", Resource.Drawable.Icon, "com.bla.blubb.plugina", "disconnected") }; * */ _pluginArrayAdapter = new PluginArrayAdapter(this, Resource.Layout.ListViewPluginRow, _items); ListAdapter = _pluginArrayAdapter; }
protected override void OnResume() { base.OnResume(); PluginDatabase pluginDb = new PluginDatabase(this); _items = (from pluginPackage in pluginDb.GetAllPluginPackages() let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName let enabledStatus = pluginDb.IsEnabled(pluginPackage) ? GetString(Resource.String.plugin_enabled) : GetString(Resource.String.plugin_disabled) select new PluginItem(pluginPackage, enabledStatus, this)).ToList(); /* * { * new PluginItem("PluginA", Resource.Drawable.Icon, "keepass2android.plugina", "connected"), * new PluginItem("KeepassNFC", Resource.Drawable.Icon, "com.bla.blubb.plugina", "disconnected") * }; * */ _pluginArrayAdapter = new PluginArrayAdapter(this, Resource.Layout.ListViewPluginRow, _items); ListAdapter = _pluginArrayAdapter; }
private void UpdateView() { var scopesContainer = FindViewById <LinearLayout>(Resource.Id.scopes_list); //scopesContainer.RemoveAllViews(); var pluginDb = new PluginDatabase(this); _checkbox.Checked = pluginDb.IsEnabled(_pluginPackageName); foreach (string scope in pluginDb.GetPluginScopes(_pluginPackageName)) { string scopeId = scope.Substring("keepass2android.".Length); TextWithHelp help = new TextWithHelp(this, GetString(Resources.GetIdentifier(scopeId + "_title", "string", PackageName)), GetString(Resources.GetIdentifier(scopeId + "_explanation", "string", PackageName))); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent); help.LayoutParameters = layoutParams; scopesContainer.AddView(help); } }
public void CloseAfterTaskComplete() { //before closing, wait a little to get plugin updates int numPlugins = new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeCurrentEntry).Count(); var timeToWait = TimeSpan.FromMilliseconds(500 * numPlugins); SetProgressBarIndeterminateVisibility(true); _timer = new Timer(obj => { RunOnUiThread(() => { //task is completed -> return NullTask Intent resIntent = new Intent(); new NullTask().ToIntent(resIntent); SetResult(KeePass.ExitCloseAfterTaskComplete, resIntent); //close activity: Finish(); } ); }, null, timeToWait, TimeSpan.FromMilliseconds(-1)); }
public override void OnReceive(Context context, Intent intent) { PluginDatabase pluginDb = new PluginDatabase(context); if (intent.Action == Strings.ActionRequestAccess) { var senderPackage = intent.GetStringExtra(Strings.ExtraSender); var requestToken = intent.GetStringExtra(Strings.ExtraRequestToken); var requestedScopes = intent.GetStringArrayListExtra(Strings.ExtraScopes); if (!AreScopesValid(requestedScopes)) { return; } if (pluginDb.GetRequestToken(senderPackage) != requestToken) { Log.Warn(_tag, "Invalid requestToken!"); return; } string currentAccessToken = pluginDb.GetAccessToken(senderPackage); if ((currentAccessToken != null) && (AccessManager.IsSubset(requestedScopes, pluginDb.GetPluginScopes(senderPackage)))) { //permission already there. var i = new Intent(Strings.ActionReceiveAccess); i.PutExtra(Strings.ExtraSender, context.PackageName); i.PutExtra(Strings.ExtraAccessToken, currentAccessToken); //TODO: Plugin should verify requestToken to make sure it doesn't receive accessTokens from malicious apps i.PutExtra(Strings.ExtraRequestToken, requestToken); i.SetPackage(senderPackage); context.SendBroadcast(i); Log.Debug(_tag, "Plugin " + senderPackage + " enabled."); } else { //store that scope was requested but not yet approved (=> accessToken = null) pluginDb.StorePlugin(senderPackage, null, requestedScopes); Log.Debug(_tag, "Plugin " + senderPackage + " not enabled."); //see if the plugin has an access token string accessToken = intent.GetStringExtra(Strings.ExtraAccessToken); if (accessToken != null) { //notify plugin that access token is no longer valid or sufficient Intent i = new Intent(Strings.ActionRevokeAccess); i.PutExtra(Strings.ExtraSender, context.PackageName); i.PutExtra(Strings.ExtraAccessToken, accessToken); i.SetPackage(senderPackage); context.SendBroadcast(i); Log.Warn(_tag, "Access token of plugin " + senderPackage + " not (or no more) valid."); } } if (OnReceivedRequest != null) OnReceivedRequest(this, new PluginHostEventArgs() { Package = senderPackage }); } }
/// <summary> /// Sends a broadcast to all potential plugins prompting them to request access to our app. /// </summary> public static void TriggerRequests(Context ctx) { PluginDatabase pluginDatabase = new PluginDatabase(ctx); foreach (string pkg in GetAllPlugins(ctx)) TriggerRequest(ctx, pkg, pluginDatabase); }
public void CloseAfterTaskComplete() { //before closing, wait a little to get plugin updates int numPlugins = new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeCurrentEntry).Count(); var timeToWait = TimeSpan.FromMilliseconds(500*numPlugins); SetProgressBarIndeterminateVisibility(true); _timer = new Timer(obj => { RunOnUiThread(() => { //task is completed -> return NullTask Intent resIntent = new Intent(); new NullTask().ToIntent(resIntent); SetResult(KeePass.ExitCloseAfterTaskComplete, resIntent); //close activity: Finish(); } ); }, null, timeToWait, TimeSpan.FromMilliseconds(-1)); }
public override void OnReceive(Context context, Intent intent) { PluginDatabase pluginDb = new PluginDatabase(context); if (intent.Action == Strings.ActionRequestAccess) { string senderPackage = intent.GetStringExtra(Strings.ExtraSender); string requestToken = intent.GetStringExtra(Strings.ExtraRequestToken); IList <string> requestedScopes = intent.GetStringArrayListExtra(Strings.ExtraScopes); if (!AreScopesValid(requestedScopes)) { Log.Debug(_tag, "requested scopes not valid"); return; } if (pluginDb.GetRequestToken(senderPackage) != requestToken) { Log.Warn(_tag, "Invalid requestToken!"); return; } string currentAccessToken = pluginDb.GetAccessToken(senderPackage); if ((currentAccessToken != null) && (AccessManager.IsSubset(requestedScopes, pluginDb.GetPluginScopes(senderPackage)))) { //permission already there. var i = new Intent(Strings.ActionReceiveAccess); i.PutExtra(Strings.ExtraSender, context.PackageName); i.PutExtra(Strings.ExtraAccessToken, currentAccessToken); //TODO: Plugin should verify requestToken to make sure it doesn't receive accessTokens from malicious apps i.PutExtra(Strings.ExtraRequestToken, requestToken); i.SetPackage(senderPackage); context.SendBroadcast(i); Log.Debug(_tag, "Plugin " + senderPackage + " enabled."); } else { //store that scope was requested but not yet approved (=> accessToken = null) pluginDb.StorePlugin(senderPackage, null, requestedScopes); Log.Debug(_tag, "Plugin " + senderPackage + " not enabled."); //see if the plugin has an access token string accessToken = intent.GetStringExtra(Strings.ExtraAccessToken); if (accessToken != null) { //notify plugin that access token is no longer valid or sufficient Intent i = new Intent(Strings.ActionRevokeAccess); i.PutExtra(Strings.ExtraSender, context.PackageName); i.PutExtra(Strings.ExtraAccessToken, accessToken); i.SetPackage(senderPackage); context.SendBroadcast(i); Log.Warn(_tag, "Access token of plugin " + senderPackage + " not (or no more) valid."); } } if (OnReceivedRequest != null) { OnReceivedRequest(this, new PluginHostEventArgs() { Package = senderPackage }); } } }
protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it Button button = FindViewById<Button>(Resource.Id.MyButton); button.Click += delegate { PluginHost.TriggerRequests(this); }; FindViewById<Button>(Resource.Id.managePluginsButton).Click += delegate(object sender, EventArgs args) { StartActivity(new Intent(this, typeof(PluginListActivity))); }; FindViewById<Button>(Resource.Id.entryviewButton).Click += delegate { StartActivity(new Intent(this, typeof(EntryActivity))); }; FindViewById<Button>(Resource.Id.testDbButton).Click += delegate { string message = "ok. "; try { Stopwatch sw = new Stopwatch(); sw.Start(); PluginDatabase db = new PluginDatabase(this); db.Clear(); if (db.GetAllPluginPackages().Count() != 0) throw new Exception("db not empty!"); const string testPackageA = "test.package.a"; const string testPackageB = "test.package.b"; db.ClearPlugin(testPackageA); db.ClearPlugin(testPackageB); EnsurePackageDataIsEmpty(db, testPackageA); EnsurePackageDataIsEmpty(db, testPackageB); string[] requestedScopes = { Strings.ScopeDatabaseActions }; db.StorePlugin(testPackageA, null, requestedScopes); EnsurePackageDataIsEmpty(db, testPackageB); EnsurePackageDataIsEmpty(new PluginDatabase(this), testPackageB); db.StorePlugin(testPackageB, null, requestedScopes); EnsurePackageHasUnacceptedScope(db, testPackageA, Strings.ScopeDatabaseActions); EnsurePackageHasUnacceptedScope(db, testPackageB, Strings.ScopeDatabaseActions); EnsurePackageHasUnacceptedScope(new PluginDatabase(this), testPackageA, Strings.ScopeDatabaseActions); if (db.GetAllPluginPackages().Count() != 2) throw new Exception("wrong count of plugins"); if (db.GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Any()) { throw new Exception("wrong count of accepted plugins"); } if (new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Any()) { throw new Exception("wrong count of accepted plugins"); } db.SetEnabled(testPackageA, true); if (db.GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Single() != testPackageA) { throw new Exception("wrong plugin"); } if (new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Single() != testPackageA) { throw new Exception("wrong plugin"); } if (db.GetPluginsWithAcceptedScope("somescope").Any()) { throw new Exception("wrong count of accepted plugins"); } var accessTokenA = db.GetAccessToken(testPackageA); if (String.IsNullOrEmpty(accessTokenA)) throw new Exception("expected access token!"); if (!db.IsEnabled(testPackageA)) throw new Exception("plugin not enabled!"); if (db.IsEnabled(testPackageB)) throw new Exception("plugin enabled!"); if (!db.IsValidAccessToken(testPackageA, accessTokenA, Strings.ScopeDatabaseActions)) throw new Exception("invalid token!"); db.SetEnabled(testPackageA, false); if (db.IsValidAccessToken(testPackageA, accessTokenA, Strings.ScopeDatabaseActions)) throw new Exception("valid token?!"); if (db.GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Any()) throw new Exception("unexpected!"); new PluginDatabase(this).SetEnabled(testPackageB, true); if (!db.IsEnabled(testPackageB)) throw new Exception("plugin not enabled!"); db.SetEnabled(testPackageA, true); accessTokenA = db.GetAccessToken(testPackageA); message += sw.ElapsedMilliseconds + "ms"; Stopwatch swQuery = new Stopwatch(); swQuery.Start(); int n = 3; for (int i = 0; i < n; i++) { if (db.GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions).Count() != 2) { throw new Exception("wrong plugin"); } if (!db.IsValidAccessToken(testPackageA, accessTokenA, Strings.ScopeDatabaseActions)) throw new Exception("invalid token"); } message += "/ " + swQuery.ElapsedMilliseconds/(double)n/2.0 + "ms for query"; } catch (Exception exception) { message = exception.ToString(); } Toast.MakeText(this, message, ToastLength.Long).Show(); }; }
private void EnsurePackageHasUnacceptedScope(PluginDatabase db, string plugin, string scope) { if (String.IsNullOrEmpty(db.GetRequestToken(plugin))) throw new Exception("invalid request token"); if (db.GetAccessToken(plugin) != null) throw new Exception("invalid access token!"); if (db.GetPluginScopes(plugin).Count != 1) throw new Exception("Unexpected scopes!"); if (db.GetPluginScopes(plugin).First() != scope) throw new Exception("Unexpected scope in db!"); }
private static void EnsurePackageDataIsEmpty(PluginDatabase db, string testPackageA) { if (String.IsNullOrEmpty(db.GetRequestToken(testPackageA))) throw new Exception("invalid request token"); if (db.GetAccessToken(testPackageA) != null) throw new Exception("invalid access token!"); if (db.GetPluginScopes(testPackageA).Count > 0) throw new Exception("Unexpected scopes!"); }
private void UpdateView() { var scopesContainer = FindViewById<LinearLayout>(Resource.Id.scopes_list); //scopesContainer.RemoveAllViews(); var pluginDb = new PluginDatabase(this); _checkbox.Checked = pluginDb.IsEnabled(_pluginPackageName); foreach (string scope in pluginDb.GetPluginScopes(_pluginPackageName)) { string scopeId = scope.Substring("keepass2android.".Length); TextWithHelp help = new TextWithHelp(this, GetString(Resources.GetIdentifier(scopeId + "_title", "string", PackageName)), GetString(Resources.GetIdentifier(scopeId + "_explanation", "string", PackageName))); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent); help.LayoutParameters = layoutParams; scopesContainer.AddView(help); } }