Files
baya-monorepo/server/src/Tests/Baya.Test.Foundation/SymmetricFieldEncryptorTests.cs
T
hamid 765cc632d5 backend phase 0: foundation, cross-cutting seams & starter cleanup
Remove the Order demo (entity/feature/repo/config/gRPC/proto) and the three
pre-marketplace migrations; regenerate a fresh InitialBaseline migration.

Stand up the REST surface (PingController + System/Ping CQRS) proving the
Mediator -> behaviors -> OperationResult -> ApiResult envelope end to end.

Close wiring gaps: register LoggingBehavior (outermost) and add the built-in
rate limiter (per-IP global + otp/auth/sensitive policies), placed before
authentication.

Add current-user + audit plumbing: ICurrentUser (HttpContext + null impls),
rename BaseEntity audit fields to CreatedAt/ModifiedAt (DateTimeOffset) +
CreatedById/ModifiedById, stamped by a new AuditFieldInterceptor.

Introduce five cross-cutting seams (IDateTimeProvider, IFieldEncryptor,
ICacheService, IObjectStorage, INotificationDispatcher) with in-memory/local
mocks registered via AddCrossCuttingSeams.

Add Baya.Test.Foundation (encryptor, audit interceptor, ping handler) and
update docs, contracts (swagger.v1.json), handoff, report, and mocks registry.
2026-06-30 22:48:41 +03:30

71 lines
1.9 KiB
C#

using Baya.Infrastructure.CrossCutting.Seams;
using Microsoft.Extensions.Options;
namespace Baya.Test.Foundation;
public class SymmetricFieldEncryptorTests
{
private static SymmetricFieldEncryptor CreateEncryptor()
{
var options = Options.Create(new SeamOptions
{
FieldEncryption = new FieldEncryptionOptions
{
Key = "unit-test-field-encryption-key",
HashKey = "unit-test-hash-key"
}
});
return new SymmetricFieldEncryptor(options);
}
[Fact]
public void Decrypt_OfEncrypt_ReturnsOriginalPlaintext()
{
// Arrange
var encryptor = CreateEncryptor();
const string plaintext = "09123456789";
// Act
var cipher = encryptor.Encrypt(plaintext);
var roundTripped = encryptor.Decrypt(cipher);
// Assert
Assert.NotEqual(plaintext, cipher);
Assert.Equal(plaintext, roundTripped);
}
[Fact]
public void Encrypt_SameInputTwice_ProducesDifferentCiphertext()
{
// Arrange — a random IV per call means ciphertext is not deterministic (semantic security).
var encryptor = CreateEncryptor();
const string plaintext = "IR820540102680020817909002";
// Act
var first = encryptor.Encrypt(plaintext);
var second = encryptor.Encrypt(plaintext);
// Assert
Assert.NotEqual(first, second);
Assert.Equal(plaintext, encryptor.Decrypt(first));
Assert.Equal(plaintext, encryptor.Decrypt(second));
}
[Fact]
public void Hash_IsDeterministic_ForLookups()
{
// Arrange
var encryptor = CreateEncryptor();
const string value = "IR820540102680020817909002";
// Act
var first = encryptor.Hash(value);
var second = encryptor.Hash(value);
// Assert
Assert.Equal(first, second);
Assert.NotEqual(value, first);
}
}