|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Globalization;
using System.Text;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.DataProtection;
public class DataProtectionAdvancedExtensionsTests
{
private const string SampleEncodedString = "AQI"; // = WebEncoders.Base64UrlEncode({ 0x01, 0x02 })
[Fact]
public void Protect_PayloadAsString_WithExplicitExpiration()
{
// Arrange
var plaintextAsBytes = Encoding.UTF8.GetBytes("this is plaintext");
var expiration = StringToDateTime("2015-01-01 00:00:00Z");
var mockDataProtector = new Mock<ITimeLimitedDataProtector>();
mockDataProtector.Setup(o => o.Protect(plaintextAsBytes, expiration)).Returns(new byte[] { 0x01, 0x02 });
// Act
string protectedPayload = mockDataProtector.Object.Protect("this is plaintext", expiration);
// Assert
Assert.Equal(SampleEncodedString, protectedPayload);
}
[Fact]
public void Protect_PayloadAsString_WithLifetimeAsTimeSpan()
{
// Arrange
var plaintextAsBytes = Encoding.UTF8.GetBytes("this is plaintext");
DateTimeOffset actualExpiration = default(DateTimeOffset);
var mockDataProtector = new Mock<ITimeLimitedDataProtector>();
mockDataProtector.Setup(o => o.Protect(plaintextAsBytes, It.IsAny<DateTimeOffset>()))
.Returns<byte[], DateTimeOffset>((_, exp) =>
{
actualExpiration = exp;
return new byte[] { 0x01, 0x02 };
});
// Act
DateTimeOffset lowerBound = DateTimeOffset.UtcNow.AddHours(48);
string protectedPayload = mockDataProtector.Object.Protect("this is plaintext", TimeSpan.FromHours(48));
DateTimeOffset upperBound = DateTimeOffset.UtcNow.AddHours(48);
// Assert
Assert.Equal(SampleEncodedString, protectedPayload);
Assert.InRange(actualExpiration, lowerBound, upperBound);
}
[Fact]
public void Protect_PayloadAsBytes_WithLifetimeAsTimeSpan()
{
// Arrange
DateTimeOffset actualExpiration = default(DateTimeOffset);
var mockDataProtector = new Mock<ITimeLimitedDataProtector>();
mockDataProtector.Setup(o => o.Protect(new byte[] { 0x11, 0x22, 0x33 }, It.IsAny<DateTimeOffset>()))
.Returns<byte[], DateTimeOffset>((_, exp) =>
{
actualExpiration = exp;
return new byte[] { 0x01, 0x02 };
});
// Act
DateTimeOffset lowerBound = DateTimeOffset.UtcNow.AddHours(48);
byte[] protectedPayload = mockDataProtector.Object.Protect(new byte[] { 0x11, 0x22, 0x33 }, TimeSpan.FromHours(48));
DateTimeOffset upperBound = DateTimeOffset.UtcNow.AddHours(48);
// Assert
Assert.Equal(new byte[] { 0x01, 0x02 }, protectedPayload);
Assert.InRange(actualExpiration, lowerBound, upperBound);
}
[Fact]
public void Unprotect_PayloadAsString()
{
// Arrange
var futureDate = DateTimeOffset.UtcNow.AddYears(1);
var controlExpiration = futureDate;
var mockDataProtector = new Mock<ITimeLimitedDataProtector>();
mockDataProtector.Setup(o => o.Unprotect(new byte[] { 0x01, 0x02 }, out controlExpiration)).Returns(Encoding.UTF8.GetBytes("this is plaintext"));
// Act
string unprotectedPayload = mockDataProtector.Object.Unprotect(SampleEncodedString, out var testExpiration);
// Assert
Assert.Equal("this is plaintext", unprotectedPayload);
Assert.Equal(futureDate, testExpiration);
}
private static DateTime StringToDateTime(string input)
{
return DateTimeOffset.ParseExact(input, "u", CultureInfo.InvariantCulture).UtcDateTime;
}
}
|