2

I have a curiously curious bug happening in my app.

I have this very simple helper method I use to store some cool data on the user device:

public static async Task TrySetAsync(string key, string value)
    {
        try
        {
            await SecureStorage.SetAsync(key, value);
        }
        catch (Exception ex)
        {
            await App.Current.MainPage.DisplayAlert(
                "Device incompatible",
                "Your device is not compatible with this app.",
                "Ok");
        }
    }

It works perfectly fine and never had a problem, but I decided to perform a compatibility check on the app start so the user knows immediately their device won't cut it. To do that, I decided to implement it in the OnAppearing() method of the initial login page. It looks like this:

protected override async void OnAppearing()
    {
        try
        {
            // Try to save data to a random container
            string tempKey = System.Guid.NewGuid().ToString();

            //  Should throw an exception if SecureStorage is not compatible
            await Xamarin.Essentials.SecureStorage
                .SetAsync(tempKey, string.Empty);

            // Remove the datum
            Xamarin.Essentials.SecureStorage
                .Remove(tempKey);
        }
        catch
        {
            await App.Current.MainPage.DisplayAlert(
                "Device incompatible", 
                "This device does not support secure storage required for the application.", 
                "Ok");

            App.Terminate();
        }


        base.OnAppearing();
    }

I removed the Entitlements from the project to test my little concoction, and yet, it passes through it without a problem. No exception gets thrown. But upon logging in, where the original TrySetAsync method is used (first code snippet), the expected exception is thrown (missing entitlement). The debugger enters the try block and leaves it without an issue.

In summary:

It appears, that the app does not require any entitlements when SecureStorage is referenced in the OnAppearing(), yet throws the expected exception in TrySetAsync(...) defined in the main App class.

Any advice?

P.S. Originally I used GetAsync with a random guid string in OnAppearing(), which I changed to SetAsync and Remove, thinking that maybe getting data does not require compatibility. In general I never had an issue like that with SecureStorage and it really seems like some internal bug to me.\

ANSWER

My bad for using string.Empty as a value. It appears that SecureStorage.SetAsync will ignore such value and not store it, which then results in no exception being thrown at all. Also, attempting to GetAsync a non-existent key from SecureStorage will also not result in a missing entitlement exception

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Jeff Nama
  • 61
  • 5
  • 1
    It is extremely unlikely (I'm tempted to say impossible) that the location of the code allows a non-existent entitlement to be used. Its much more likely that the symptom you have observed doesn't mean the entitlement worked. I have no idea how it could be that the exception is not thrown, but I would test more thoroughly. A thorough test is to store a value into securestorage, then read it back, into a different variable. Use debug writelines to find out whether all those lines of code get executed, and to find out whether the value returned from storage is correct. – ToolmakerSteve Aug 06 '21 at 20:01
  • 1
    Prediction: If you have a debug writeline after the first call to securestorage, that line will never be executed. Nor will any following lines in that try block. If this prediction is shown to be correct, then we investigate what that means. Also add a debug writeline as first line of `catch`. It won't surprise me if `DisplayAlert` fails when done inside `OnAppearing`. – ToolmakerSteve Aug 06 '21 at 20:05
  • 1
    Also, have you checked VS Output pane, to see if any warnings or error messages at the time this code executes? – ToolmakerSteve Aug 06 '21 at 20:09
  • Hi Steve, sorry for long response, I could only sit down to it today. Following your advice, I wrote a more throughout test and I found that there are two cases where the exception is not thrown: 1. value in SetAsync is string.Empty or null: app ignores the value and doesn't store it, no exception is thrown. 2. key referenced by GetAsync does not currently exist on device KeyChain: fetch returns null (as expected) and does not throw an exception. Other than these two cases, the code works as expected. I was simply unfortunate (and a bit dumb) to use string.Empty and not call both Get and Set – Jeff Nama Aug 12 '21 at 08:28
  • I'll edit my original question to contain the answer and will report this as an issue to their GitHub. Thanks for the help – Jeff Nama Aug 12 '21 at 08:29

1 Answers1

0

(OP answered the question themselves):

My bad for using string.Empty as a value. It appears that SecureStorage.SetAsync will ignore such value and not store it, which then results in no exception being thrown at all. Also, attempting to GetAsync a non-existent key from SecureStorage will also not result in a missing entitlement exception

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196