public void SetAsync_ProtectsAndInvokesJS_NullValue()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);
            var jsResultTask            = Task.FromResult((object)null);
            var expectedPurpose         = $"{typeof(TestProtectedBrowserStorage).FullName}:test store:test key";

            // Act
            jsRuntime.NextInvocationResult = jsResultTask;
            var result = protectedBrowserStorage.SetAsync("test key", null);

            // Assert
            Assert.Same(jsResultTask, result);
            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("protectedBrowserStorage.set", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal("test store", arg),
                              arg => Assert.Equal("test key", arg),
                              arg => Assert.Equal(
                                  "null",
                                  TestDataProtectionProvider.Unprotect(expectedPurpose, (string)arg)));
        }
        public async Task ReusesCachedProtectorsByPurpose()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();

            jsRuntime.NextInvocationResult = Task.FromResult((object)null);
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);

            // Act
            await protectedBrowserStorage.SetAsync("key 1", null);

            await protectedBrowserStorage.SetAsync("key 2", null);

            await protectedBrowserStorage.SetAsync("key 1", null);

            await protectedBrowserStorage.SetAsync("key 3", null);

            // Assert
            var typeName         = typeof(TestProtectedBrowserStorage).FullName;
            var expectedPurposes = new[]
            {
                $"{typeName}:test store:key 1",
                $"{typeName}:test store:key 2",
                $"{typeName}:test store:key 3"
            };

            Assert.Equal(expectedPurposes, dataProtectionProvider.ProtectorsCreated.ToArray());

            Assert.Collection(jsRuntime.Invocations,
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[0], "null"), invocation.Args[2]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[1], "null"), invocation.Args[2]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[0], "null"), invocation.Args[2]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[2], "null"), invocation.Args[2]));
        }
        public void SetAsync_ProtectsAndInvokesJS(string customPurpose)
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);
            var jsResultTask            = Task.FromResult((object)null);
            var data = new TestModel {
                StringProperty = "Hello", IntProperty = 123
            };
            var keyName         = "test key";
            var expectedPurpose = customPurpose == null
                ? $"{typeof(TestProtectedBrowserStorage).FullName}:test store:{keyName}"
                : customPurpose;

            // Act
            jsRuntime.NextInvocationResult = jsResultTask;
            var result = customPurpose == null
                ? protectedBrowserStorage.SetAsync(keyName, data)
                : protectedBrowserStorage.SetAsync(customPurpose, keyName, data);

            // Assert
            Assert.Same(jsResultTask, result);
            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("protectedBrowserStorage.set", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal("test store", arg),
                              arg => Assert.Equal(keyName, arg),
                              arg => Assert.Equal(
                                  "{\"StringProperty\":\"Hello\",\"IntProperty\":123}",
                                  TestDataProtectionProvider.Unprotect(expectedPurpose, (string)arg)));
        }
    public async Task GetAsync_InvokesJSAndUnprotects_ValidData_DefaultPurpose()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var data = new TestModel { StringProperty = "Hello", IntProperty = 123 };
        var keyName = "testKey";
        var expectedPurpose = $"{typeof(TestProtectedBrowserStorage).FullName}:testStore:{keyName}";
        var storedJson = "{\"StringProperty\":\"Hello\",\"IntProperty\":123}";
        jsRuntime.NextInvocationResult = new ValueTask<string>(
            TestDataProtectionProvider.Protect(expectedPurpose, storedJson));

        // Act
        var result = await protectedBrowserStorage.GetAsync<TestModel>(keyName);

        // Assert
        Assert.True(result.Success);
        Assert.Equal("Hello", result.Value.StringProperty);
        Assert.Equal(123, result.Value.IntProperty);

        var invocation = jsRuntime.Invocations.Single();
        Assert.Equal("testStore.getItem", invocation.Identifier);
        Assert.Collection(invocation.Args, arg => Assert.Equal(keyName, arg));
    }
        public async Task GetAsync_InvokesJSAndUnprotects_ValidData(string customPurpose)
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);
            var data = new TestModel {
                StringProperty = "Hello", IntProperty = 123
            };
            var keyName         = "test key";
            var expectedPurpose = customPurpose == null
                ? $"{typeof(TestProtectedBrowserStorage).FullName}:test store:{keyName}"
                : customPurpose;
            var storedJson = "{\"StringProperty\":\"Hello\",\"IntProperty\":123}";

            jsRuntime.NextInvocationResult = Task.FromResult(
                TestDataProtectionProvider.Protect(expectedPurpose, storedJson));

            // Act
            var result = customPurpose == null
                ? await protectedBrowserStorage.GetAsync <TestModel>(keyName)
                : await protectedBrowserStorage.GetAsync <TestModel>(customPurpose, keyName);

            // Assert
            Assert.Equal("Hello", result.StringProperty);
            Assert.Equal(123, result.IntProperty);

            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("protectedBrowserStorage.get", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal("test store", arg),
                              arg => Assert.Equal(keyName, arg));
        }
        public void SetAsync_ProtectsAndInvokesJS_CustomPurpose()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
            var jsResultTask            = new ValueTask <object>((object)null);
            var data = new TestModel {
                StringProperty = "Hello", IntProperty = 123
            };
            var keyName       = "testKey";
            var customPurpose = "my custom purpose";

            // Act
            jsRuntime.NextInvocationResult = jsResultTask;
            var result = protectedBrowserStorage.SetAsync(customPurpose, keyName, data);

            // Assert
            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("testStore.setItem", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal(keyName, arg),
                              arg => Assert.Equal(
                                  "{\"stringProperty\":\"Hello\",\"intProperty\":123}",
                                  TestDataProtectionProvider.Unprotect(customPurpose, (string)arg)));
        }
