diff --git a/src/keepass2android/AboutActivity.cs b/src/keepass2android/AboutActivity.cs
new file mode 100644
index 00000000..3b3926a7
--- /dev/null
+++ b/src/keepass2android/AboutActivity.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.App;
+using Android.Content;
+using Android.Content.PM;
+
+namespace keepass2android
+{
+ [Activity(Label = "@string/app_name",
+ ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
+ Theme = "@style/Base")]
+ [IntentFilter(new[] { "keepass2android.AboutActivity" }, Categories = new[] { Intent.CategoryDefault })]
+ public class AboutActivity: Activity, IDialogInterfaceOnDismissListener
+ {
+ private AboutDialog _dialog;
+
+ protected override void OnResume()
+ {
+ if ((_dialog == null) || (_dialog.IsShowing == false))
+ {
+ if (new ActivityDesign(this).UseDarkTheme)
+ _dialog = new AboutDialog(this, Android.Resource.Style.ThemeHoloNoActionBarFullscreen);
+ else
+ _dialog = new AboutDialog(this, Android.Resource.Style.ThemeHoloLightNoActionBarFullscreen);
+ _dialog.SetOnDismissListener(this);
+ _dialog.Show();
+ }
+ base.OnResume();
+ }
+
+ public void OnDismiss(IDialogInterface dialog)
+ {
+ Finish();
+ }
+ }
+}
diff --git a/src/keepass2android/EntryActivity.cs b/src/keepass2android/EntryActivity.cs
index 4fd5aea9..9161add3 100644
--- a/src/keepass2android/EntryActivity.cs
+++ b/src/keepass2android/EntryActivity.cs
@@ -38,7 +38,6 @@ using KeePassLib;
using KeePassLib.Security;
using KeePassLib.Utility;
using Keepass2android.Pluginsdk;
-using PluginHostTest;
using keepass2android.Io;
using Uri = Android.Net.Uri;
diff --git a/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs b/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs
index a1a4207d..5084cfa6 100644
--- a/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs
+++ b/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs
@@ -1,6 +1,5 @@
using Android.Content;
using Android.Graphics.Drawables;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs b/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs
index b1a56d97..468040b8 100644
--- a/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs
+++ b/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs
@@ -1,5 +1,5 @@
using Android.Graphics.Drawables;
-using PluginHostTest;
+
namespace keepass2android
{
diff --git a/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs b/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs
index 38c07867..7ca945ed 100644
--- a/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs
+++ b/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs
@@ -1,5 +1,4 @@
using Android.Graphics.Drawables;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs b/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs
index 54ff1890..b720e263 100644
--- a/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs
+++ b/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs
@@ -1,5 +1,4 @@
using Android.Graphics.Drawables;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs b/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs
index a90fc61b..8169fa39 100644
--- a/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs
+++ b/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs
@@ -1,5 +1,4 @@
using Android.Graphics.Drawables;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/GroupActivity.cs b/src/keepass2android/GroupActivity.cs
index bd898757..e7d1693e 100644
--- a/src/keepass2android/GroupActivity.cs
+++ b/src/keepass2android/GroupActivity.cs
@@ -167,18 +167,6 @@ namespace keepass2android
return cv.OnContextItemSelected(item);
}
- protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
- {
- switch (resultCode)
- {
-
- case Result.Canceled:
- break;
- default:
- base.OnActivityResult(requestCode, resultCode, data);
- break;
- }
- }
}
}
diff --git a/src/keepass2android/KeePass.cs b/src/keepass2android/KeePass.cs
index ec22af59..f33cd6ec 100644
--- a/src/keepass2android/KeePass.cs
+++ b/src/keepass2android/KeePass.cs
@@ -40,6 +40,9 @@ using String = System.String;
* While the database is closed, there is only one activity on the stack: Keepass -> FileSelect <-> Password.
* After opening an database (in Password), Password is always the root of the stack (exception: after creating a database,
* FileSelect is the root without Password being open).
+ * Another exception: QueryCredentialsActivity is root of the stack if an external app is querying credentials.
+ * QueryCredentialsActivity checks the plugin access permissions, then launches FileSelectActivity (which starts
+ * the normal stack.)
*
* Some possible stacks:
* Password -> Group ( -> Group (subgroups) ... ) -> EntryView -> EntryEdit
@@ -184,6 +187,7 @@ namespace keepass2android
private static String LIB_DALVIK = "libdvm.so";
private static String LIB_ART = "libart.so";
private static String LIB_ART_D = "libartd.so";
+ public static string StartWithTask = "keepass2android.ACTION_START_WITH_TASK";
public KeePass()
{
diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs
index 27806ecc..e2c0eb23 100644
--- a/src/keepass2android/PasswordActivity.cs
+++ b/src/keepass2android/PasswordActivity.cs
@@ -159,11 +159,11 @@ namespace keepass2android
Intent i = new Intent(act, typeof(PasswordActivity));
- i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
+ i.SetFlags(ActivityFlags.ForwardResult);
i.PutExtra(KeyFilename, fileName);
appTask.ToIntent(i);
- act.StartActivityForResult(i, 0);
+ act.StartActivity(i);
}
@@ -179,7 +179,7 @@ namespace keepass2android
Intent i = new Intent(act, typeof(PasswordActivity));
PutIoConnectionToIntent(ioc, i);
- i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.ForwardResult);
+ i.SetFlags(ActivityFlags.ForwardResult);
appTask.ToIntent(i);
@@ -355,7 +355,7 @@ namespace keepass2android
// and if the activity is not launched from history (i.e. recent tasks) because this would mean that
// the Activity was closed already (user cancelling the task or task complete) but is restarted due recent tasks.
// Don't re-start the task (especially bad if tak was complete already)
- if ((savedInstanceState == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
+ if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
{
AppTask = new NullTask();
}
diff --git a/src/keepass2android/QueryCredentialsActivity.cs b/src/keepass2android/QueryCredentialsActivity.cs
new file mode 100644
index 00000000..ccbdf2b8
--- /dev/null
+++ b/src/keepass2android/QueryCredentialsActivity.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.Content.PM;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Keepass2android.Pluginsdk;
+
+namespace keepass2android
+{
+ [Activity(Label = "@string/app_name",
+ ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
+ Theme = "@style/Base")]
+ [IntentFilter(new[] { Strings.ActionQueryCredentials},
+ Categories = new[] { Intent.CategoryDefault })]
+ [IntentFilter(new[] { Strings.ActionQueryCredentialsForOwnPackage },
+ Categories = new[] { Intent.CategoryDefault })]
+ public class QueryCredentialsActivity : Activity
+ {
+ private const int RequestCodePluginAccess = 1;
+ private const int RequestCodeQuery = 2;
+ private const string IsRecreate = "isRecreate";
+ private const string StartedQuery = "startedQuery";
+ private bool _startedQuery;
+ private string _requiredScope;
+ private string _requestedUrl;
+ private string _pluginPackage;
+
+ protected override void OnCreate(Bundle savedInstanceState)
+ {
+ base.OnCreate(savedInstanceState);
+
+ //if launched from history, don't re-use the task. Proceed to FileSelect instead.
+ if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
+ {
+ Kp2aLog.Log("Forwarding to FileSelect. QueryCredentialsActivity started from history.");
+ Intent intent = new Intent(this, typeof(FileSelectActivity));
+ intent.AddFlags(ActivityFlags.ForwardResult);
+ StartActivity(intent);
+ Finish();
+ return;
+ }
+
+ _pluginPackage = null;
+ if (CallingActivity != null)
+ _pluginPackage = CallingActivity.PackageName;
+ if (_pluginPackage == null)
+ {
+ Kp2aLog.Log("Couldn't retrieve calling package. Probably activity was started without startActivityForResult()");
+ Finish();
+ return;
+ }
+ if (Intent.Action == Strings.ActionQueryCredentialsForOwnPackage)
+ {
+ _requiredScope = Strings.ScopeQueryCredentialsForOwnPackage;
+ _requestedUrl = "androidapp://" + _pluginPackage;
+ }
+ else if (Intent.Action == Strings.ActionQueryCredentials)
+ {
+ _requiredScope = Strings.ScopeQueryCredentials;
+ _requestedUrl = Intent.GetStringExtra(Strings.ExtraQueryString);
+ }
+ else
+ {
+ Kp2aLog.Log("Invalid action for QueryCredentialsActivity: " + Intent.Action);
+ SetResult(Result.FirstUser);
+ Finish();
+ return;
+ }
+
+ //only start the query or request plugin access when creating the first time.
+ //if we're restarting (after config change or low memory), we will get onActivityResult() later
+ //which will either start the next activity or finish this one.
+ if ((savedInstanceState == null) || (savedInstanceState.GetBoolean(IsRecreate, false) == false))
+ {
+ ShowToast();
+
+ if (new PluginDatabase(this).HasAcceptedScope(_pluginPackage,_requiredScope))
+ {
+ StartQuery();
+ }
+ else
+ {
+ RequestPluginAccess();
+ }
+ }
+ }
+
+ private void ShowToast()
+ {
+ string pluginDisplayName = _pluginPackage;
+ try
+ {
+ pluginDisplayName = PackageManager.GetApplicationLabel(PackageManager.GetApplicationInfo(_pluginPackage, 0));
+ }
+ catch (Exception e)
+ {
+ Kp2aLog.Log(e.ToString());
+ }
+ if (String.IsNullOrEmpty(_requestedUrl))
+ Toast.MakeText(this, GetString(Resource.String.query_credentials, new Java.Lang.Object[] {pluginDisplayName}), ToastLength.Long).Show();
+ else
+ Toast.MakeText(this,
+ GetString(Resource.String.query_credentials_for_url,
+ new Java.Lang.Object[] { pluginDisplayName, _requestedUrl }), ToastLength.Long).Show(); ;
+ }
+
+ private void StartQuery()
+ {
+ //launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
+ //will return the results later
+ Intent i = new Intent(this, typeof (FileSelectActivity));
+ //don't show user notifications when an entry is opened.
+ var task = new SearchUrlTask() {UrlToSearchFor = _requestedUrl, ShowUserNotifications = false};
+ task.ToIntent(i);
+ StartActivityForResult(i, RequestCodeQuery);
+ _startedQuery = true;
+ }
+
+ private void RequestPluginAccess()
+ {
+ Intent i = new Intent(this, typeof(PluginDetailsActivity));
+ i.SetAction(Strings.ActionEditPluginSettings);
+ i.PutExtra(Strings.ExtraPluginPackage, _pluginPackage);
+ StartActivityForResult(i, RequestCodePluginAccess);
+ }
+
+ protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
+ {
+ base.OnActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == RequestCodePluginAccess)
+ {
+ if (new PluginDatabase(this).HasAcceptedScope(_pluginPackage, _requiredScope))
+ {
+ //user granted access. Search for the requested credentials:
+ StartQuery();
+ }
+ else
+ {
+ //user didn't grant access
+ SetResult(Result.Canceled);
+ Finish();
+ }
+ }
+ if (requestCode == RequestCodeQuery)
+ {
+ if (resultCode == KeePass.ExitCloseAfterTaskComplete)
+ {
+ //double check we really have the permission
+ if (!new PluginDatabase(this).HasAcceptedScope(_pluginPackage, _requiredScope))
+ {
+ Kp2aLog.Log("Ohoh! Scope not available, shouldn't get here. Malicious app somewhere?");
+ SetResult(Result.Canceled);
+ Finish();
+ return;
+ }
+ //return credentials to caller:
+ Intent credentialData = new Intent();
+ PluginHost.AddEntryToIntent(credentialData, App.Kp2a.GetDb().LastOpenedEntry);
+ SetResult(Result.Ok, credentialData);
+ Finish();
+ }
+ else
+ {
+ SetResult(Result.Canceled);
+ Finish();
+ }
+ }
+ }
+
+ protected override void OnSaveInstanceState(Bundle outState)
+ {
+ base.OnSaveInstanceState(outState);
+ outState.PutBoolean(StartedQuery, _startedQuery);
+ outState.PutBoolean(IsRecreate, true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/Resources/Resource.designer.cs b/src/keepass2android/Resources/Resource.designer.cs
index bf2fcb93..a674782b 100644
--- a/src/keepass2android/Resources/Resource.designer.cs
+++ b/src/keepass2android/Resources/Resource.designer.cs
@@ -3431,59 +3431,59 @@ namespace keepass2android
// aapt resource value: 0x7f090271
public const int CannotMoveGroupHere = 2131296881;
- // aapt resource value: 0x7f0902b2
- public const int CertificateFailure = 2131296946;
-
- // aapt resource value: 0x7f0902b1
- public const int CertificateWarning = 2131296945;
-
- // aapt resource value: 0x7f0902c3
- public const int ChangeLog = 2131296963;
-
- // aapt resource value: 0x7f0902c2
- public const int ChangeLog_0_7 = 2131296962;
-
- // aapt resource value: 0x7f0902c0
- public const int ChangeLog_0_8 = 2131296960;
-
- // aapt resource value: 0x7f0902bf
- public const int ChangeLog_0_8_1 = 2131296959;
-
- // aapt resource value: 0x7f0902be
- public const int ChangeLog_0_8_2 = 2131296958;
-
- // aapt resource value: 0x7f0902bd
- public const int ChangeLog_0_8_3 = 2131296957;
-
- // aapt resource value: 0x7f0902bc
- public const int ChangeLog_0_8_4 = 2131296956;
-
- // aapt resource value: 0x7f0902bb
- public const int ChangeLog_0_8_5 = 2131296955;
-
- // aapt resource value: 0x7f0902ba
- public const int ChangeLog_0_8_6 = 2131296954;
-
- // aapt resource value: 0x7f0902b9
- public const int ChangeLog_0_9 = 2131296953;
-
// aapt resource value: 0x7f0902b8
- public const int ChangeLog_0_9_1 = 2131296952;
+ public const int CertificateFailure = 2131296952;
// aapt resource value: 0x7f0902b7
- public const int ChangeLog_0_9_2 = 2131296951;
+ public const int CertificateWarning = 2131296951;
- // aapt resource value: 0x7f0902b6
- public const int ChangeLog_0_9_3 = 2131296950;
+ // aapt resource value: 0x7f0902c9
+ public const int ChangeLog = 2131296969;
- // aapt resource value: 0x7f0902b5
- public const int ChangeLog_0_9_3_r5 = 2131296949;
+ // aapt resource value: 0x7f0902c8
+ public const int ChangeLog_0_7 = 2131296968;
+
+ // aapt resource value: 0x7f0902c6
+ public const int ChangeLog_0_8 = 2131296966;
+
+ // aapt resource value: 0x7f0902c5
+ public const int ChangeLog_0_8_1 = 2131296965;
+
+ // aapt resource value: 0x7f0902c4
+ public const int ChangeLog_0_8_2 = 2131296964;
+
+ // aapt resource value: 0x7f0902c3
+ public const int ChangeLog_0_8_3 = 2131296963;
+
+ // aapt resource value: 0x7f0902c2
+ public const int ChangeLog_0_8_4 = 2131296962;
// aapt resource value: 0x7f0902c1
- public const int ChangeLog_keptDonate = 2131296961;
+ public const int ChangeLog_0_8_5 = 2131296961;
- // aapt resource value: 0x7f0902b4
- public const int ChangeLog_title = 2131296948;
+ // aapt resource value: 0x7f0902c0
+ public const int ChangeLog_0_8_6 = 2131296960;
+
+ // aapt resource value: 0x7f0902bf
+ public const int ChangeLog_0_9 = 2131296959;
+
+ // aapt resource value: 0x7f0902be
+ public const int ChangeLog_0_9_1 = 2131296958;
+
+ // aapt resource value: 0x7f0902bd
+ public const int ChangeLog_0_9_2 = 2131296957;
+
+ // aapt resource value: 0x7f0902bc
+ public const int ChangeLog_0_9_3 = 2131296956;
+
+ // aapt resource value: 0x7f0902bb
+ public const int ChangeLog_0_9_3_r5 = 2131296955;
+
+ // aapt resource value: 0x7f0902c7
+ public const int ChangeLog_keptDonate = 2131296967;
+
+ // aapt resource value: 0x7f0902ba
+ public const int ChangeLog_title = 2131296954;
// aapt resource value: 0x7f090123
public const int CheckForFileChangesOnSave_key = 2131296547;
@@ -3722,17 +3722,29 @@ namespace keepass2android
// aapt resource value: 0x7f09025f
public const int RestoringRemoteFile = 2131296863;
+ // aapt resource value: 0x7f0902b1
+ public const int SCOPE_CURRENT_ENTRY_explanation = 2131296945;
+
+ // aapt resource value: 0x7f0902b0
+ public const int SCOPE_CURRENT_ENTRY_title = 2131296944;
+
// aapt resource value: 0x7f0902af
- public const int SCOPE_CURRENT_ENTRY_explanation = 2131296943;
+ public const int SCOPE_DATABASE_ACTIONS_explanation = 2131296943;
// aapt resource value: 0x7f0902ae
- public const int SCOPE_CURRENT_ENTRY_title = 2131296942;
+ public const int SCOPE_DATABASE_ACTIONS_title = 2131296942;
- // aapt resource value: 0x7f0902ad
- public const int SCOPE_DATABASE_ACTIONS_explanation = 2131296941;
+ // aapt resource value: 0x7f0902b3
+ public const int SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE_explanation = 2131296947;
- // aapt resource value: 0x7f0902ac
- public const int SCOPE_DATABASE_ACTIONS_title = 2131296940;
+ // aapt resource value: 0x7f0902b2
+ public const int SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE_title = 2131296946;
+
+ // aapt resource value: 0x7f0902b5
+ public const int SCOPE_QUERY_CREDENTIALS_explanation = 2131296949;
+
+ // aapt resource value: 0x7f0902b4
+ public const int SCOPE_QUERY_CREDENTIALS_title = 2131296948;
// aapt resource value: 0x7f090210
public const int SaveAttachmentDialog_open = 2131296784;
@@ -4247,11 +4259,11 @@ namespace keepass2android
// aapt resource value: 0x7f090151
public const int brackets = 2131296593;
- // aapt resource value: 0x7f0902c8
- public const int browser_intall_text = 2131296968;
+ // aapt resource value: 0x7f0902ce
+ public const int browser_intall_text = 2131296974;
- // aapt resource value: 0x7f0902c9
- public const int building_search_idx = 2131296969;
+ // aapt resource value: 0x7f0902cf
+ public const int building_search_idx = 2131296975;
// aapt resource value: 0x7f09028c
public const int button_change_location = 2131296908;
@@ -4382,14 +4394,14 @@ namespace keepass2android
// aapt resource value: 0x7f090101
public const int db_key = 2131296513;
- // aapt resource value: 0x7f0902ca
- public const int decrypting_db = 2131296970;
+ // aapt resource value: 0x7f0902d0
+ public const int decrypting_db = 2131296976;
- // aapt resource value: 0x7f0902cb
- public const int decrypting_entry = 2131296971;
+ // aapt resource value: 0x7f0902d1
+ public const int decrypting_entry = 2131296977;
- // aapt resource value: 0x7f0902cc
- public const int default_checkbox = 2131296972;
+ // aapt resource value: 0x7f0902d2
+ public const int default_checkbox = 2131296978;
// aapt resource value: 0x7f0900f3
public const int default_file_path = 2131296499;
@@ -4412,8 +4424,8 @@ namespace keepass2android
// aapt resource value: 0x7f090108
public const int design_key = 2131296520;
- // aapt resource value: 0x7f0902c4
- public const int design_title = 2131296964;
+ // aapt resource value: 0x7f0902ca
+ public const int design_title = 2131296970;
// aapt resource value: 0x7f09015e
public const int digits = 2131296606;
@@ -4445,11 +4457,11 @@ namespace keepass2android
// aapt resource value: 0x7f090160
public const int ellipsis = 2131296608;
- // aapt resource value: 0x7f0902c6
- public const int enable_plugin_question = 2131296966;
+ // aapt resource value: 0x7f0902cc
+ public const int enable_plugin_question = 2131296972;
- // aapt resource value: 0x7f0902c5
- public const int enable_plugin_title = 2131296965;
+ // aapt resource value: 0x7f0902cb
+ public const int enable_plugin_title = 2131296971;
// aapt resource value: 0x7f0901fe
public const int enable_quickunlock = 2131296766;
@@ -4481,8 +4493,8 @@ namespace keepass2android
// aapt resource value: 0x7f090162
public const int entry_accessed = 2131296610;
- // aapt resource value: 0x7f0902cd
- public const int entry_and_or = 2131296973;
+ // aapt resource value: 0x7f0902d3
+ public const int entry_and_or = 2131296979;
// aapt resource value: 0x7f090172
public const int entry_binaries = 2131296626;
@@ -4535,8 +4547,8 @@ namespace keepass2android
// aapt resource value: 0x7f090294
public const int error_adding_keyfile = 2131296916;
- // aapt resource value: 0x7f0902ce
- public const int error_arc4 = 2131296974;
+ // aapt resource value: 0x7f0902d4
+ public const int error_arc4 = 2131296980;
// aapt resource value: 0x7f090173
public const int error_can_not_handle_uri = 2131296627;
@@ -4577,8 +4589,8 @@ namespace keepass2android
// aapt resource value: 0x7f09017e
public const int error_nopass = 2131296638;
- // aapt resource value: 0x7f0902cf
- public const int error_out_of_memory = 2131296975;
+ // aapt resource value: 0x7f0902d5
+ public const int error_out_of_memory = 2131296981;
// aapt resource value: 0x7f09017f
public const int error_pass_gen_type = 2131296639;
@@ -4589,8 +4601,8 @@ namespace keepass2android
// aapt resource value: 0x7f090181
public const int error_rounds_not_number = 2131296641;
- // aapt resource value: 0x7f0902d0
- public const int error_rounds_too_large = 2131296976;
+ // aapt resource value: 0x7f0902d6
+ public const int error_rounds_too_large = 2131296982;
// aapt resource value: 0x7f090216
public const int error_string_key = 2131296790;
@@ -4607,8 +4619,8 @@ namespace keepass2android
// aapt resource value: 0x7f0901d1
public const int export_database_successful = 2131296721;
- // aapt resource value: 0x7f0902b3
- public const int export_fileformats_title = 2131296947;
+ // aapt resource value: 0x7f0902b9
+ public const int export_fileformats_title = 2131296953;
// aapt resource value: 0x7f090150
public const int export_prefs = 2131296592;
@@ -4673,8 +4685,8 @@ namespace keepass2android
// aapt resource value: 0x7f090186
public const int generate_password = 2131296646;
- // aapt resource value: 0x7f0902b0
- public const int get_regular_version = 2131296944;
+ // aapt resource value: 0x7f0902b6
+ public const int get_regular_version = 2131296950;
// aapt resource value: 0x7f090187
public const int group = 2131296647;
@@ -4778,11 +4790,11 @@ namespace keepass2android
// aapt resource value: 0x7f0901dd
public const int insert_element_here = 2131296733;
- // aapt resource value: 0x7f0902d1
- public const int install_from_market = 2131296977;
+ // aapt resource value: 0x7f0902d7
+ public const int install_from_market = 2131296983;
- // aapt resource value: 0x7f0902d2
- public const int install_from_website = 2131296978;
+ // aapt resource value: 0x7f0902d8
+ public const int install_from_website = 2131296984;
// aapt resource value: 0x7f090196
public const int invalid_algorithm = 2131296662;
@@ -4991,8 +5003,8 @@ namespace keepass2android
// aapt resource value: 0x7f0901ad
public const int menu_hide_password = 2131296685;
- // aapt resource value: 0x7f0902d3
- public const int menu_homepage = 2131296979;
+ // aapt resource value: 0x7f0902d9
+ public const int menu_homepage = 2131296985;
// aapt resource value: 0x7f0901ae
public const int menu_lock = 2131296686;
@@ -5129,8 +5141,8 @@ namespace keepass2android
// aapt resource value: 0x7f0902a8
public const int plugin_enabled = 2131296936;
- // aapt resource value: 0x7f0902ab
- public const int plugin_enabled_checkbox = 2131296939;
+ // aapt resource value: 0x7f0902ad
+ public const int plugin_enabled_checkbox = 2131296941;
// aapt resource value: 0x7f0902a5
public const int plugin_packagename = 2131296933;
@@ -5141,8 +5153,8 @@ namespace keepass2android
// aapt resource value: 0x7f0902a4
public const int plugins = 2131296932;
- // aapt resource value: 0x7f0902c7
- public const int plugins_text = 2131296967;
+ // aapt resource value: 0x7f0902cd
+ public const int plugins_text = 2131296973;
// aapt resource value: 0x7f09008d
public const int popular_domain_0 = 2131296397;
@@ -5213,6 +5225,12 @@ namespace keepass2android
// aapt resource value: 0x7f090219
public const int protection = 2131296793;
+ // aapt resource value: 0x7f0902ac
+ public const int query_credentials = 2131296940;
+
+ // aapt resource value: 0x7f0902ab
+ public const int query_credentials_for_url = 2131296939;
+
// aapt resource value: 0x7f09004b
public const int quick_fixes = 2131296331;
diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml
index 26d546bc..c1a9808c 100644
--- a/src/keepass2android/Resources/values/strings.xml
+++ b/src/keepass2android/Resources/values/strings.xml
@@ -419,6 +419,9 @@
enabled
disabled
Find plug-ins online
+
+ %1$s is requesting credentials for %2$s.
+ %1$s is requesting credentials. Please select an entry.
Enabled
@@ -427,6 +430,12 @@
Current entry data
Plugin will receive all data about the current database entry and will be allowed to offer actions and modify the display of it.
+
+ Query own credentials
+ Plugin will be allowed to query the credentials associated with its own application package.
+
+ Query credentials
+ Plugin will be allowed to query credentials for deliberate web sites or applications.
Get more storage types
diff --git a/src/keepass2android/ShareUrlResults.cs b/src/keepass2android/ShareUrlResults.cs
index 81974719..8f8b81bd 100644
--- a/src/keepass2android/ShareUrlResults.cs
+++ b/src/keepass2android/ShareUrlResults.cs
@@ -59,7 +59,8 @@ namespace keepass2android
{
base.OnCreate(savedInstanceState);
- SetResult(KeePass.ExitCloseAfterTaskComplete);
+ //if user presses back to leave this activity:
+ SetResult(Result.Canceled);
_db = App.Kp2a.GetDb();
if (App.Kp2a.DatabaseIsUnlocked)
@@ -77,12 +78,6 @@ namespace keepass2android
AppTask.ToBundle(outState);
}
- public override void LaunchActivityForEntry(KeePassLib.PwEntry pwEntry, int pos)
- {
- base.LaunchActivityForEntry(pwEntry, pos);
- Finish();
- }
-
private void Query(String url)
{
try
@@ -105,13 +100,11 @@ namespace keepass2android
} catch (Exception e)
{
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
+ SetResult(Result.Canceled);
Finish();
return;
}
-
-
-
//if there is exactly one match: open the entry
if (Group.Entries.Count() == 1)
{
@@ -153,22 +146,15 @@ namespace keepass2android
{
createUrlEntry.Visibility = ViewStates.Gone;
}
-
-
-
}
public override bool OnSearchRequested()
{
- if (base.OnSearchRequested())
- {
- Finish();
- return true;
- }
- else
- {
- return false;
- }
+ Intent i = new Intent(this, typeof(SearchActivity));
+ AppTask.ToIntent(i);
+ i.SetFlags(ActivityFlags.ForwardResult);
+ StartActivity(i);
+ return true;
}
}}
diff --git a/src/keepass2android/app/AppTask.cs b/src/keepass2android/app/AppTask.cs
index c1161cd4..387c83f9 100644
--- a/src/keepass2android/app/AppTask.cs
+++ b/src/keepass2android/app/AppTask.cs
@@ -49,23 +49,23 @@ namespace keepass2android
}
///
- /// represents data stored in an intent or bundle as extra string array
+ /// represents data stored in an intent or bundle as extra string array list
///
- public class StringArrayExtra : IExtra
+ public class StringArrayListExtra : IExtra
{
public string Key { get; set; }
- public string[] Value { get; set; }
+ public IList Value { get; set; }
#region IExtra implementation
public void ToBundle(Bundle b)
{
- b.PutStringArray(Key, Value);
+ b.PutStringArrayList(Key, Value);
}
public void ToIntent(Intent i)
{
- i.PutExtra(Key, Value);
+ i.PutStringArrayListExtra(Key, Value);
}
#endregion
@@ -268,7 +268,9 @@ namespace keepass2android
///
/// User is about to search an entry for a given URL
///
- public class SearchUrlTask: AppTask
+ /// Derive from SelectEntryTask. This means that as soon as an Entry is opened, we're returning with
+ /// ExitAfterTaskComplete. This also allows te specify the flag if we need to display the user notifications.
+ public class SearchUrlTask: SelectEntryTask
{
public const String UrlToSearchKey = "UrlToSearch";
@@ -280,18 +282,29 @@ namespace keepass2android
public override void Setup(Bundle b)
{
+ base.Setup(b);
UrlToSearchFor = b.GetString(UrlToSearchKey);
}
public override IEnumerable Extras
{
get
{
+ foreach (IExtra e in base.Extras)
+ yield return e;
yield return new StringExtra { Key=UrlToSearchKey, Value = UrlToSearchFor };
}
}
public override void AfterUnlockDatabase(PasswordActivity act)
{
- ShareUrlResults.Launch(act, this);
+ if (String.IsNullOrEmpty(UrlToSearchFor))
+ {
+ GroupActivity.Launch(act, new SelectEntryTask() { ShowUserNotifications = ShowUserNotifications});
+ }
+ else
+ {
+ ShareUrlResults.Launch(act, this);
+ }
+
//removed. this causes an issue in the following workflow:
//When the user wants to find an entry for a URL but has the wrong database open he needs
@@ -308,13 +321,6 @@ namespace keepass2android
//act.AppTask = new NullTask();
}
- public override void CompleteOnCreateEntryActivity(EntryActivity activity)
- {
- //show the notifications
- activity.StartNotificationsService(true);
- //close
- activity.CloseAfterTaskComplete();
- }
}
@@ -324,12 +330,59 @@ namespace keepass2android
///
public class SelectEntryTask: AppTask
{
+ public SelectEntryTask()
+ {
+ ShowUserNotifications = true;
+ CloseAfterCreate = true;
+ }
+
+ public const String ShowUserNotificationsKey = "ShowUserNotifications";
+
+ public bool ShowUserNotifications { get; set; }
+
+ public const String CloseAfterCreateKey = "CloseAfterCreate";
+
+ public bool CloseAfterCreate { get; set; }
+
+
+ public override void Setup(Bundle b)
+ {
+ ShowUserNotifications = GetBoolFromBundle(b, ShowUserNotificationsKey, true);
+ CloseAfterCreate = GetBoolFromBundle(b, CloseAfterCreateKey, true);
+ }
+
+ private static bool GetBoolFromBundle(Bundle b, string key, bool defaultValue)
+ {
+ bool boolValue;
+ if (!Boolean.TryParse(b.GetString(key), out boolValue))
+ {
+ boolValue = defaultValue;
+ }
+ return boolValue;
+ }
+
+ public override IEnumerable Extras
+ {
+ get
+ {
+ yield return new StringExtra { Key = ShowUserNotificationsKey, Value = ShowUserNotifications.ToString() };
+ yield return new StringExtra { Key = CloseAfterCreateKey, Value = CloseAfterCreate.ToString() };
+ }
+ }
+
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{
- //show the notifications
- activity.StartNotificationsService(true);
- //close
- activity.CloseAfterTaskComplete();
+ if (ShowUserNotifications)
+ {
+ //show the notifications
+ activity.StartNotificationsService(CloseAfterCreate);
+
+ }
+ if (CloseAfterCreate)
+ {
+ //close
+ activity.CloseAfterTaskComplete();
+ }
}
}
@@ -337,7 +390,7 @@ namespace keepass2android
/// User is about to select an entry. When selected, ask whether the url he was searching for earlier should be stored
/// in the selected entry for later use.
///
- public class SelectEntryForUrlTask: AppTask
+ public class SelectEntryForUrlTask: SelectEntryTask
{
///
/// default constructor for creating from Bundle
@@ -350,10 +403,11 @@ namespace keepass2android
public SelectEntryForUrlTask(string url)
{
UrlToSearchFor = url;
+ ShowUserNotifications = true;
}
public const String UrlToSearchKey = "UrlToSearch";
-
+
public string UrlToSearchFor
{
get;
@@ -362,22 +416,25 @@ namespace keepass2android
public override void Setup(Bundle b)
{
+ base.Setup(b);
UrlToSearchFor = b.GetString(UrlToSearchKey);
}
public override IEnumerable Extras
{
get
{
+ foreach (IExtra e in base.Extras)
+ yield return e;
yield return new StringExtra { Key = UrlToSearchKey, Value = UrlToSearchFor };
}
}
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{
- //if the database is readonly, don't offer to modify the URL
- if (App.Kp2a.GetDb().CanWrite == false)
+ //if the database is readonly (or no URL exists), don't offer to modify the URL
+ if ((App.Kp2a.GetDb().CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
{
- ShowNotificationsAndClose(activity);
+ base.CompleteOnCreateEntryActivity(activity);
return;
}
@@ -386,12 +443,6 @@ namespace keepass2android
}
- private static void ShowNotificationsAndClose(EntryActivity activity)
- {
- activity.StartNotificationsService(true);
- activity.CloseAfterTaskComplete();
- }
-
///
/// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
///
@@ -404,17 +455,16 @@ namespace keepass2android
builder.SetPositiveButton(activity.GetString(Resource.String.yes), (dlgSender, dlgEvt) =>
{
- activity.AddUrlToEntry(url, () => ShowNotificationsAndClose(activity));
+ activity.AddUrlToEntry(url, () => base.CompleteOnCreateEntryActivity(activity));
});
builder.SetNegativeButton(activity.GetString(Resource.String.no), (dlgSender, dlgEvt) =>
{
- ShowNotificationsAndClose(activity);
+ base.CompleteOnCreateEntryActivity(activity);
});
Dialog dialog = builder.Create();
dialog.Show();
-
}
}
@@ -477,17 +527,35 @@ namespace keepass2android
///
public const String ProtectedFieldsListKey = Keepass2android.Pluginsdk.Strings.ExtraProtectedFieldsList;
+
+ ///
+ /// Extra key to specify whether user notifications (e.g. for copy password or keyboard) should be displayed when the entry
+ /// is selected after creating.
+ ///
+ public const String ShowUserNotificationsKey = "ShowUserNotifications";
+
+
public string Url { get; set; }
public string AllFields { get; set; }
- public string[] ProtectedFieldsList { get; set; }
+ public IList ProtectedFieldsList { get; set; }
+
+ public bool ShowUserNotifications { get; set; }
+
public override void Setup(Bundle b)
{
+ bool showUserNotification;
+ if (!Boolean.TryParse(b.GetString(ShowUserNotificationsKey), out showUserNotification))
+ {
+ showUserNotification = true; //default to true
+ }
+ ShowUserNotifications = showUserNotification;
+
Url = b.GetString(UrlKey);
AllFields = b.GetString(AllFieldsKey);
- ProtectedFieldsList = b.GetStringArray(ProtectedFieldsListKey);
+ ProtectedFieldsList = b.GetStringArrayList(ProtectedFieldsListKey);
}
public override IEnumerable Extras
{
@@ -498,7 +566,9 @@ namespace keepass2android
if (AllFields != null)
yield return new StringExtra { Key = AllFieldsKey, Value = AllFields };
if (ProtectedFieldsList != null)
- yield return new StringArrayExtra { Key = ProtectedFieldsListKey, Value = ProtectedFieldsList };
+ yield return new StringArrayListExtra { Key = ProtectedFieldsListKey, Value = ProtectedFieldsList };
+
+ yield return new StringExtra { Key = ShowUserNotificationsKey, Value = ShowUserNotifications.ToString() };
}
}
@@ -511,17 +581,14 @@ namespace keepass2android
}
if (AllFields != null)
{
- IList protectedFieldsKeys = new List();
- if (ProtectedFieldsList != null)
- {
- protectedFieldsKeys = new Org.Json.JSONArray(ProtectedFieldsList).ToArray();
- }
+
var allFields = new Org.Json.JSONObject(AllFields);
for (var iter = allFields.Keys(); iter.HasNext; )
{
string key = iter.Next().ToString();
string value = allFields.Get(key).ToString();
- bool isProtected = protectedFieldsKeys.Contains(key) || key == PwDefs.PasswordField;
+ bool isProtected = ((ProtectedFieldsList != null) && (ProtectedFieldsList.Contains(key)))
+ || (key == PwDefs.PasswordField);
newEntry.Strings.Set(key, new ProtectedString(isProtected, value));
}
@@ -531,7 +598,9 @@ namespace keepass2android
public override void AfterAddNewEntry(EntryEditActivity entryEditActivity, PwEntry newEntry)
{
- EntryActivity.Launch(entryEditActivity, newEntry, -1, new SelectEntryTask(), ActivityFlags.ForwardResult);
+ EntryActivity.Launch(entryEditActivity, newEntry, -1,
+ new SelectEntryTask() { ShowUserNotifications = this.ShowUserNotifications},
+ ActivityFlags.ForwardResult);
//no need to call Finish here, that's done in EntryEditActivity ("closeOrShowError")
}
diff --git a/src/keepass2android/fileselect/FileSelectActivity.cs b/src/keepass2android/fileselect/FileSelectActivity.cs
index 4449c480..4c6b5d81 100644
--- a/src/keepass2android/fileselect/FileSelectActivity.cs
+++ b/src/keepass2android/fileselect/FileSelectActivity.cs
@@ -26,6 +26,7 @@ using Android.Views;
using Android.Widget;
using Android.Content.PM;
using KeePassLib.Serialization;
+using Keepass2android.Pluginsdk;
using keepass2android.Io;
using Environment = Android.OS.Environment;
@@ -42,6 +43,8 @@ namespace keepass2android
Label = "@string/kp2a_findUrl",
Categories=new[]{Intent.CategoryDefault},
DataMimeType="text/plain")]
+ [IntentFilter(new[] { Strings.ActionStartWithTask },
+ Categories = new[] { Intent.CategoryDefault })]
public class FileSelectActivity : ListActivity
{
private readonly ActivityDesign _design;
@@ -84,7 +87,7 @@ namespace keepass2android
else
{
//see PasswordActivity for an explanation
- if ((savedInstanceState == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
+ if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
{
AppTask = new NullTask();
}
diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj
index a20eadd9..646ef7cb 100644
--- a/src/keepass2android/keepass2android.csproj
+++ b/src/keepass2android/keepass2android.csproj
@@ -127,6 +127,7 @@
+
diff --git a/src/keepass2android/pluginhost/PluginArrayAdapter.cs b/src/keepass2android/pluginhost/PluginArrayAdapter.cs
index 953fa198..4b73ffe8 100644
--- a/src/keepass2android/pluginhost/PluginArrayAdapter.cs
+++ b/src/keepass2android/pluginhost/PluginArrayAdapter.cs
@@ -6,7 +6,6 @@ using Android.Content;
using Android.Views;
using System.Collections.Generic;
using Android.App;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/pluginhost/PluginDatabase.cs b/src/keepass2android/pluginhost/PluginDatabase.cs
index 0c339848..93098622 100644
--- a/src/keepass2android/pluginhost/PluginDatabase.cs
+++ b/src/keepass2android/pluginhost/PluginDatabase.cs
@@ -171,5 +171,30 @@ namespace keepass2android
var prefs = _ctx.GetSharedPreferences("KP2A.Plugin." + plugin, FileCreationMode.Private);
prefs.Edit().Clear().Commit();
}
+
+ ///
+ /// Checks if the given pluginPackage has been granted the requiredScope
+ ///
+ public bool HasAcceptedScope(string pluginPackage, string requiredScope)
+ {
+ if (pluginPackage == null)
+ {
+ Log.Warn(_tag, "No pluginPackage specified!");
+ return false;
+ }
+
+ var prefs = GetPreferencesForPlugin(pluginPackage);
+ if (prefs.GetString(_accessToken, null) == null)
+ {
+ Log.Info(_tag, "No access token for " + pluginPackage);
+ return false;
+ }
+ if (!AccessManager.StringToStringArray(prefs.GetString(_scopes, "")).Contains(requiredScope))
+ {
+ Log.Info(_tag, "Scope " + requiredScope + " not granted for " + pluginPackage);
+ return false;
+ }
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/src/keepass2android/pluginhost/PluginDetailsActivity.cs b/src/keepass2android/pluginhost/PluginDetailsActivity.cs
index fb574e11..cbae8c31 100644
--- a/src/keepass2android/pluginhost/PluginDetailsActivity.cs
+++ b/src/keepass2android/pluginhost/PluginDetailsActivity.cs
@@ -15,10 +15,9 @@ using Android.Views;
using Android.Widget;
using Java.Util;
using Keepass2android.Pluginsdk;
-using keepass2android;
using keepass2android.views;
-namespace PluginHostTest
+namespace keepass2android
{
[Activity(Label = AppNames.AppName)]
[IntentFilter(new[] { Strings.ActionEditPluginSettings },
diff --git a/src/keepass2android/pluginhost/PluginHost.cs b/src/keepass2android/pluginhost/PluginHost.cs
index e709f3e6..f70af880 100644
--- a/src/keepass2android/pluginhost/PluginHost.cs
+++ b/src/keepass2android/pluginhost/PluginHost.cs
@@ -22,7 +22,10 @@ namespace keepass2android
private const string _tag = "KP2A_PluginHost";
- private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions, Strings.ScopeCurrentEntry };
+ private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions,
+ Strings.ScopeCurrentEntry,
+ Strings.ScopeQueryCredentials,
+ Strings.ScopeQueryCredentialsForOwnPackage};
public static IEnumerable GetAllPlugins(Context ctx)
{
@@ -154,9 +157,16 @@ namespace keepass2android
//add the output string array (placeholders replaced taking into account the db context)
Dictionary outputFields = entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
- JSONObject json = new JSONObject(outputFields);
- var jsonStr = json.ToString();
- intent.PutExtra(Strings.ExtraEntryOutputData, jsonStr);
+ JSONObject jsonOutput = new JSONObject(outputFields);
+ var jsonOutputStr = jsonOutput.ToString();
+ intent.PutExtra(Strings.ExtraEntryOutputData, jsonOutputStr);
+
+ JSONArray jsonProtectedFields = new JSONArray(
+ entry.OutputStrings
+ .Where(pair => pair.Value.IsProtected)
+ .Select(pair => pair.Key)
+ .ToArray());
+ intent.PutExtra(Strings.ExtraProtectedFieldsList, jsonProtectedFields.ToString());
intent.PutExtra(Strings.ExtraEntryId, entry.Uuid.ToHexString());
diff --git a/src/keepass2android/pluginhost/PluginListActivity.cs b/src/keepass2android/pluginhost/PluginListActivity.cs
index 7b5a20ba..c83dbe7d 100644
--- a/src/keepass2android/pluginhost/PluginListActivity.cs
+++ b/src/keepass2android/pluginhost/PluginListActivity.cs
@@ -6,7 +6,6 @@ using Android.Content.PM;
using Android.OS;
using Android.Widget;
using Keepass2android.Pluginsdk;
-using PluginHostTest;
namespace keepass2android
{
diff --git a/src/keepass2android/search/SearchResults.cs b/src/keepass2android/search/SearchResults.cs
index 6d2926e6..8af7f636 100644
--- a/src/keepass2android/search/SearchResults.cs
+++ b/src/keepass2android/search/SearchResults.cs
@@ -120,12 +120,11 @@ namespace keepass2android.search
public override bool OnSearchRequested()
{
- if (base.OnSearchRequested())
- {
- Finish();
- return true;
- }
- return false;
+ Intent i = new Intent(this, typeof(SearchActivity));
+ AppTask.ToIntent(i);
+ i.SetFlags(ActivityFlags.ForwardResult);
+ StartActivity(i);
+ return true;
}
}
}