mirror of
https://github.com/bitwarden/mobile
synced 2025-12-23 19:53:50 +00:00
[EC-835] Add kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly on Watch Keychain (#2250)
* EC-835 Added in the Watch app keychain accessible when passcode set this device only and when the passcode is set to signal the iPhone to trigger a sync on opening the watch app * EC-835 Embed LocalAuthentication framework into the watch app to fix no such module when importing it * EC-835 Changed approach to check if Watch has passcode enabled by using Keychain accessible kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly instead of LAContext * EC-835 Fix weird error saying unassigned local variable on the CI compiler. It seems it doesn't realize of the full condition
This commit is contained in:
committed by
GitHub
parent
4347c2f81d
commit
e72932cbaa
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
||||
using Bit.App.Services;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using WatchConnectivity;
|
||||
|
||||
@@ -11,12 +12,16 @@ namespace Bit.iOS.Core.Services
|
||||
{
|
||||
public class WatchDeviceService : BaseWatchDeviceService
|
||||
{
|
||||
const string ACTION_MESSAGE_KEY = "actionMessage";
|
||||
const string TRIGGER_SYNC_ACTION_KEY = "triggerSync";
|
||||
|
||||
public WatchDeviceService(ICipherService cipherService,
|
||||
IEnvironmentService environmentService,
|
||||
IStateService stateService,
|
||||
IVaultTimeoutService vaultTimeoutService)
|
||||
: base(cipherService, environmentService, stateService, vaultTimeoutService)
|
||||
{
|
||||
WCSessionManager.SharedManager.OnMessagedReceived += OnMessagedReceived;
|
||||
}
|
||||
|
||||
public override bool IsConnected => WCSessionManager.SharedManager.IsSessionActivated;
|
||||
@@ -44,5 +49,17 @@ namespace Bit.iOS.Core.Services
|
||||
{
|
||||
WCSessionManager.SharedManager.StartSession();
|
||||
}
|
||||
|
||||
private void OnMessagedReceived(WCSession session, Dictionary<string, object> data)
|
||||
{
|
||||
if (data != null
|
||||
&&
|
||||
data.TryGetValue(ACTION_MESSAGE_KEY, out var action)
|
||||
&&
|
||||
action as string == TRIGGER_SYNC_ACTION_KEY)
|
||||
{
|
||||
SyncDataToWatchAsync().FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Foundation;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -21,6 +22,25 @@ namespace Bit.iOS.Core.Utilities
|
||||
var NSKeys = dict.Keys.Select(x => keyConverter(x)).ToArray();
|
||||
return NSDictionary<KTo, VTo>.FromObjectsAndKeys(NSValues, NSKeys, NSKeys.Count());
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ToDictionary(this NSDictionary<NSString, NSObject> nsDict)
|
||||
{
|
||||
return nsDict.ToDictionary(v => v?.ToString() as object);
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ToDictionary(this NSDictionary<NSString, NSObject> nsDict, Func<NSObject, object> valueTransformer)
|
||||
{
|
||||
return nsDict.ToDictionary(k => k.ToString(), v => valueTransformer(v));
|
||||
}
|
||||
|
||||
public static Dictionary<KTo, VTo> ToDictionary<KFrom, VFrom, KTo, VTo>(this NSDictionary<KFrom, VFrom> nsDict, Func<KFrom, KTo> keyConverter, Func<VFrom, VTo> valueConverter)
|
||||
where KFrom : NSObject
|
||||
where VFrom : NSObject
|
||||
{
|
||||
var keys = nsDict.Keys.Select(k => keyConverter(k)).ToArray();
|
||||
var values = nsDict.Values.Select(v => valueConverter(v)).ToArray();
|
||||
return keys.Zip(values, (k, v) => new { Key = k, Value = v })
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Services;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Foundation;
|
||||
using Newtonsoft.Json;
|
||||
using ObjCRuntime;
|
||||
|
||||
namespace WatchConnectivity
|
||||
{
|
||||
@@ -15,19 +19,18 @@ namespace WatchConnectivity
|
||||
private static readonly WCSessionManager sharedManager = new WCSessionManager();
|
||||
private static WCSession session = WCSession.IsSupported ? WCSession.DefaultSession : null;
|
||||
|
||||
public static string Device = "Phone";
|
||||
|
||||
public event WCSessionReceiveDataHandler ApplicationContextUpdated;
|
||||
public event WCSessionReceiveDataHandler MessagedReceived;
|
||||
public delegate void WCSessionReceiveDataHandler(WCSession session, Dictionary<string, object> applicationContext);
|
||||
public event WCSessionReceiveDataHandler OnApplicationContextUpdated;
|
||||
public event WCSessionReceiveDataHandler OnMessagedReceived;
|
||||
public delegate void WCSessionReceiveDataHandler(WCSession session, Dictionary<string, object> data);
|
||||
|
||||
WCSessionUserInfoTransfer _transf;
|
||||
|
||||
private WCSession validSession
|
||||
{
|
||||
get
|
||||
{
|
||||
Console.WriteLine($"Paired status:{(session.Paired ? '✓' : '✗')}\n");
|
||||
Console.WriteLine($"Watch App Installed status:{(session.WatchAppInstalled ? '✓' : '✗')}\n");
|
||||
Debug.WriteLine($"Paired status:{(session.Paired ? '✓' : '✗')}\n");
|
||||
Debug.WriteLine($"Watch App Installed status:{(session.WatchAppInstalled ? '✓' : '✗')}\n");
|
||||
return (session.Paired && session.WatchAppInstalled) ? session : null;
|
||||
}
|
||||
}
|
||||
@@ -62,26 +65,15 @@ namespace WatchConnectivity
|
||||
{
|
||||
session.Delegate = this;
|
||||
session.ActivateSession();
|
||||
Console.WriteLine($"Started Watch Connectivity Session on {Device}");
|
||||
Debug.WriteLine($"Started Watch Connectivity Session");
|
||||
}
|
||||
}
|
||||
|
||||
public override void SessionReachabilityDidChange(WCSession session)
|
||||
{
|
||||
Console.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')} from {Device}");
|
||||
// handle session reachability change
|
||||
if (session.Reachable)
|
||||
{
|
||||
// great! continue on with Interactive Messaging
|
||||
}
|
||||
else
|
||||
{
|
||||
// 😥 prompt the user to unlock their iOS device
|
||||
}
|
||||
Debug.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')}");
|
||||
}
|
||||
|
||||
#region Application Context Methods
|
||||
|
||||
public void SendBackgroundHighPriorityMessage(Dictionary<string, object> applicationContext)
|
||||
{
|
||||
// Application context doesnt need the watch to be reachable, it will be received when opened
|
||||
@@ -90,27 +82,24 @@ namespace WatchConnectivity
|
||||
return;
|
||||
}
|
||||
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
|
||||
try
|
||||
{
|
||||
try
|
||||
var sendSuccessfully = validSession.UpdateApplicationContext(applicationContext.ToNSDictionary(), out var error);
|
||||
if (sendSuccessfully)
|
||||
{
|
||||
var sendSuccessfully = validSession.UpdateApplicationContext(applicationContext.ToNSDictionary(), out var error);
|
||||
if (sendSuccessfully)
|
||||
{
|
||||
Console.WriteLine($"Sent App Context from {Device} \nPayLoad: {applicationContext.ToNSDictionary().ToString()} \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error Updating Application Context: {error.LocalizedDescription}");
|
||||
}
|
||||
Debug.WriteLine($"Sent App Context \nPayLoad: {applicationContext.ToNSDictionary().ToString()} \n");
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Exception Updating Application Context: {ex.Message}");
|
||||
Debug.WriteLine($"Error Updating Application Context: {error.LocalizedDescription}");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
}
|
||||
}
|
||||
WCSessionUserInfoTransfer _transf;
|
||||
|
||||
public void SendBackgroundFifoHighPriorityMessage(Dictionary<string, object> message)
|
||||
{
|
||||
if(validSession is null || validSession.ActivationState != WCSessionActivationState.Activated)
|
||||
@@ -120,11 +109,10 @@ namespace WatchConnectivity
|
||||
|
||||
_transf?.Cancel();
|
||||
|
||||
Console.WriteLine("Started transferring user info");
|
||||
Debug.WriteLine("Started transferring user info");
|
||||
|
||||
_transf = session.TransferUserInfo(message.ToNSDictionary());
|
||||
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
@@ -133,53 +121,41 @@ namespace WatchConnectivity
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
Console.WriteLine("Finished transferring user info");
|
||||
Debug.WriteLine("Finished transferring user info");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error transferring user info " + ex);
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
}
|
||||
});
|
||||
|
||||
//session.SendMessage(dic,
|
||||
// (dd) =>
|
||||
// {
|
||||
// Console.WriteLine(dd?.ToString());
|
||||
// },
|
||||
// error =>
|
||||
// {
|
||||
// Console.WriteLine(error?.ToString());
|
||||
// }
|
||||
//);
|
||||
}
|
||||
|
||||
public override void DidReceiveApplicationContext(WCSession session, NSDictionary<NSString, NSObject> applicationContext)
|
||||
{
|
||||
Console.WriteLine($"Receiving Message on {Device}");
|
||||
if (ApplicationContextUpdated != null)
|
||||
Debug.WriteLine($"Receiving Message");
|
||||
if (OnApplicationContextUpdated != null)
|
||||
{
|
||||
var keys = applicationContext.Keys.Select(k => k.ToString()).ToArray();
|
||||
var values = applicationContext.Values.Select(v => JsonConvert.DeserializeObject(v.ToString())).ToArray();
|
||||
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
ApplicationContextUpdated(session, dictionary);
|
||||
OnApplicationContextUpdated(session, dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message)
|
||||
{
|
||||
Console.WriteLine($"Receiving Message on {Device}");
|
||||
Debug.WriteLine($"Receiving Message");
|
||||
|
||||
var keys = message.Keys.Select(k => k.ToString()).ToArray();
|
||||
var values = message.Values.Select(v => v?.ToString() as object).ToArray();
|
||||
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
MessagedReceived?.Invoke(session, dictionary);
|
||||
OnMessagedReceived?.Invoke(session, message.ToDictionary());
|
||||
}
|
||||
|
||||
#endregion
|
||||
public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message, WCSessionReplyHandler replyHandler)
|
||||
{
|
||||
Debug.WriteLine($"Receiving Message");
|
||||
|
||||
OnMessagedReceived?.Invoke(session, message.ToDictionary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user