public async Task <IActionResult> Patch(string id, [FromBody] JsonPatchDocument <Credential> request) { try { Guid entityId = new Guid(id); var existingCredential = repository.GetOne(entityId); if (existingCredential == null) { ModelState.AddModelError("Credential", "Credential cannot be found or does not exist."); return(NotFound(ModelState)); } for (int i = 0; i < request.Operations.Count; i++) { //verify that credential name is not taken if (request.Operations[i].op.ToString().ToLower() == "replace" && request.Operations[i].path.ToString().ToLower() == "/name") { existingCredential.Name = request.Operations[i].value.ToString(); _credentialManager.CredentialNameAvailability(existingCredential); } //generate new password hash if (request.Operations[i].op.ToString().ToLower() == "replace" && request.Operations[i].path.ToString().ToLower() == "/passwordsecret") { var encryptionKey = _credentialManager.GetEncryptionKey(); if (!String.IsNullOrEmpty(request.Operations[i].value.ToString())) { //generate salt existingCredential.HashSalt = CredentialHasher.CreateSalt(32); //create 32 byte salt //generate hash existingCredential.PasswordHash = CredentialHasher.GenerateSaltedHash(request.Operations[i].value.ToString(), existingCredential.HashSalt); //encrypt the provided password existingCredential.PasswordSecret = CredentialsEncrypter.Encrypt(request.Operations[i].value.ToString(), encryptionKey); } request.Replace(e => e.HashSalt, existingCredential.HashSalt); request.Replace(e => e.PasswordHash, existingCredential.PasswordHash); request.Replace(e => e.PasswordSecret, existingCredential.PasswordSecret); } //verify start-end date range if (request.Operations[i].op.ToString().ToLower() == "replace" && request.Operations[i].path.ToString().ToLower() == "/startdate" | request.Operations[i].path.ToString().ToLower() == "/enddate") { if (request.Operations[i].path.ToString().ToLower() == "/startdate") { existingCredential.StartDate = Convert.ToDateTime(request.Operations[i].value.ToString()); } else { existingCredential.EndDate = Convert.ToDateTime(request.Operations[i].value.ToString()); } if (!_credentialManager.ValidateStartAndEndDates(existingCredential)) { ModelState.AddModelError("Credential", "Start and End Date are not valid. End Date must be after the Start Date"); return(BadRequest(ModelState)); } } } await _webhookPublisher.PublishAsync("Credentials.CredentialUpdated", existingCredential.Id.ToString(), existingCredential.Name).ConfigureAwait(false); return(await base.PatchEntity(id, request)); } catch (Exception ex) { return(ex.GetActionResult()); } }