2019-03-28 03:12:44 +03:00
|
|
|
|
using System;
|
2019-06-12 06:04:41 +03:00
|
|
|
|
using System.Collections.Generic;
|
2019-07-01 23:56:42 +03:00
|
|
|
|
using System.Threading.Tasks;
|
2019-06-27 23:22:58 +03:00
|
|
|
|
using AuthenticationServices;
|
2019-06-11 22:20:28 +03:00
|
|
|
|
using Bit.App.Abstractions;
|
2019-06-12 06:04:41 +03:00
|
|
|
|
using Bit.App.Resources;
|
2019-06-11 22:20:28 +03:00
|
|
|
|
using Bit.App.Services;
|
2019-06-24 19:23:00 +03:00
|
|
|
|
using Bit.App.Utilities;
|
2019-07-01 23:56:42 +03:00
|
|
|
|
using Bit.Core;
|
2019-06-11 22:20:28 +03:00
|
|
|
|
using Bit.Core.Abstractions;
|
|
|
|
|
using Bit.Core.Services;
|
|
|
|
|
using Bit.Core.Utilities;
|
2019-06-12 06:04:41 +03:00
|
|
|
|
using Bit.iOS.Core.Utilities;
|
2019-06-11 22:20:28 +03:00
|
|
|
|
using Bit.iOS.Services;
|
2019-06-12 05:20:59 +03:00
|
|
|
|
using CoreNFC;
|
2019-03-28 03:12:44 +03:00
|
|
|
|
using Foundation;
|
|
|
|
|
using UIKit;
|
2019-06-26 16:35:18 +03:00
|
|
|
|
using Xamarin.Forms;
|
|
|
|
|
using Xamarin.Forms.Platform.iOS;
|
2019-03-28 03:12:44 +03:00
|
|
|
|
|
|
|
|
|
namespace Bit.iOS
|
|
|
|
|
{
|
|
|
|
|
[Register("AppDelegate")]
|
2019-06-28 15:21:44 +03:00
|
|
|
|
public partial class AppDelegate : FormsApplicationDelegate
|
2019-03-28 03:12:44 +03:00
|
|
|
|
{
|
2019-06-12 05:20:59 +03:00
|
|
|
|
private NFCNdefReaderSession _nfcSession = null;
|
|
|
|
|
private iOSPushNotificationHandler _pushHandler = null;
|
|
|
|
|
private NFCReaderDelegate _nfcDelegate = null;
|
2019-07-01 23:56:42 +03:00
|
|
|
|
private NSTimer _clipboardTimer = null;
|
|
|
|
|
private NSTimer _lockTimer = null;
|
2019-06-11 22:20:28 +03:00
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
private IDeviceActionService _deviceActionService;
|
|
|
|
|
private IMessagingService _messagingService;
|
|
|
|
|
private IBroadcasterService _broadcasterService;
|
|
|
|
|
private IStorageService _storageService;
|
|
|
|
|
|
2019-03-28 03:12:44 +03:00
|
|
|
|
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
|
|
|
|
|
{
|
2019-06-27 03:28:23 +03:00
|
|
|
|
Forms.Init();
|
2019-06-11 22:20:28 +03:00
|
|
|
|
InitApp();
|
2019-06-12 06:04:41 +03:00
|
|
|
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
|
|
|
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
|
|
|
|
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
|
|
|
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
2019-04-23 00:08:37 +03:00
|
|
|
|
|
2019-05-17 19:03:35 +03:00
|
|
|
|
LoadApplication(new App.App(null));
|
2019-06-28 15:21:44 +03:00
|
|
|
|
iOSCoreHelpers.AppearanceAdjustments();
|
2019-05-23 03:28:31 +03:00
|
|
|
|
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
|
2019-06-12 06:04:41 +03:00
|
|
|
|
|
2019-06-27 23:22:58 +03:00
|
|
|
|
_broadcasterService.Subscribe(nameof(AppDelegate), async (message) =>
|
2019-06-12 06:04:41 +03:00
|
|
|
|
{
|
|
|
|
|
if(message.Command == "scheduleLockTimer")
|
|
|
|
|
{
|
|
|
|
|
var lockOptionMinutes = (int)message.Data;
|
2019-07-01 23:56:42 +03:00
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "cancelLockTimer")
|
|
|
|
|
{
|
2019-06-26 16:35:18 +03:00
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "updatedTheme")
|
|
|
|
|
{
|
2019-06-24 19:23:00 +03:00
|
|
|
|
// ThemeManager.SetThemeStyle(message.Data as string);
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "copiedToClipboard")
|
|
|
|
|
{
|
2019-07-01 23:56:42 +03:00
|
|
|
|
await ClearClipboardTimerAsync(message.Data as Tuple<string, int?, bool>);
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "listenYubiKeyOTP")
|
|
|
|
|
{
|
|
|
|
|
ListenYubiKey((bool)message.Data);
|
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "showAppExtension")
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "showStatusBar")
|
|
|
|
|
{
|
2019-06-26 17:05:31 +03:00
|
|
|
|
Device.BeginInvokeOnMainThread(() =>
|
|
|
|
|
UIApplication.SharedApplication.SetStatusBarHidden(!(bool)message.Data, false));
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "syncCompleted")
|
|
|
|
|
{
|
|
|
|
|
if(message.Data is Dictionary<string, object> data && data.ContainsKey("successfully"))
|
|
|
|
|
{
|
|
|
|
|
var success = data["successfully"] as bool?;
|
2019-06-27 23:22:58 +03:00
|
|
|
|
if(success.GetValueOrDefault() && _deviceActionService.SystemMajorVersion() >= 12)
|
2019-06-12 06:04:41 +03:00
|
|
|
|
{
|
2019-06-27 23:22:58 +03:00
|
|
|
|
await ASHelpers.ReplaceAllIdentities();
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "addedCipher" || message.Command == "editedCipher")
|
|
|
|
|
{
|
2019-06-27 23:22:58 +03:00
|
|
|
|
if(_deviceActionService.SystemMajorVersion() >= 12)
|
|
|
|
|
{
|
|
|
|
|
if(await ASHelpers.IdentitiesCanIncremental())
|
|
|
|
|
{
|
|
|
|
|
var cipherId = message.Data as string;
|
|
|
|
|
if(message.Command == "addedCipher" && !string.IsNullOrWhiteSpace(cipherId))
|
|
|
|
|
{
|
|
|
|
|
var identity = await ASHelpers.GetCipherIdentityAsync(cipherId);
|
|
|
|
|
if(identity == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await ASCredentialIdentityStore.SharedStore?.SaveCredentialIdentitiesAsync(
|
|
|
|
|
new ASPasswordCredentialIdentity[] { identity });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await ASHelpers.ReplaceAllIdentities();
|
|
|
|
|
}
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "deletedCipher")
|
|
|
|
|
{
|
2019-06-27 23:22:58 +03:00
|
|
|
|
if(_deviceActionService.SystemMajorVersion() >= 12)
|
|
|
|
|
{
|
|
|
|
|
if(await ASHelpers.IdentitiesCanIncremental())
|
|
|
|
|
{
|
|
|
|
|
var identity = ASHelpers.ToCredentialIdentity(
|
|
|
|
|
message.Data as Bit.Core.Models.View.CipherView);
|
|
|
|
|
if(identity == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await ASCredentialIdentityStore.SharedStore?.RemoveCredentialIdentitiesAsync(
|
|
|
|
|
new ASPasswordCredentialIdentity[] { identity });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await ASHelpers.ReplaceAllIdentities();
|
|
|
|
|
}
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
else if(message.Command == "loggedOut")
|
|
|
|
|
{
|
2019-06-27 23:22:58 +03:00
|
|
|
|
if(_deviceActionService.SystemMajorVersion() >= 12)
|
|
|
|
|
{
|
|
|
|
|
await ASCredentialIdentityStore.SharedStore?.RemoveAllCredentialIdentitiesAsync();
|
|
|
|
|
}
|
2019-06-12 06:04:41 +03:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2019-03-28 03:12:44 +03:00
|
|
|
|
return base.FinishedLaunching(app, options);
|
|
|
|
|
}
|
2019-06-11 22:20:28 +03:00
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
public override void DidEnterBackground(UIApplication uiApplication)
|
|
|
|
|
{
|
|
|
|
|
var view = new UIView(UIApplication.SharedApplication.KeyWindow.Frame)
|
|
|
|
|
{
|
|
|
|
|
Tag = 4321
|
|
|
|
|
};
|
|
|
|
|
var backgroundView = new UIView(UIApplication.SharedApplication.KeyWindow.Frame)
|
|
|
|
|
{
|
2019-06-26 16:35:18 +03:00
|
|
|
|
BackgroundColor = ((Color)Xamarin.Forms.Application.Current.Resources["SplashBackgroundColor"])
|
|
|
|
|
.ToUIColor()
|
2019-06-12 06:04:41 +03:00
|
|
|
|
};
|
2019-06-26 16:35:18 +03:00
|
|
|
|
var theme = ThemeManager.GetTheme(false);
|
|
|
|
|
var darkbasedTheme = theme == "dark" || theme == "black" || theme == "nord";
|
|
|
|
|
var logo = new UIImage(darkbasedTheme ? "logo_white.png" : "logo.png");
|
|
|
|
|
var imageView = new UIImageView(logo)
|
2019-06-12 06:04:41 +03:00
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2019-06-25 00:02:05 +03:00
|
|
|
|
_messagingService.Send("resumed");
|
2019-06-12 06:04:41 +03:00
|
|
|
|
base.WillEnterForeground(uiApplication);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication,
|
|
|
|
|
NSObject annotation)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-11 22:20:28 +03:00
|
|
|
|
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
|
|
|
|
|
{
|
|
|
|
|
_pushHandler?.OnErrorReceived(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
|
|
|
|
|
{
|
|
|
|
|
_pushHandler?.OnRegisteredSuccess(deviceToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void DidRegisterUserNotificationSettings(UIApplication application,
|
|
|
|
|
UIUserNotificationSettings notificationSettings)
|
|
|
|
|
{
|
|
|
|
|
application.RegisterForRemoteNotifications();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo,
|
|
|
|
|
Action<UIBackgroundFetchResult> completionHandler)
|
|
|
|
|
{
|
|
|
|
|
_pushHandler?.OnMessageReceived(userInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
|
|
|
|
|
{
|
|
|
|
|
_pushHandler?.OnMessageReceived(userInfo);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 15:21:44 +03:00
|
|
|
|
public void InitApp()
|
2019-06-11 22:20:28 +03:00
|
|
|
|
{
|
|
|
|
|
if(ServiceContainer.RegisteredServices.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 15:21:44 +03:00
|
|
|
|
// Migration services
|
2019-06-11 22:20:28 +03:00
|
|
|
|
ServiceContainer.Register<ILogService>("logService", new ConsoleLogService());
|
|
|
|
|
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
|
|
|
|
|
if(false && App.Migration.MigrationHelpers.NeedsMigration())
|
|
|
|
|
{
|
|
|
|
|
ServiceContainer.Register<App.Migration.Abstractions.IOldSecureStorageService>(
|
|
|
|
|
"oldSecureStorageService", new Migration.KeyChainStorageService());
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 15:21:44 +03:00
|
|
|
|
iOSCoreHelpers.RegisterLocalServices();
|
|
|
|
|
RegisterPush();
|
|
|
|
|
ServiceContainer.Init();
|
|
|
|
|
iOSCoreHelpers.RegisterHockeyApp();
|
|
|
|
|
_pushHandler = new iOSPushNotificationHandler(
|
|
|
|
|
ServiceContainer.Resolve<IPushNotificationListenerService>("pushNotificationListenerService"));
|
|
|
|
|
_nfcDelegate = new NFCReaderDelegate((success, message) =>
|
|
|
|
|
_messagingService.Send("gotYubiKeyOTP", message));
|
2019-06-11 22:20:28 +03:00
|
|
|
|
|
2019-06-28 15:21:44 +03:00
|
|
|
|
iOSCoreHelpers.Bootstrap();
|
|
|
|
|
}
|
2019-06-11 22:20:28 +03:00
|
|
|
|
|
2019-06-28 15:21:44 +03:00
|
|
|
|
private void RegisterPush()
|
|
|
|
|
{
|
2019-06-11 22:20:28 +03:00
|
|
|
|
var notificationListenerService = new PushNotificationListenerService();
|
|
|
|
|
ServiceContainer.Register<IPushNotificationListenerService>(
|
|
|
|
|
"pushNotificationListenerService", notificationListenerService);
|
|
|
|
|
var iosPushNotificationService = new iOSPushNotificationService();
|
|
|
|
|
ServiceContainer.Register<IPushNotificationService>(
|
|
|
|
|
"pushNotificationService", iosPushNotificationService);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-01 23:56:42 +03:00
|
|
|
|
private async Task ClearClipboardTimerAsync(Tuple<string, int?, bool> data)
|
|
|
|
|
{
|
|
|
|
|
if(data.Item3)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var clearMs = data.Item2;
|
|
|
|
|
if(clearMs == null)
|
|
|
|
|
{
|
|
|
|
|
var clearSeconds = await _storageService.GetAsync<int?>(Constants.ClearClipboardKey);
|
|
|
|
|
if(clearSeconds != null)
|
|
|
|
|
{
|
|
|
|
|
clearMs = clearSeconds.Value * 1000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(clearMs == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_clipboardTimer?.Invalidate();
|
|
|
|
|
_clipboardTimer?.Dispose();
|
|
|
|
|
_clipboardTimer = null;
|
|
|
|
|
var lastClipboardValue = data.Item1;
|
|
|
|
|
var clearMsSpan = TimeSpan.FromMilliseconds(clearMs.Value);
|
|
|
|
|
Device.BeginInvokeOnMainThread(() =>
|
|
|
|
|
{
|
|
|
|
|
_clipboardTimer = NSTimer.CreateScheduledTimer(clearMsSpan, timer =>
|
|
|
|
|
{
|
|
|
|
|
Device.BeginInvokeOnMainThread(() =>
|
|
|
|
|
{
|
|
|
|
|
if(lastClipboardValue == UIPasteboard.General.String)
|
|
|
|
|
{
|
|
|
|
|
UIPasteboard.General.String = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
_clipboardTimer?.Invalidate();
|
|
|
|
|
_clipboardTimer?.Dispose();
|
|
|
|
|
_clipboardTimer = null;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 06:04:41 +03:00
|
|
|
|
private void ShowAppExtension()
|
|
|
|
|
{
|
|
|
|
|
var itemProvider = new NSItemProvider(new NSDictionary(), Core.Constants.UTTypeAppExtensionSetup);
|
2019-06-28 18:47:04 +03:00
|
|
|
|
var extensionItem = new NSExtensionItem
|
|
|
|
|
{
|
|
|
|
|
Attachments = new NSItemProvider[] { itemProvider }
|
|
|
|
|
};
|
2019-06-12 06:04:41 +03:00
|
|
|
|
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);
|
2019-06-12 05:20:59 +03:00
|
|
|
|
}
|
2019-03-28 03:12:44 +03:00
|
|
|
|
}
|
|
|
|
|
}
|