/// <summary>
 /// Creates a secret if it does not exist, updates if it does.  Returns a Secret object read from the Vault. It will return NULL if secret was not created successfully.
 /// This is the equivalent of calling CreateOrUpdateSecretAndReturn along with ReadSecret.
 /// </summary>
 /// <param name="secret">Secret object that contains the secret path to be created.</param>
 /// <returns>Secret object populated with the Secret info as read from the Vault.</returns>
 public async Task <KeyValueSecret> CreateOrUpdateSecret(KeyValueSecret secret)
 {
     if (await CreateOrUpdateSecretAndReturn(secret))
     {
         return(await ReadSecret(secret.Path));
     }
     else
     {
         return(null);
     }
 }
 /// <summary>
 /// Deletes the Vault secret at the path specified.  Returns True AND sets the vault path to nothing and deletes the Secret's attributes, if successful.
 /// Returns False and does not delete the Secret object if it failed to delete for some reason.
 /// </summary>
 /// <param name="secret">True for success.  False otherwise.</param>
 /// <returns></returns>
 public async Task <bool> DeleteSecret(KeyValueSecret secret)
 {
     if ((await DeleteSecret(secret.Path)))
     {
         secret.Path = "";
         secret.Attributes.Clear();
         return(true);
     }
     else
     {
         return(false);
     }
 }
        /// <summary>
        /// Creates the given Secret, ONLY if there is not already a secret by this path already.  Returns NULL if secret already exists.  Returns Secret object otherwise.
        /// </summary>
        /// <param name="secret">Secret object to create in Vault.</param>
        /// <returns>new KeyValueSecret object if it was created in Vault, NULL if it already exists.</returns>
        public async Task <KeyValueSecret> CreateSecret(KeyValueSecret secret)
        {
            // Ensure secret does not exist currently.
            KeyValueSecret exists = await ReadSecret(secret.Path);

            if (exists != null)
            {
                return(null);
            }

            // Create it.
            return(await CreateOrUpdateSecret(secret));
        }
        /// <summary>
        /// Determines whether a given secret exists or not.
        /// </summary>
        /// <param name="secretPath">The name of the secret to determine if it exists.</param>
        /// <returns>True if the secret exists.  False if it was not found.</returns>
        public async Task <bool> IfExists(string secretPath)
        {
            KeyValueSecret exists = await ReadSecret(secretPath);

            if (exists != null)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Creates a secret if it does not exist, updates if it does.  Returns true if successful, false otherwise.
        /// </summary>
        /// <param name="secret">The Secret object with at least the secret path populated.</param>
        /// <returns>True if successful in creating the secret in Vault, false otherwise.</returns>
        public async Task <bool> CreateOrUpdateSecretAndReturn(KeyValueSecret secret)
        {
            string path = MountPointPath + secret.Path;

            // Set TTL to 4 hour if not specified explicitly
            if (secret.RefreshInterval == 0)
            {
                secret.RefreshInterval = (4 * 3600);
            }


            // Build the content parameters, which will contain the TTL and the key value attributes.
            Dictionary <string, string> contentParams = new Dictionary <string, string>();

            contentParams.Add("ttl", secret.RefreshInterval.ToString());
            //string contentParamsJSON = VaultSerializationHelper.ToJson(contentParams);
            string contentParamsJSON = JsonConvert.SerializeObject(contentParams, Formatting.None);


            // Build entire JSON Body:  Input Params + Bulk Items List.
            string attrJSON;

            if (secret.Attributes.Count > 0)
            {
                //attrJSON = VaultSerializationHelper.ToJson(secret.Attributes);
                attrJSON = JsonConvert.SerializeObject(secret.Attributes, Formatting.None);

                // Combine the 2 JSON's
                string newVarsJSON = contentParamsJSON.Substring(1, contentParamsJSON.Length - 2) + ",";
                attrJSON = attrJSON.Insert(1, newVarsJSON);
            }
            else
            {
                attrJSON = contentParamsJSON;
            }

            VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PostAsync_B(path, "CreateOrUpdateSecret", attrJSON);

            return(vdro.Success);
        }
        /// <summary>
        /// Reads the secret that matches the secretPath passed in and returns a Secret object.  Returns NULL if the secret was not found.
        /// </summary>
        /// <param name="secretPath">The full path to the secret.  Also known as the secret's full name.</param>
        /// <returns>Secret object populated with the secret's attributes if successful.  Null if not successful.</returns>
        public async Task <KeyValueSecret> ReadSecret(string secretPath)
        {
            string path = MountPointPath + secretPath;

            try {
                VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "ReadSecret");

                if (vdro.Success)
                {
                    KeyValueSecret secret = await vdro.GetDotNetObject <KeyValueSecret>("");

                    //KeyValueSecret secret = vdro.GetVaultTypedObjectFromResponse<KeyValueSecret>();

                    // Vault does not populate the path variable.  We need to set.
                    secret.Path = secretPath;
                    return(secret);
                }

                throw new ApplicationException("SecretBackEnd: ReadSecret - Arrived at an unexpected code path.");
            }
            catch (VaultInvalidPathException) { return(null); }
        }
        /// <summary>
        /// Creates a secret if it does not exist, updates if it does.  Returns a Secret object read from the Vault. It will return NULL if secret was not created successfully.
        /// This is the equivalent of calling CreateOrUpdateSecretAndReturn along with ReadSecret.
        /// </summary>
        /// <param name="secretPath">The name or full path of the secret.</param>
        /// <returns>Secret object if successful.  Null otherwise</returns>
        public async Task <KeyValueSecret> CreateOrUpdateSecret(string secretPath)
        {
            KeyValueSecret secret = new KeyValueSecret(secretPath);

            return(await CreateOrUpdateSecret(secret));
        }
        /// <summary>
        /// Updates an already existing secret OR will create it.  Just another name for CreateOrUpdateSecret.
        /// </summary>
        /// <param name="secret">Secret that should be updated.</param>
        /// <returns>Secret Object with the updated values.</returns>
        public async Task <KeyValueSecret> UpdateSecret(KeyValueSecret secret)
        {
            return(await CreateOrUpdateSecret(secret));

            throw new NotImplementedException();
        }
 /// <summary>
 /// List all the secrets immediately in the secret path provided.  Note:  This does not list the secret attributes only the secrets themselves.
 /// Because of the way Vault identifies secrets and secrets with sub items (folders), a secret that contains a sub item will be listed 2x in the output.
 /// Once with just the secret name and once with the folder identifier.  so:  (sublevel and sublevel/).
 /// </summary>
 /// <param name="secret">Secret that you wish to use as parent to list secrets from.  Only lists immediate children of this secret.</param>
 /// <returns>List of strings of the secret names.</returns>
 public async Task <List <string> > ListSecrets(KeyValueSecret secret)
 {
     return(await ListSecrets(secret.Path));
 }
 /// <summary>
 /// Determines if a secret exists in the Vault Backend.  True if it exists, False otherwise.  Note: If you are checking for existince prior to reading the secret, then it
 /// is better to just call ReadSecret and check for a null return value to see if it exists or not.  IfExists calls ReadSecret to perform its logic!
 /// </summary>
 /// <param name="secret"></param>
 /// <returns></returns>
 public async Task <bool> IfExists(KeyValueSecret secret)
 {
     return(await IfExists(secret.Path));
 }
 /// <summary>
 /// Reads the secret for the Secret passed in and returns a new KeyValueSecret object.  Returns NULL if the secret was not found.
 /// </summary>
 /// <param name="secret">A Secret Object with at least the secret Path specified.</param>
 /// <returns>Secret Object as read from Vault.</returns>
 public async Task <KeyValueSecret> ReadSecret(KeyValueSecret secret)
 {
     return(await ReadSecret(secret.Path));
 }