mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-26 12:16:07 +01:00
bootstrap ios
This commit is contained in:
parent
a8dfb8e2b9
commit
5d4cc007bb
@ -1,35 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
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.Services;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS
|
||||
{
|
||||
// The UIApplicationDelegate for the application. This class is responsible for launching the
|
||||
// User Interface of the application, as well as listening (and optionally responding) to
|
||||
// application events from iOS.
|
||||
[Register("AppDelegate")]
|
||||
public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
|
||||
{
|
||||
//
|
||||
// This method is invoked when the application has loaded and is ready to run. In this
|
||||
// method you should instantiate the window, load the UI into it and then make the window
|
||||
// visible.
|
||||
//
|
||||
// You have 17 seconds to return from this method, or iOS will terminate your application.
|
||||
//
|
||||
private const string AppId = "com.8bit.bitwarden";
|
||||
private const string AppGroupId = "group.com.8bit.bitwarden";
|
||||
private const string AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden";
|
||||
|
||||
private iOSPushNotificationHandler _pushHandler;
|
||||
|
||||
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
|
||||
{
|
||||
Xamarin.Forms.Forms.Init();
|
||||
|
||||
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
|
||||
InitApp();
|
||||
|
||||
LoadApplication(new App.App(null));
|
||||
|
||||
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
|
||||
return base.FinishedLaunching(app, options);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void InitApp()
|
||||
{
|
||||
if(ServiceContainer.RegisteredServices.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RegisterLocalServices();
|
||||
ServiceContainer.Init();
|
||||
_pushHandler = new iOSPushNotificationHandler(
|
||||
ServiceContainer.Resolve<IPushNotificationListenerService>("pushNotificationListenerService"));
|
||||
// TODO: HockeyApp Init
|
||||
}
|
||||
|
||||
private void RegisterLocalServices()
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
// Note: This might cause a race condition. Investigate more.
|
||||
Task.Run(() =>
|
||||
{
|
||||
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
|
||||
FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
|
||||
{
|
||||
FadeAnimationEnabled = false,
|
||||
FadeAnimationForCachedImages = false
|
||||
});
|
||||
});
|
||||
|
||||
var preferencesStorage = new PreferencesStorageService(AppGroupId);
|
||||
var appGroupContainer = new NSFileManager().GetContainerUrl(AppGroupId);
|
||||
var liteDbStorage = new LiteDbStorageService(
|
||||
Path.Combine(appGroupContainer.Path, "Library", "bitwarden.db"));
|
||||
liteDbStorage.InitAsync();
|
||||
var localizeService = new LocalizeService();
|
||||
var broadcasterService = new BroadcasterService();
|
||||
var messagingService = new MobileBroadcasterMessagingService(broadcasterService);
|
||||
var i18nService = new MobileI18nService(localizeService.GetCurrentCultureInfo());
|
||||
var secureStorageService = new KeyChainStorageService(AppId, AccessGroup);
|
||||
var cryptoPrimitiveService = new CryptoPrimitiveService();
|
||||
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
|
||||
var deviceActionService = new DeviceActionService(mobileStorageService, messagingService);
|
||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
|
||||
broadcasterService);
|
||||
|
||||
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);
|
||||
ServiceContainer.Register<IMessagingService>("messagingService", messagingService);
|
||||
ServiceContainer.Register<ILocalizeService>("localizeService", localizeService);
|
||||
ServiceContainer.Register<II18nService>("i18nService", i18nService);
|
||||
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", cryptoPrimitiveService);
|
||||
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
||||
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
||||
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
||||
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
||||
|
||||
// Push
|
||||
var notificationListenerService = new PushNotificationListenerService();
|
||||
ServiceContainer.Register<IPushNotificationListenerService>(
|
||||
"pushNotificationListenerService", notificationListenerService);
|
||||
var iosPushNotificationService = new iOSPushNotificationService();
|
||||
ServiceContainer.Register<IPushNotificationService>(
|
||||
"pushNotificationService", iosPushNotificationService);
|
||||
}
|
||||
|
||||
private void Bootstrap()
|
||||
{
|
||||
(ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService).Init();
|
||||
ServiceContainer.Resolve<IAuthService>("authService").Init();
|
||||
// Note: This is not awaited
|
||||
var bootstrapTask = BootstrapAsync();
|
||||
}
|
||||
|
||||
private async Task BootstrapAsync()
|
||||
{
|
||||
var disableFavicon = await ServiceContainer.Resolve<IStorageService>("storageService").GetAsync<bool?>(
|
||||
Constants.DisableFaviconKey);
|
||||
await ServiceContainer.Resolve<IStateService>("stateService").SaveAsync(Constants.DisableFaviconKey,
|
||||
disableFavicon);
|
||||
await ServiceContainer.Resolve<IEnvironmentService>("environmentService").SetUrlsFromStorageAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,9 @@ namespace Bit.iOS
|
||||
{
|
||||
public class Application
|
||||
{
|
||||
// This is the main entry point of the application.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ObjCRuntime.Dlfcn.dlopen(ObjCRuntime.Constants.libSystemLibrary, 0);
|
||||
|
||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
||||
// you can specify it here.
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
}
|
||||
}
|
||||
|
92
src/iOS/Migration/KeyChainStorageService.cs
Normal file
92
src/iOS/Migration/KeyChainStorageService.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Bit.App.Migration.Abstractions;
|
||||
using Foundation;
|
||||
using Security;
|
||||
|
||||
namespace Bit.iOS.Migration
|
||||
{
|
||||
public class KeyChainStorageService : IOldSecureStorageService
|
||||
{
|
||||
public void Store(string key, byte[] dataBytes)
|
||||
{
|
||||
using(var data = NSData.FromArray(dataBytes))
|
||||
using(var newRecord = GetKeyRecord(key, data))
|
||||
{
|
||||
Delete(key);
|
||||
CheckError(SecKeyChain.Add(newRecord));
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Retrieve(string key)
|
||||
{
|
||||
SecStatusCode resultCode;
|
||||
|
||||
using(var existingRecord = GetKeyRecord(key))
|
||||
using(var record = SecKeyChain.QueryAsRecord(existingRecord, out resultCode))
|
||||
{
|
||||
if(resultCode == SecStatusCode.ItemNotFound)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CheckError(resultCode);
|
||||
return record.Generic.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(string key)
|
||||
{
|
||||
using(var record = GetExistingRecord(key))
|
||||
{
|
||||
if(record != null)
|
||||
{
|
||||
CheckError(SecKeyChain.Remove(record));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string key)
|
||||
{
|
||||
using(var existingRecord = GetExistingRecord(key))
|
||||
{
|
||||
return existingRecord != null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckError(SecStatusCode resultCode, [CallerMemberName] string caller = null)
|
||||
{
|
||||
if(resultCode != SecStatusCode.Success)
|
||||
{
|
||||
throw new Exception(string.Format("Failed to execute {0}. Result code: {1}", caller, resultCode));
|
||||
}
|
||||
}
|
||||
|
||||
private static SecRecord GetKeyRecord(string key, NSData data = null)
|
||||
{
|
||||
var record = new SecRecord(SecKind.GenericPassword)
|
||||
{
|
||||
Service = "com.8bit.bitwarden",
|
||||
Account = key,
|
||||
AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden"
|
||||
};
|
||||
|
||||
if(data != null)
|
||||
{
|
||||
record.Generic = data;
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
private static SecRecord GetExistingRecord(string key)
|
||||
{
|
||||
var existingRecord = GetKeyRecord(key);
|
||||
|
||||
SecStatusCode resultCode;
|
||||
SecKeyChain.QueryAsRecord(existingRecord, out resultCode);
|
||||
|
||||
return resultCode == SecStatusCode.Success ? existingRecord : null;
|
||||
}
|
||||
}
|
||||
}
|
@ -110,6 +110,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AppDelegate.cs" />
|
||||
<Compile Include="Migration\KeyChainStorageService.cs" />
|
||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
||||
<Compile Include="Services\DeviceActionService.cs" />
|
||||
<Compile Include="Services\iOSPushNotificationHandler.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user