improve user experience with autofill security alert:
* remember trusted links * allow to make an app trusted * improve message by displaying application label instead of package name (show package name once for security)
This commit is contained in:
@@ -1232,8 +1232,8 @@ Initial public release
|
||||
|
||||
|
||||
<string name="AutofillWarning_title">Security Alert: Unrecognized domain/package link</string>
|
||||
<string name="AutofillWarning_Intro">You are about to insert credentials for domain "%1$s" into the app with package name "%2$s".</string>
|
||||
<string name="AutofillWarning_Intro">You are about to insert credentials for domain "%1$s" into the app "%2$s".</string>
|
||||
<string name="AutofillWarning_FillDomainInUntrustedApp">If you trust "%2$s" to belong to "%1$s" or you trust the app "%2$s" not to misuse the credentials (e.g. because it is a trusted browser app), it is ok to continue. If not, please cancel.</string>
|
||||
<string name="AutofillWarning_continue">Security Alert: Unrecognized domain/package link</string>
|
||||
<string name="AutofillWarning_trustAsBrowser">Accept always in "%1$s"</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -10,13 +10,13 @@ using Android.Views.Autofill;
|
||||
using Android.Widget;
|
||||
using Java.Util;
|
||||
using keepass2android.services.AutofillBase.model;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.Content.PM;
|
||||
using Com.Dropbox.Core.V2.Teamlog;
|
||||
using AlertDialog = Android.App.AlertDialog;
|
||||
|
||||
namespace keepass2android.services.AutofillBase
|
||||
{
|
||||
|
||||
public abstract class ChooseForAutofillActivityBase : AndroidX.AppCompat.App.AppCompatActivity
|
||||
{
|
||||
protected Intent ReplyIntent;
|
||||
@@ -51,6 +51,7 @@ namespace keepass2android.services.AutofillBase
|
||||
RestartApp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Intent.HasExtra(ExtraDisplayWarning))
|
||||
{
|
||||
AutofillServiceBase.DisplayWarning warning =
|
||||
@@ -60,22 +61,56 @@ namespace keepass2android.services.AutofillBase
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.SetTitle(this.GetString(Resource.String.AutofillWarning_title));
|
||||
|
||||
string appName = Intent.GetStringExtra(ExtraQueryPackageString);
|
||||
string appNameWithPackage = appName;
|
||||
try
|
||||
{
|
||||
var appInfo = PackageManager.GetApplicationInfo(appName, 0);
|
||||
if (appInfo != null)
|
||||
{
|
||||
appName = PackageManager.GetApplicationLabel(appInfo);
|
||||
appNameWithPackage = appName + " (" + Intent.GetStringExtra(ExtraQueryPackageString) + ")";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
builder.SetMessage(
|
||||
GetString(Resource.String.AutofillWarning_Intro, new Java.Lang.Object[] { Intent.GetStringExtra(ExtraQueryDomainString), Intent.GetStringExtra(ExtraQueryPackageString) })
|
||||
GetString(Resource.String.AutofillWarning_Intro, new Java.Lang.Object[]
|
||||
{
|
||||
Intent.GetStringExtra(ExtraQueryDomainString), appNameWithPackage
|
||||
})
|
||||
+ " " +
|
||||
this.GetString(Resource.String.AutofillWarning_FillDomainInUntrustedApp, new Java.Lang.Object[] { Intent.GetStringExtra(ExtraQueryDomainString), Intent.GetStringExtra(ExtraQueryPackageString) }));
|
||||
this.GetString(Resource.String.AutofillWarning_FillDomainInUntrustedApp, new Java.Lang.Object[]
|
||||
{
|
||||
Intent.GetStringExtra(ExtraQueryDomainString), appName
|
||||
}));
|
||||
|
||||
builder.SetPositiveButton(this.GetString(Resource.String.Continue),
|
||||
(dlgSender, dlgEvt) =>
|
||||
{
|
||||
new Kp2aDigitalAssetLinksDataSource(this).RememberTrustedLink(Intent.GetStringExtra(ExtraQueryDomainString),
|
||||
Intent.GetStringExtra(ExtraQueryPackageString));
|
||||
Proceed();
|
||||
|
||||
});
|
||||
builder.SetNeutralButton(this.GetString(Resource.String.AutofillWarning_trustAsBrowser, new Java.Lang.Object[]
|
||||
{appName}),
|
||||
(sender, args) =>
|
||||
{
|
||||
new Kp2aDigitalAssetLinksDataSource(this).RememberAsTrustedApp(Intent.GetStringExtra(ExtraQueryPackageString));
|
||||
Proceed();
|
||||
});
|
||||
|
||||
builder.SetNegativeButton(this.GetString(Resource.String.cancel), (dlgSender, dlgEvt) =>
|
||||
{
|
||||
Finish();
|
||||
});
|
||||
|
||||
|
||||
Dialog dialog = builder.Create();
|
||||
dialog.Show();
|
||||
@@ -86,6 +121,7 @@ namespace keepass2android.services.AutofillBase
|
||||
Proceed();
|
||||
}
|
||||
|
||||
|
||||
private void Proceed()
|
||||
{
|
||||
string requestedUrl = Intent.GetStringExtra(ExtraQueryString);
|
||||
|
@@ -1,33 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.Content;
|
||||
using Android.Preferences;
|
||||
|
||||
namespace keepass2android.services.AutofillBase
|
||||
{
|
||||
|
||||
internal class Kp2aDigitalAssetLinksDataSource
|
||||
{
|
||||
private static Kp2aDigitalAssetLinksDataSource instance;
|
||||
|
||||
private Kp2aDigitalAssetLinksDataSource() { }
|
||||
private const string Autofilltrustedapps = "AutoFillTrustedApps";
|
||||
private readonly Context _ctx;
|
||||
|
||||
public static Kp2aDigitalAssetLinksDataSource Instance
|
||||
public Kp2aDigitalAssetLinksDataSource(Context ctx)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new Kp2aDigitalAssetLinksDataSource();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
public bool IsValid(Context context, string webDomain, string packageName)
|
||||
public bool IsTrustedApp(string packageName)
|
||||
{
|
||||
return (IsTrustedBrowser(packageName));
|
||||
if (_trustedBrowsers.Contains(packageName))
|
||||
return true;
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(_ctx);
|
||||
var trustedApps = prefs.GetStringSet(Autofilltrustedapps, new List<string>()).ToHashSet();
|
||||
return trustedApps.Contains(packageName);
|
||||
}
|
||||
|
||||
public bool IsTrustedLink(string domain, string targetPackage)
|
||||
{
|
||||
//we can fill everything into trusted apps (aka browsers)
|
||||
if (IsTrustedApp(targetPackage))
|
||||
return true;
|
||||
//see if the user explicitly allows to fill credentials for domain into targetPackage:
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(_ctx);
|
||||
var trustedLinks = prefs.GetStringSet("AutoFillTrustedLinks", new List<string>()).ToHashSet();
|
||||
return trustedLinks.Contains(BuildLink(domain, targetPackage));
|
||||
}
|
||||
|
||||
public void RememberAsTrustedApp(string packageName)
|
||||
{
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(_ctx);
|
||||
var trustedApps = prefs.GetStringSet(Autofilltrustedapps, new List<string>()).ToHashSet();
|
||||
trustedApps.Add(packageName);
|
||||
prefs.Edit().PutStringSet(Autofilltrustedapps, trustedApps).Commit();
|
||||
|
||||
}
|
||||
|
||||
public void RememberTrustedLink(string domain, string package)
|
||||
{
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(_ctx);
|
||||
var trustedLinks = prefs.GetStringSet("AutoFillTrustedLinks", new List<string>()).ToHashSet();
|
||||
trustedLinks.Add(BuildLink(domain, package));
|
||||
prefs.Edit().PutStringSet("AutoFillTrustedLinks", trustedLinks).Commit();
|
||||
}
|
||||
|
||||
private static string BuildLink(string domain, string package)
|
||||
{
|
||||
return domain + " + " + package;
|
||||
}
|
||||
|
||||
|
||||
static readonly HashSet<string> _trustedBrowsers = new HashSet<string>
|
||||
{
|
||||
"org.mozilla.firefox","org.mozilla.firefox_beta","org.mozilla.klar","org.mozilla.focus",
|
||||
@@ -41,9 +73,5 @@ namespace keepass2android.services.AutofillBase
|
||||
"acr.browser.lightning", "acr.browser.barebones", "jp.hazuki.yuzubrowser"
|
||||
};
|
||||
|
||||
private bool IsTrustedBrowser(string packageName)
|
||||
{
|
||||
return _trustedBrowsers.Contains(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,8 @@ namespace keepass2android.services.AutofillBase
|
||||
public string PackageId { get; set; }
|
||||
|
||||
public StructureParser(Context context, AssistStructure structure)
|
||||
{
|
||||
{
|
||||
kp2aDigitalAssetLinksDataSource = new Kp2aDigitalAssetLinksDataSource(context);
|
||||
mContext = context;
|
||||
Structure = structure;
|
||||
AutofillFields = new AutofillFieldMetadataCollection();
|
||||
@@ -176,7 +177,7 @@ namespace keepass2android.services.AutofillBase
|
||||
result.PackageName = Structure.ActivityComponent.PackageName;
|
||||
if (!string.IsNullOrEmpty(webDomain))
|
||||
{
|
||||
result.IncompatiblePackageAndDomain = !Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, result.PackageName);
|
||||
result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName);
|
||||
if (result.IncompatiblePackageAndDomain)
|
||||
{
|
||||
CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}");
|
||||
@@ -196,6 +197,8 @@ namespace keepass2android.services.AutofillBase
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> _usernameHints = new HashSet<string> { "email","e-mail","username" };
|
||||
private Kp2aDigitalAssetLinksDataSource kp2aDigitalAssetLinksDataSource;
|
||||
|
||||
private static bool HasUsernameHint(AssistStructure.ViewNode f)
|
||||
{
|
||||
return ContainsAny(f.IdEntry, _usernameHints) ||
|
||||
|
Reference in New Issue
Block a user