From 4112e0a4c9fba06003c658789864a36eceb0ea7a Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 17 May 2019 14:34:00 -0400 Subject: [PATCH] autofill actions --- src/Android/Services/DeviceActionService.cs | 107 +++++++++++++++++++ src/App/Abstractions/IDeviceActionService.cs | 4 + src/iOS/Services/DeviceActionService.cs | 16 +++ 3 files changed, 127 insertions(+) diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs index 7a89295b3..dd71f6f59 100644 --- a/src/Android/Services/DeviceActionService.cs +++ b/src/Android/Services/DeviceActionService.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Android; using Android.App; +using Android.App.Assist; using Android.Content; using Android.Content.PM; using Android.Nfc; @@ -21,6 +23,9 @@ using Bit.App.Resources; using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; +using Bit.Core.Models.View; +using Bit.Core.Utilities; +using Bit.Droid.Autofill; using Plugin.CurrentActivity; namespace Bit.Droid.Services @@ -401,6 +406,85 @@ namespace Bit.Droid.Services return result.Task; } + public void Autofill(CipherView cipher) + { + var activity = (MainActivity)CrossCurrentActivity.Current.Activity; + if(activity.Intent.GetBooleanExtra("autofillFramework", false)) + { + if(cipher == null) + { + activity.SetResult(Result.Canceled); + activity.Finish(); + return; + } + var structure = activity.Intent + .GetParcelableExtra(AutofillManager.ExtraAssistStructure) as AssistStructure; + if(structure == null) + { + activity.SetResult(Result.Canceled); + activity.Finish(); + return; + } + var parser = new Parser(structure, activity.ApplicationContext); + parser.Parse(); + if(!parser.FieldCollection.Fields.Any() || string.IsNullOrWhiteSpace(parser.Uri)) + { + activity.SetResult(Result.Canceled); + activity.Finish(); + return; + } + var dataset = AutofillHelpers.BuildDataset(activity, parser.FieldCollection, new FilledItem(cipher)); + var replyIntent = new Intent(); + replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, dataset); + activity.SetResult(Result.Ok, replyIntent); + activity.Finish(); + } + else + { + var data = new Intent(); + if(cipher == null) + { + data.PutExtra("canceled", "true"); + } + else + { + var task = CopyTotpAsync(cipher); + data.PutExtra("uri", cipher.Login.Uri); + data.PutExtra("username", cipher.Login.Username); + data.PutExtra("password", cipher.Login.Password); + } + if(activity.Parent == null) + { + activity.SetResult(Result.Ok, data); + } + else + { + activity.Parent.SetResult(Result.Ok, data); + } + activity.Finish(); + _messagingService.Send("finishMainActivity"); + } + } + + public void CloseAutofill() + { + Autofill(null); + } + + public void Background() + { + var activity = (MainActivity)CrossCurrentActivity.Current.Activity; + if(activity.Intent.GetBooleanExtra("autofillFramework", false)) + { + activity.SetResult(Result.Canceled); + activity.Finish(); + } + else + { + activity.MoveTaskToBack(true); + } + } + private bool DeleteDir(Java.IO.File dir) { if(dir != null && dir.IsDirectory) @@ -472,5 +556,28 @@ namespace Bit.Droid.Services intent.AddFlags(flags); return intent; } + + private async Task CopyTotpAsync(CipherView cipher) + { + var autoCopyDisabled = await _storageService.GetAsync(Constants.DisableAutoTotpCopyKey); + var canAccessPremium = await ServiceContainer.Resolve("userService").CanAccessPremiumAsync(); + if(canAccessPremium && !autoCopyDisabled.GetValueOrDefault() && + !string.IsNullOrWhiteSpace(cipher?.Login?.Totp)) + { + var totp = await ServiceContainer.Resolve("totpService").GetCodeAsync(cipher.Login.Totp); + if(totp != null) + { + CopyToClipboard(totp); + } + } + } + + private void CopyToClipboard(string text) + { + var activity = (MainActivity)CrossCurrentActivity.Current.Activity; + var clipboardManager = activity.GetSystemService( + Context.ClipboardService) as Android.Content.ClipboardManager; + clipboardManager.Text = text; + } } } \ No newline at end of file diff --git a/src/App/Abstractions/IDeviceActionService.cs b/src/App/Abstractions/IDeviceActionService.cs index e34c05e81..f07f0e54a 100644 --- a/src/App/Abstractions/IDeviceActionService.cs +++ b/src/App/Abstractions/IDeviceActionService.cs @@ -1,4 +1,5 @@ using Bit.Core.Enums; +using Bit.Core.Models.View; using System.Threading.Tasks; namespace Bit.App.Abstractions @@ -24,5 +25,8 @@ namespace Bit.App.Abstractions int SystemMajorVersion(); string SystemModel(); Task DisplayAlertAsync(string title, string message, string cancel, params string[] buttons); + void Autofill(CipherView cipher); + void CloseAutofill(); + void Background(); } } diff --git a/src/iOS/Services/DeviceActionService.cs b/src/iOS/Services/DeviceActionService.cs index bb575dc9b..f0f3c7ac5 100644 --- a/src/iOS/Services/DeviceActionService.cs +++ b/src/iOS/Services/DeviceActionService.cs @@ -10,6 +10,7 @@ using Bit.App.Resources; using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; +using Bit.Core.Models.View; using Bit.iOS.Core.Views; using CoreGraphics; using Foundation; @@ -287,6 +288,21 @@ namespace Bit.iOS.Services return result.Task; } + public void Autofill(CipherView cipher) + { + throw new NotImplementedException(); + } + + public void CloseAutofill() + { + throw new NotImplementedException(); + } + + public void Background() + { + throw new NotImplementedException(); + } + private void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e) { if(sender is UIImagePickerController picker)