Exemple #7
0
    public async Task GetAsync_InvokesJSAndUnprotects_InvalidProtection_Plaintext()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider  = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var storedString            = "This string is not even protected";

        jsRuntime.NextInvocationResult = new ValueTask <string>(storedString);

        // Act/Assert
        var ex = await Assert.ThrowsAsync <CryptographicException>(
            async() => await protectedBrowserStorage.GetAsync <TestModel>("testKey"));
    }
        public async Task GetAsync_InvokesJSAndUnprotects_NoValue()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);

            jsRuntime.NextInvocationResult = Task.FromResult((string)null);

            // Act
            var result = await protectedBrowserStorage.GetAsync <TestModel>("test key");

            // Assert
            Assert.Null(result);
        }
    public async Task GetAsync_InvokesJSAndUnprotects_InvalidJson()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var expectedPurpose = $"{typeof(TestProtectedBrowserStorage).FullName}:testStore:testKey";
        var storedJson = "you can't parse this";
        jsRuntime.NextInvocationResult = new ValueTask<string>(
            TestDataProtectionProvider.Protect(expectedPurpose, storedJson));

        // Act/Assert
        var ex = await Assert.ThrowsAsync<JsonException>(
            async () => await protectedBrowserStorage.GetAsync<TestModel>("testKey"));
    }
    public async Task GetAsync_InvokesJSAndUnprotects_NoValue()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        jsRuntime.NextInvocationResult = new ValueTask<string>((string)null);

        // Act
        var result = await protectedBrowserStorage.GetAsync<TestModel>("testKey");

        // Assert
        Assert.False(result.Success);
        Assert.Null(result.Value);
    }
    public void DeleteAsync_InvokesJS()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var nextTask = new ValueTask<object>((object)null);
        jsRuntime.NextInvocationResult = nextTask;

        // Act
        var result = protectedBrowserStorage.DeleteAsync("testKey");

        // Assert
        var invocation = jsRuntime.Invocations.Single();
        Assert.Equal("testStore.removeItem", invocation.Identifier);
        Assert.Collection(invocation.Args, arg => Assert.Equal("testKey", arg));
    }
Exemple #12
0
    public async Task GetAsync_InvokesJSAndUnprotects_InvalidProtection_Base64Encoded()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider  = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);

        // DataProtection deals with strings by base64-encoding the results.
        // Depending on whether the stored data is base64-encoded or not,
        // it will trigger a different failure point in data protection.
        var storedString = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes("This string is not even protected"));

        jsRuntime.NextInvocationResult = new ValueTask <string>(storedString);

        // Act/Assert
        var ex = await Assert.ThrowsAsync <CryptographicException>(
            async() => await protectedBrowserStorage.GetAsync <TestModel>("testKey"));
    }
    public async Task GetValueOrDefaultAsync_InvokesJSAndUnprotects_WrongPurpose()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var expectedPurpose = $"{typeof(TestProtectedBrowserStorage).FullName}:testStore:testKey";
        var storedJson = "we won't even try to parse this";
        jsRuntime.NextInvocationResult = new ValueTask<string>(
            TestDataProtectionProvider.Protect(expectedPurpose, storedJson));

        // Act/Assert
        var ex = await Assert.ThrowsAsync<CryptographicException>(
            async () => await protectedBrowserStorage.GetAsync<TestModel>("different key"));
        var innerException = ex.InnerException;
        Assert.IsType<ArgumentException>(innerException);
        Assert.Contains("The value is not protected with the expected purpose", innerException.Message);
    }
        public void DeleteAsync_InvokesJS()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);
            var nextTask = Task.FromResult((object)null);

            jsRuntime.NextInvocationResult = nextTask;

            // Act
            var result = protectedBrowserStorage.DeleteAsync("test key");

            // Assert
            Assert.Same(nextTask, result);
            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("protectedBrowserStorage.delete", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal("test store", arg),
                              arg => Assert.Equal("test key", arg));
        }