(use "proposal_common.witx")

;;; External secrets storage.
;;;
;;; External secrets are binary blobs, that can represent external API tokens or anything that is not meant to be consumed by the wasi-crypto APIs.
;;; These secrets can be securely stored, and then retrieved using an identifier.
;;;
;;; Alternatively, the secrets manager can encrypt them, and applications will supply the ciphertext get the original secret back.
;;;
;;; The whole module is optional.
;;;
;;; __(optional)__
(module $wasi_ephemeral_crypto_exernal_secrets
  (import "memory" (memory))

  ;;; Store an external secret into the secrets manager.
  ;;;
  ;;; `$expiration` is the expiration date of the secret as a UNIX timestamp, in seconds.
  ;;; An expiration date is mandatory.
  ;;;
  ;;; On success, the secret identifier is put into `$secret_id` if it fits into `$secret_id_max_len` bytes.
  ;;; If the supplied output buffer is too small, `$overflow` is returned.
  ;;;
  ;;; If this function is not supported by the host the `$unsupported_feature` error is returned.
  (@interface func (export "external_secret_store")
    (param $secrets_manager $secrets_manager)
    (param $secret (@witx const_pointer u8))
    (param $secret_len $size)
    (param $expiration $timestamp)
    (param $secret_id (@witx pointer u8))
    (param $secret_id_max_len $size)
    (result $error (expected (error $crypto_errno)))
  )

  ;;; Replace a managed external with a new version.
  ;;;
  ;;; `$expiration` is the expiration date of the secret as a UNIX timestamp, in seconds.
  ;;; An expiration date is mandatory.
  ;;;
  ;;; On success, a new version is created and returned.
  ;;;
  ;;; If this function is not supported by the host the `$unsupported_feature` error is returned.
  (@interface func (export "external_secret_replace")
    (param $secrets_manager $secrets_manager)
    (param $secret (@witx const_pointer u8))
    (param $secret_len $size)
    (param $expiration $timestamp)
    (param $secret_id (@witx const_pointer u8))
    (param $secret_id_len $size)
    (result $error (expected $version (error $crypto_errno)))
  )

  ;;; Get a copy of an external secret given an identifier and version.
  ;;;
  ;;; `secret_version` can be set to a version number, or to `version.latest` to retrieve the most recent version of a secret.
  ;;;
  ;;; On success, a copy of the secret is returned.
  ;;;
  ;;; The function returns `$unsupported_feature` if this operation is not supported by the host, and `not_found` if the identifier and version don't match any existing secret.
  (@interface func (export "external_secret_from_id")
    (param $secrets_manager $secrets_manager)
    (param $secret_id (@witx const_pointer u8))
    (param $secret_id_len $size)
    (param $secret_version $version)
    (result $error (expected $array_output (error $crypto_errno)))
  )

  ;;; Invalidate an external secret given an identifier and a version.
  ;;;
  ;;; This asks the secrets manager to delete or revoke a stored secret, a specific version of a secret.
  ;;;
  ;;; `secret_version` can be set to a version number, or to `version.latest` to invalidate the current version, or to `version.all` to invalidate all versions of a secret.
  ;;;
  ;;; The function returns `$unsupported_feature` if this operation is not supported by the host, and `not_found` if the identifier and version don't match any existing secret.
  (@interface func (export "external_secret_invalidate")
    (param $secrets_manager $secrets_manager)
    (param $secret_id (@witx const_pointer u8))
    (param $secret_id_len $size)
    (param $secret_version $version)
    (result $error (expected (error $crypto_errno)))
  )

  ;;; Encrypt an external secret.
  ;;;
  ;;; Applications don't have access to the encryption key, and the secrets manager is free to choose any suitable algorithm.
  ;;;
  ;;; However, the returned ciphertext must include and authenticate both the secret and the expiration date.
  ;;;
  ;;; On success, the ciphertext is returned.
  (@interface func (export "external_secret_encapsulate")
    (param $secrets_manager $secrets_manager)
    (param $secret (@witx const_pointer u8))
    (param $secret_len $size)
    (param $expiration $timestamp)
    (result $error (expected $array_output (error $crypto_errno)))
  )

  ;;; Decrypt an external secret previously encrypted by the secrets manager.
  ;;;
  ;;; Returns the original secret if the ciphertext is valid.
  ;;; Returns `$expired` if the current date is past the stored expiration date.
  ;;; Returns `$verification_failed` if the ciphertext format is invalid or if its authentication tag couldn't be verified.
  (@interface func (export "external_secret_decapsulate")
    (param $secrets_manager $secrets_manager)
    (param $encrypted_secret (@witx const_pointer u8))
    (param $encrypted_secret_len $size)
    (result $error (expected $array_output (error $crypto_errno)))
  )
)
