public async Task Should_Get_Object_Signal_By_Name_And_Tag() { // Arrange var value = new TestObject { Value = Value }; await _context.Signals.AddAsync(new Signal { Id = 2, ResourceId = Guid.NewGuid(), Name = $"{Name}_object", Value = JsonConvert.SerializeObject(value), ValueType = value.GetSignalValueType(), IsBaseType = value.IsBaseType(), Tags = Tags, DateCreated = DateTime.Now, DateLastUpdated = DateTime.Now }).ConfigureAwait(false); await _context.SaveChangesAsync().ConfigureAwait(false); var request = new GetSignalByNameAndTagRequest { Name = $"{Name}_object", Tag = "Test" }; // Act var result = await _sut.Handle(request, CancellationToken.None).ConfigureAwait(false); // Assert result.ShouldNotBeNull(); result.Value.ShouldBeOfType <TestObject>(); }
public async Task Should_Update_Signal_With_New_Unencrypted_Base_Object() { // Arrange var id = Guid.NewGuid(); const string newValue = "New Test Value"; await _context.Signals.AddAsync(new Signal { Id = 1, DateCreated = DateTime.UtcNow, DateLastUpdated = DateTime.UtcNow, IsBaseType = true, Name = "Test", ResourceId = id, Value = "Test Value", ValueType = typeof(string).FullName }).ConfigureAwait(false); await _context.SaveChangesAsync().ConfigureAwait(false); var request = new PatchSignalRequest { Id = id, Patch = new JsonPatchDocument <SignalWriteModel>() .Replace(x => x.Tags, new List <string> { "Tag1", "Tag2" }) .Replace(x => x.Value, newValue) }; // Act await _sut.Execute(request, CancellationToken.None).ConfigureAwait(false); // Assert var signal = await _context.Signals.FirstOrDefaultAsync(s => s.ResourceId == id).ConfigureAwait(false); signal.Value.ShouldBe(newValue); signal.Tags.ShouldNotBeNull(); }
public async Task <byte[]> Handle(GenerateKeysRequest request, CancellationToken cancellationToken) { var rsaKeyPairGenerator = new RsaKeyPairGenerator(); var randomGenerator = new CryptoApiRandomGenerator(); rsaKeyPairGenerator.Init(new KeyGenerationParameters(new SecureRandom(randomGenerator), request.KeySize)); var keys = rsaKeyPairGenerator.GenerateKeyPair(); var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keys.Private); var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keys.Public); var publicKey = publicKeyInfo.ToAsn1Object().GetDerEncoded(); var publicKeyValue = Convert.ToBase64String(publicKey); await UpdateSetting(PublicKeySettingName, publicKeyValue, cancellationToken).ConfigureAwait(false); await _context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); return(privateKeyInfo.ToAsn1Object().GetDerEncoded()); }
public async Task <Guid> Handle(CreateFeatureFlagRequest request, CancellationToken cancellationToken) { var feature = new Feature { ResourceId = RT.Comb.Provider.PostgreSql.Create(), Name = request.Name, Signals = new List <Signal> { new Signal { Value = request.Setting.ToString(), Tags = string.Join(",", request.Tags) } } }; await _context.Features.AddAsync(feature, cancellationToken).ConfigureAwait(false); await _context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); return(feature.ResourceId); }
public async Task <string> Handle(RollKeysRequest request, CancellationToken cancellationToken) { // Get all encrypted signals var encryptedSignals = await _context.Signals.Where(signal => signal.Tags.Contains(Constants.EncryptedTag)) .ToArrayAsync(cancellationToken) .ConfigureAwait(false); // Decrypt the signals foreach (var signal in encryptedSignals) { signal.Value = await _mediator.Send(new DecryptionRequest { PrivateKey = request.PrivateKey, ToDecrypt = signal.Value }, cancellationToken).ConfigureAwait(false); } // Generate New Keys var privateKey = await _mediator.Send(new GenerateKeysRequest(), cancellationToken).ConfigureAwait(false); var publicKey = await _mediator.Send(new GetSettingRequest { Name = GenerateKeysRequestHandler.PublicKeySettingName }, cancellationToken).ConfigureAwait(false); // Re-encrypt the signals foreach (var signal in encryptedSignals) { signal.Value = await _mediator.Send(new EncryptionRequest { PublicKey = Convert.FromBase64String(publicKey), ToEncrypt = signal.Value }, cancellationToken).ConfigureAwait(false); } await _context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); return(Convert.ToBase64String(privateKey)); }
public async Task <Guid> Handle(CreateSignalRequest request, CancellationToken cancellationToken) { var tags = request.Tags.ToList(); var isBaseType = request.Value.IsBaseType(); var valueType = request.Value.GetSignalValueType(); var value = isBaseType ? request.Value.ToString() : JsonConvert.SerializeObject(request.Value); if (request.Encrypted) { var publicKey = await _mediator.Send(new GetSettingRequest { Name = GenerateKeysRequestHandler.PublicKeySettingName }, cancellationToken).ConfigureAwait(false); value = await _mediator.Send(new EncryptionRequest { PublicKey = Convert.FromBase64String(publicKey), ToEncrypt = value }, cancellationToken).ConfigureAwait(false); if (!tags.Contains(Constants.EncryptedTag)) { tags.Add(Constants.EncryptedTag); } } var joinedTags = string.Join(",", tags); // We check here to make sure we're not creating a duplicate var duplicate = tags.Any() ? await _mediator.Send(new GetSignalByNameAndTagRequest { Name = request.Name, Tag = joinedTags }, cancellationToken).ConfigureAwait(false) : await _mediator.Send(new GetSignalByNameRequest { Name = request.Name }, cancellationToken).ConfigureAwait(false); if (duplicate != null) { throw new InvalidOperationException(SignalAlreadyExistsErrorMessage); } var signal = new Signal { ResourceId = RT.Comb.Provider.PostgreSql.Create(), Name = request.Name, Tags = joinedTags, Value = value, ValueType = valueType, IsBaseType = isBaseType }; await _context.Signals.AddAsync(signal, cancellationToken).ConfigureAwait(false); await _context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); return(signal.ResourceId.Value); }
internal async Task Execute(PatchSignalRequest request, CancellationToken cancellationToken) { var domainModel = await _semaphoreContext.Signals.FirstOrDefaultAsync(signal => signal.ResourceId == request.Id, cancellationToken).ConfigureAwait(false); if (domainModel == null) { throw new InvalidOperationException(string.Format(SignalNotFoundMessage, request.Id)); } var wasEncrypted = domainModel.IsEncrypted(); if (wasEncrypted && !request.PrivateKey.IsNullOrBlank()) { domainModel.Value = await _mediator.Send(new DecryptionRequest { PrivateKey = request.PrivateKey, ToDecrypt = domainModel.Value }, cancellationToken).ConfigureAwait(false); } // Because the request needs to be the abstracted SignalWriteModel we have to perform some necessary steps // 1) Map the domain model to a write model // 2) Use the Microsoft JSON Patch framework to apply the changes requested // 3) Populate the domain model with the given changes // 4) If requested, encrypt the value // 5) Save changes // 1) var writeModel = domainModel.ToWriteModel(); // 2) request.Patch.ApplyTo(writeModel); if ((writeModel.Tags.IsNullOrEmpty() || !writeModel.Tags.Contains(Constants.EncryptedTag)) && (wasEncrypted || writeModel.Encrypted)) { writeModel.Tags = (writeModel.Tags ?? Enumerable.Empty <string>()).Union(new[] { Constants.EncryptedTag }).ToList(); } // 3) domainModel.PopulateFromWriteModel(writeModel); // 4) if (request.Patch.Operations.Any(operation => CultureInfo.CurrentCulture.CompareInfo.IndexOf(operation.path, nameof(SignalWriteModel.Value), CompareOptions.OrdinalIgnoreCase) >= 0 || CultureInfo.CurrentCulture.CompareInfo.IndexOf(operation.path, nameof(SignalWriteModel.Tags), CompareOptions.OrdinalIgnoreCase) >= 0)) { if (writeModel.Encrypted || (writeModel.Tags ?? new List <string>()).Contains(Constants.EncryptedTag)) { var publicKey = await _mediator.Send(new GetSettingRequest { Name = GenerateKeysRequestHandler.PublicKeySettingName }, cancellationToken).ConfigureAwait(false); domainModel.Value = await _mediator.Send(new EncryptionRequest { PublicKey = Convert.FromBase64String(publicKey), ToEncrypt = domainModel.Value }, cancellationToken).ConfigureAwait(false); } } // 5) await _semaphoreContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); }