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>();
        }
Exemple #2
0
        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();
        }
Exemple #3
0
        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);
        }
Exemple #5
0
        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);
        }