diff --git a/DeviceTests/DeviceTests.Shared/SecureStorage_Tests.cs b/DeviceTests/DeviceTests.Shared/SecureStorage_Tests.cs index 8ed7d618b..375e7d6fd 100644 --- a/DeviceTests/DeviceTests.Shared/SecureStorage_Tests.cs +++ b/DeviceTests/DeviceTests.Shared/SecureStorage_Tests.cs @@ -23,6 +23,13 @@ public async Task Saves_And_Loads(string key, string data, bool emulatePreApi23) // TODO: we don't know how to write iOS apps, it appears, so just skip for now if (DeviceInfo.DeviceType == DeviceType.Virtual) return; + + // Try the new platform specific api + await SecureStorage.SetAsync(key, data, Security.SecAccessible.AfterFirstUnlock); + + var b = await SecureStorage.GetAsync(key, Security.SecAccessible.AfterFirstUnlock); + + Assert.Equal(data, b); #endif #if __ANDROID__ diff --git a/Xamarin.Essentials/SecureStorage/SecureStorage.ios.cs b/Xamarin.Essentials/SecureStorage/SecureStorage.ios.cs index 62f04a995..ab8c259fb 100644 --- a/Xamarin.Essentials/SecureStorage/SecureStorage.ios.cs +++ b/Xamarin.Essentials/SecureStorage/SecureStorage.ios.cs @@ -8,39 +8,62 @@ namespace Xamarin.Essentials { public static partial class SecureStorage { - static Task PlatformGetAsync(string key) + public static SecAccessible DefaultAccessible { get; set; } = + SecAccessible.AfterFirstUnlock; + + public static Task GetAsync(string key, SecAccessible accessible) { - var kc = new KeyChain(); + if (string.IsNullOrWhiteSpace(key)) + throw new ArgumentNullException(nameof(key)); + + var kc = new KeyChain(accessible); return Task.FromResult(kc.ValueForKey(key, Alias)); } - static Task PlatformSetAsync(string key, string data) + public static Task SetAsync(string key, string value, SecAccessible accessible) { - var kc = new KeyChain(); - kc.SetValueForKey(data, key, Alias); + if (string.IsNullOrWhiteSpace(key)) + throw new ArgumentNullException(nameof(key)); + + if (value == null) + throw new ArgumentNullException(nameof(value)); + + var kc = new KeyChain(accessible); + kc.SetValueForKey(value, key, Alias); return Task.CompletedTask; } + + static Task PlatformGetAsync(string key) => + GetAsync(key, DefaultAccessible); + + static Task PlatformSetAsync(string key, string data) => + SetAsync(key, data, DefaultAccessible); } class KeyChain { - static SecRecord ExistingRecordForKey(string key, string service) + SecAccessible accessible; + + internal KeyChain(SecAccessible accessible) => + this.accessible = accessible; + + SecRecord ExistingRecordForKey(string key, string service) { return new SecRecord(SecKind.GenericPassword) { Account = key, Service = service, Label = key, + Accessible = accessible }; } internal string ValueForKey(string key, string service) { var record = ExistingRecordForKey(key, service); - SecStatusCode resultCode; - var match = SecKeyChain.QueryAsRecord(record, out resultCode); + var match = SecKeyChain.QueryAsRecord(record, out var resultCode); if (resultCode == SecStatusCode.Success) return NSString.FromData(match.ValueData, NSStringEncoding.UTF8); @@ -75,6 +98,7 @@ SecRecord CreateRecordForNewKeyValue(string key, string value, string service) Account = key, Service = service, Label = key, + Accessible = accessible, ValueData = NSData.FromString(value, NSStringEncoding.UTF8), }; }