From 5dbe9e5ca212f3f272adb3cede8b08cc98d1c26f Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Tue, 11 Jun 2019 23:04:41 -0400 Subject: [PATCH] add lots of misc thigns to appdelegate --- src/App/App.xaml.cs | 2 +- src/iOS.Core/Constants.cs | 32 +++ .../HockeyAppCrashManagerDelegate.cs | 40 ++++ src/iOS.Core/iOS.Core.csproj | 2 + src/iOS/AppDelegate.cs | 191 +++++++++++++++++- 5 files changed, 260 insertions(+), 7 deletions(-) create mode 100644 src/iOS.Core/Constants.cs create mode 100644 src/iOS.Core/Utilities/HockeyAppCrashManagerDelegate.cs diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 285be41ea..639f499e1 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -103,7 +103,7 @@ namespace Bit.App { return; } - await LogOutAsync(false); + Device.BeginInvokeOnMainThread(async () => await LogOutAsync(false)); } else if(message.Command == "loggedOut") { diff --git a/src/iOS.Core/Constants.cs b/src/iOS.Core/Constants.cs new file mode 100644 index 000000000..50941c0bb --- /dev/null +++ b/src/iOS.Core/Constants.cs @@ -0,0 +1,32 @@ +namespace Bit.iOS.Core +{ + public static class Constants + { + public const string AppExtensionVersionNumberKey = "version_number"; + public const string AppExtensionUrlStringKey = "url_string"; + public const string AppExtensionUsernameKey = "username"; + public const string AppExtensionPasswordKey = "password"; + public const string AppExtensionTotpKey = "totp"; + public const string AppExtensionTitleKey = "login_title"; + public const string AppExtensionNotesKey = "notes"; + public const string AppExtensionSectionTitleKey = "section_title"; + public const string AppExtensionFieldsKey = "fields"; + public const string AppExtensionReturnedFieldsKey = "returned_fields"; + public const string AppExtensionOldPasswordKey = "old_password"; + public const string AppExtensionPasswordGeneratorOptionsKey = "password_generator_options"; + public const string AppExtensionGeneratedPasswordMinLengthKey = "password_min_length"; + public const string AppExtensionGeneratedPasswordMaxLengthKey = "password_max_length"; + public const string AppExtensionGeneratedPasswordRequireDigitsKey = "password_require_digits"; + public const string AppExtensionGeneratedPasswordRequireSymbolsKey = "password_require_symbols"; + public const string AppExtensionGeneratedPasswordForbiddenCharactersKey = "password_forbidden_characters"; + public const string AppExtensionWebViewPageFillScript = "fillScript"; + public const string AppExtensionWebViewPageDetails = "pageDetails"; + + public const string UTTypeAppExtensionFindLoginAction = "org.appextension.find-login-action"; + public const string UTTypeAppExtensionSaveLoginAction = "org.appextension.save-login-action"; + public const string UTTypeAppExtensionChangePasswordAction = "org.appextension.change-password-action"; + public const string UTTypeAppExtensionFillWebViewAction = "org.appextension.fill-webview-action"; + public const string UTTypeAppExtensionFillBrowserAction = "org.appextension.fill-browser-action"; + public const string UTTypeAppExtensionSetup = "com.8bit.bitwarden.extension-setup"; + } +} diff --git a/src/iOS.Core/Utilities/HockeyAppCrashManagerDelegate.cs b/src/iOS.Core/Utilities/HockeyAppCrashManagerDelegate.cs new file mode 100644 index 000000000..e85b2c87a --- /dev/null +++ b/src/iOS.Core/Utilities/HockeyAppCrashManagerDelegate.cs @@ -0,0 +1,40 @@ +using Bit.Core.Abstractions; +using HockeyApp.iOS; +using Newtonsoft.Json; +using System.Threading.Tasks; + +namespace Bit.iOS.Core.Utilities +{ + public class HockeyAppCrashManagerDelegate : BITCrashManagerDelegate + { + private readonly IAppIdService _appIdService; + private readonly IUserService _userService; + + private string _userId; + private string _appId; + + public HockeyAppCrashManagerDelegate( + IAppIdService appIdService, + IUserService userService) + { + _appIdService = appIdService; + _userService = userService; + } + + public async Task InitAsync(BITHockeyManager manager) + { + _userId = await _userService.GetUserIdAsync(); + _appId = await _appIdService.GetAppIdAsync(); + manager.UserId = _userId; + } + + public override string ApplicationLogForCrashManager(BITCrashManager crashManager) + { + return JsonConvert.SerializeObject(new + { + AppId = _appId, + UserId = _userId + }, Formatting.Indented); + } + } +} diff --git a/src/iOS.Core/iOS.Core.csproj b/src/iOS.Core/iOS.Core.csproj index f8cae9d08..0129d3e5e 100644 --- a/src/iOS.Core/iOS.Core.csproj +++ b/src/iOS.Core/iOS.Core.csproj @@ -53,6 +53,8 @@ + + diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 061183d91..2d7fc4a11 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -1,16 +1,20 @@ using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Bit.App.Abstractions; +using Bit.App.Resources; using Bit.App.Services; using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Services; using Bit.Core.Utilities; using Bit.iOS.Core.Services; +using Bit.iOS.Core.Utilities; using Bit.iOS.Services; using CoreNFC; using Foundation; +using HockeyApp.iOS; using UIKit; namespace Bit.iOS @@ -26,18 +30,131 @@ namespace Bit.iOS private iOSPushNotificationHandler _pushHandler = null; private NFCReaderDelegate _nfcDelegate = null; + private IDeviceActionService _deviceActionService; + private IMessagingService _messagingService; + private IBroadcasterService _broadcasterService; + private IStorageService _storageService; + public override bool FinishedLaunching(UIApplication app, NSDictionary options) { Xamarin.Forms.Forms.Init(); InitApp(); Bootstrap(); + _deviceActionService = ServiceContainer.Resolve("deviceActionService"); + _messagingService = ServiceContainer.Resolve("messagingService"); + _broadcasterService = ServiceContainer.Resolve("broadcasterService"); + _storageService = ServiceContainer.Resolve("storageService"); LoadApplication(new App.App(null)); - + AppearanceAdjustments(); ZXing.Net.Mobile.Forms.iOS.Platform.Init(); + + _broadcasterService.Subscribe(nameof(AppDelegate), (message) => + { + if(message.Command == "scheduleLockTimer") + { + var lockOptionMinutes = (int)message.Data; + } + else if(message.Command == "cancelLockTimer") + { + + } + else if(message.Command == "updatedTheme") + { + + } + else if(message.Command == "copiedToClipboard") + { + + } + else if(message.Command == "listenYubiKeyOTP") + { + ListenYubiKey((bool)message.Data); + } + else if(message.Command == "showAppExtension") + { + + } + else if(message.Command == "showStatusBar") + { + UIApplication.SharedApplication.SetStatusBarHidden(!(bool)message.Data, false); + } + else if(message.Command == "syncCompleted") + { + if(message.Data is Dictionary data && data.ContainsKey("successfully")) + { + var success = data["successfully"] as bool?; + if(success.GetValueOrDefault()) + { + + } + } + } + else if(message.Command == "addedCipher" || message.Command == "editedCipher") + { + + } + else if(message.Command == "deletedCipher") + { + + } + else if(message.Command == "loggedOut") + { + + } + }); + return base.FinishedLaunching(app, options); } + public override void DidEnterBackground(UIApplication uiApplication) + { + var view = new UIView(UIApplication.SharedApplication.KeyWindow.Frame) + { + Tag = 4321 + }; + var backgroundView = new UIView(UIApplication.SharedApplication.KeyWindow.Frame) + { + BackgroundColor = new UIColor(red: 0.93f, green: 0.94f, blue: 0.96f, alpha: 1.0f) + }; + var imageView = new UIImageView(new UIImage("logo.png")) + { + Center = new CoreGraphics.CGPoint(view.Center.X, view.Center.Y - 30) + }; + view.AddSubview(backgroundView); + view.AddSubview(imageView); + UIApplication.SharedApplication.KeyWindow.AddSubview(view); + UIApplication.SharedApplication.KeyWindow.BringSubviewToFront(view); + UIApplication.SharedApplication.KeyWindow.EndEditing(true); + UIApplication.SharedApplication.SetStatusBarHidden(true, false); + _storageService.SaveAsync(Bit.Core.Constants.LastActiveKey, DateTime.UtcNow); + base.DidEnterBackground(uiApplication); + } + + public override void OnActivated(UIApplication uiApplication) + { + base.OnActivated(uiApplication); + UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0; + var view = UIApplication.SharedApplication.KeyWindow.ViewWithTag(4321); + if(view != null) + { + view.RemoveFromSuperview(); + UIApplication.SharedApplication.SetStatusBarHidden(false, false); + } + } + + public override void WillEnterForeground(UIApplication uiApplication) + { + _messagingService.Send("Resumed"); + base.WillEnterForeground(uiApplication); + } + + public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, + NSObject annotation) + { + return true; + } + public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error) { _pushHandler?.OnErrorReceived(error); @@ -75,8 +192,19 @@ namespace Bit.iOS ServiceContainer.Init(); _pushHandler = new iOSPushNotificationHandler( ServiceContainer.Resolve("pushNotificationListenerService")); - _nfcDelegate = new NFCReaderDelegate((success, message) => { }); // TODO: process YubiKey - // TODO: HockeyApp Init + _nfcDelegate = new NFCReaderDelegate((success, message) => + _messagingService.Send("GotYubiKeyOTP", message)); + + var crashManagerDelegate = new HockeyAppCrashManagerDelegate( + ServiceContainer.Resolve("appIdService"), + ServiceContainer.Resolve("userService")); + var manager = BITHockeyManager.SharedHockeyManager; + manager.Configure("51f96ae568ba45f699a18ad9f63046c3", crashManagerDelegate); + manager.CrashManager.CrashManagerStatus = BITCrashManagerStatus.AutoSend; + manager.StartManager(); + manager.Authenticator.AuthenticateInstallation(); + manager.DisableMetricsManager = manager.DisableFeedbackManager = manager.DisableUpdateManager = true; + var task = crashManagerDelegate.InitAsync(manager); } private void RegisterLocalServices() @@ -146,16 +274,67 @@ namespace Bit.iOS private async Task BootstrapAsync() { var disableFavicon = await ServiceContainer.Resolve("storageService").GetAsync( - Constants.DisableFaviconKey); - await ServiceContainer.Resolve("stateService").SaveAsync(Constants.DisableFaviconKey, - disableFavicon); + Bit.Core.Constants.DisableFaviconKey); + await ServiceContainer.Resolve("stateService").SaveAsync( + Bit.Core.Constants.DisableFaviconKey, disableFavicon); await ServiceContainer.Resolve("environmentService").SetUrlsFromStorageAsync(); } private void AppearanceAdjustments() { + var primaryColor = new UIColor(red: 0.24f, green: 0.55f, blue: 0.74f, alpha: 1.0f); + var grayLight = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f); + UINavigationBar.Appearance.ShadowImage = new UIImage(); UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default); + UIBarButtonItem.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor; + UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).SetTitleColor(primaryColor, + UIControlState.Normal); + UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor; + UIStepper.Appearance.TintColor = grayLight; + UISlider.Appearance.TintColor = primaryColor; + UIApplication.SharedApplication.StatusBarHidden = false; + UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent; + } + + private void ListenYubiKey(bool listen) + { + if(_deviceActionService.SupportsNfc()) + { + _nfcSession?.InvalidateSession(); + _nfcSession?.Dispose(); + _nfcSession = null; + if(listen) + { + _nfcSession = new NFCNdefReaderSession(_nfcDelegate, null, true) + { + AlertMessage = AppResources.HoldYubikeyNearTop + }; + _nfcSession.BeginSession(); + } + } + } + + private void ShowAppExtension() + { + var itemProvider = new NSItemProvider(new NSDictionary(), Core.Constants.UTTypeAppExtensionSetup); + var extensionItem = new NSExtensionItem(); + extensionItem.Attachments = new NSItemProvider[] { itemProvider }; + var activityViewController = new UIActivityViewController(new NSExtensionItem[] { extensionItem }, null); + activityViewController.CompletionHandler = (activityType, completed) => + { + // TODO + //page.EnabledExtension(completed && activityType == "com.8bit.bitwarden.find-login-action-extension"); + }; + var modal = UIApplication.SharedApplication.KeyWindow.RootViewController.ModalViewController; + if(activityViewController.PopoverPresentationController != null) + { + activityViewController.PopoverPresentationController.SourceView = modal.View; + var frame = UIScreen.MainScreen.Bounds; + frame.Height /= 2; + activityViewController.PopoverPresentationController.SourceRect = frame; + } + modal.PresentViewController(activityViewController, true, null); } } }