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))); }
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)); }
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)); }