Private/Model.psm1

#!/usr/bin/env pwsh
using namespace System
using namespace System.Text.Json.Serialization

using module ./Enums.psm1
using module ./Exceptions.psm1

#Requires -Modules clihelper.xconvert

#region apimodels

class IdentityProjectAdditionalPrivilegePermissionConditionEnvironment {
  [JsonPropertyName("`$eq")]
  [string] $Eq

  IdentityProjectAdditionalPrivilegePermissionConditionEnvironment() {}
  IdentityProjectAdditionalPrivilegePermissionConditionEnvironment([string]$eq) {
    $this.Eq = $eq
  }
}

class IdentityProjectAdditionalPrivilegePermissionCondition {
  [JsonPropertyName("environment")]
  [IdentityProjectAdditionalPrivilegePermissionConditionEnvironment] $Environment

  IdentityProjectAdditionalPrivilegePermissionCondition() {}
  IdentityProjectAdditionalPrivilegePermissionCondition([IdentityProjectAdditionalPrivilegePermissionConditionEnvironment]$environment) {
    $this.Environment = $environment
  }
}

class IdentityProjectAdditionalPrivilegePermission {
  [JsonPropertyName("subject")]
  [string] $Subject
  [JsonPropertyName("action")]
  [string[]] $Action
  [JsonPropertyName("conditions")]
  [IdentityProjectAdditionalPrivilegePermissionCondition] $Conditions

  IdentityProjectAdditionalPrivilegePermission() {}
  IdentityProjectAdditionalPrivilegePermission([string]$subject, [string[]]$action, [IdentityProjectAdditionalPrivilegePermissionCondition]$conditions) {
    $this.Subject = $subject
    $this.Action = $action
    $this.Conditions = $conditions
  }
}

class IdentityProjectAdditionalPrivilegeType {
  [JsonPropertyName("isTemporary")]
  [bool] $IsTemporary = $false

  IdentityProjectAdditionalPrivilegeType() {}
  IdentityProjectAdditionalPrivilegeType([bool]$isTemporary) {
    $this.IsTemporary = $isTemporary
  }
}

class AddIdentityProjectAdditionalPrivilegeOptions {
  [JsonPropertyName("identityId")]
  [string] $IdentityId
  [JsonPropertyName("projectId")]
  [string] $ProjectId
  [JsonPropertyName("slug")]
  [string] $Slug
  [JsonPropertyName("type")]
  [IdentityProjectAdditionalPrivilegeType] $Type = [IdentityProjectAdditionalPrivilegeType]::new($false)
  [JsonPropertyName("permissions")]
  [IdentityProjectAdditionalPrivilegePermission[]] $Permissions

  AddIdentityProjectAdditionalPrivilegeOptions() {}

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.IdentityId)) { throw [InfisicalException]::new("IdentityId is required") }
    if ([string]::IsNullOrWhiteSpace($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrWhiteSpace($this.Slug)) { throw [InfisicalException]::new("Slug is required") }
    if ($null -eq $this.Permissions) { throw [InfisicalException]::new("Permissions is required") }
  }
}

class IdentityProjectAdditionalPrivilegeResponse {
  [JsonPropertyName("privilege")]
  [object] $Privilege
}


class MachineIdentityCredential {
  [JsonPropertyName("accessToken")]
  [string] $AccessToken
  [JsonPropertyName("expiresIn")]
  [decimal] $ExpiresIn
  [JsonPropertyName("accessTokenMaxTTL")]
  [decimal] $AccessTokenMaxTTL
  [JsonPropertyName("tokenType")]
  [string] $TokenType

  MachineIdentityCredential([string]$accessToken, [decimal]$expiresIn, [decimal]$accessTokenMaxTTL, [string]$tokenType) {
    $this.AccessToken = $accessToken
    $this.ExpiresIn = $expiresIn
    $this.AccessTokenMaxTTL = $accessTokenMaxTTL
    $this.TokenType = $tokenType
  }

  MachineIdentityCredential() {}
}

class UniversalAuthLoginRequest {
  [JsonPropertyName("clientId")]
  [string] $ClientId
  [JsonPropertyName("clientSecret")]
  [string] $ClientSecret

  UniversalAuthLoginRequest([string]$clientId, [securestring]$clientSecret) {
    $this.ClientId = $clientId
    $this.ClientSecret = ($clientSecret | xconvert Tostring)
  }
}

class LdapAuthLoginRequest {
  [JsonPropertyName("identityId")]
  [string] $IdentityId
  [JsonPropertyName("username")]
  [string] $Username
  [JsonPropertyName("password")]
  [string] $Password

  LdapAuthLoginRequest([string]$identityId, [string]$username, [securestring]$password) {
    $this.IdentityId = $identityId
    $this.Username = $username
    $this.Password = ($password | xconvert Tostring)
  }
}

class ListSecretsOptions {
  [bool] $SetSecretsAsEnvironmentVariables = $false
  [JsonPropertyName("workspaceId")]
  [string] $ProjectId = $null
  [JsonPropertyName("environment")]
  [string] $EnvironmentSlug = $null
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = "/"
  [JsonPropertyName("viewSecretValue")]
  [System.Nullable[bool]] $ViewSecretValue = $null
  [JsonPropertyName("expandSecretReferences")]
  [System.Nullable[bool]] $ExpandSecretReferences = $true
  [JsonPropertyName("recursive")]
  [System.Nullable[bool]] $Recursive = $false
  [JsonPropertyName("tagSlugs")]
  [string[]] $TagSlugs = $null
  [JsonPropertyName("include_imports")]
  [bool] $IncludeImports = $true

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrEmpty($this.EnvironmentSlug)) { throw [InfisicalException]::new("EnvironmentSlug is required") }
    if ([string]::IsNullOrEmpty($this.SecretPath)) { throw [InfisicalException]::new("SecretPath is required") }
  }
}

class GetSecretOptions {
  [JsonPropertyName("workspaceId")]
  [string] $ProjectId = $null
  [JsonPropertyName("environment")]
  [string] $EnvironmentSlug = $null
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = "/"
  [JsonPropertyName("secretName")]
  [string] $SecretName = [string]::Empty
  [JsonPropertyName("version")]
  [System.Nullable[int]] $Version = $null
  [JsonPropertyName("type")]
  [System.Nullable[SecretType]] $Type = $null
  [JsonPropertyName("viewSecretValue")]
  [System.Nullable[bool]] $ViewSecretValue = $null
  [JsonPropertyName("expandSecretReferences")]
  [System.Nullable[bool]] $ExpandSecretReferences = $true
  [JsonPropertyName("include_imports")]
  [bool] $IncludeImports = $true

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrEmpty($this.EnvironmentSlug)) { throw [InfisicalException]::new("EnvironmentSlug is required") }
    if ([string]::IsNullOrEmpty($this.SecretPath)) { throw [InfisicalException]::new("SecretPath is required") }
    if ([string]::IsNullOrEmpty($this.SecretName)) { throw [InfisicalException]::new("SecretName is required") }
  }
}

class SecretMetadata {
  [JsonPropertyName("key")]
  [string] $Key = [string]::Empty
  [JsonPropertyName("value")]
  [string] $Value = [string]::Empty
}

class CreateSecretOptions {
  [JsonPropertyName("secretName")]
  [string] $SecretName = [string]::Empty
  [JsonPropertyName("workspaceId")]
  [string] $ProjectId = $null
  [JsonPropertyName("environment")]
  [string] $EnvironmentSlug = $null
  [JsonPropertyName("secretValue")]
  [string] $SecretValue = [string]::Empty
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = "/"
  [JsonPropertyName("secretComment")]
  [string] $SecretComment = $null
  [JsonPropertyName("secretMetadata")]
  [SecretMetadata[]] $Metadata = $null
  [JsonPropertyName("skipMultilineEncoding")]
  [System.Nullable[bool]] $SkipMultilineEncoding = $null
  [JsonPropertyName("type")]
  [System.Nullable[SecretType]] $Type = $null
  [JsonPropertyName("secretReminderRepeatDays")]
  [System.Nullable[int]] $SecretReminderRepeatDays = $null
  [JsonPropertyName("secretReminderNote")]
  [string] $SecretReminderNote = $null

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrEmpty($this.EnvironmentSlug)) { throw [InfisicalException]::new("EnvironmentSlug is required") }
    if ([string]::IsNullOrEmpty($this.SecretName)) { throw [InfisicalException]::new("SecretName is required") }
    if ([string]::IsNullOrEmpty($this.SecretValue)) { throw [InfisicalException]::new("SecretValue is required") }
    if ([string]::IsNullOrEmpty($this.SecretPath)) { throw [InfisicalException]::new("SecretPath is required") }
  }
}

class UpdateSecretOptions {
  # SecretName is the current key name (used in the URL path, NOT sent in body)
  [string] $SecretName = [string]::Empty
  # Optional: rename the secret. Leave $null to keep existing name.
  # NOTE: Do NOT set to empty string - the API rejects empty string for this field.
  [string] $NewSecretName = $null
  [string] $ProjectId = $null
  [string] $EnvironmentSlug = $null
  [System.Nullable[SecretType]] $Type = $null
  [string] $SecretPath = "/"
  [System.Nullable[bool]] $NewSkipMultilineEncoding = $null
  # Optional: update the secret value. Leave $null to keep existing value.
  [string] $NewSecretValue = $null
  # Optional: update the secret comment. Leave $null to keep existing comment.
  [string] $NewSecretComment = $null
  [SecretMetadata[]] $NewMetadata = $null
  [string] $NewSecretReminderNote = $null
  [System.Nullable[int]] $NewSecretReminderRepeatDays = $null

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrEmpty($this.SecretName)) { throw [InfisicalException]::new("SecretName is required") }
    if ([string]::IsNullOrEmpty($this.SecretPath)) { throw [InfisicalException]::new("SecretPath is required") }
    if ([string]::IsNullOrEmpty($this.EnvironmentSlug)) { throw [InfisicalException]::new("EnvironmentSlug is required") }
  }

  # Returns a hashtable with only the fields that should be sent to the API.
  # Omits null/empty optional string fields to avoid API validation errors
  # (e.g. the API rejects newSecretName="" with a 422 minimum-length error).
  [System.Collections.Hashtable] ToSerializableHashtable() {
    $body = [System.Collections.Hashtable]::new()
    $body["workspaceId"] = $this.ProjectId
    $body["environment"] = $this.EnvironmentSlug
    $body["secretPath"] = $this.SecretPath
    if ($null -ne $this.Type) { $body["type"] = $this.Type.ToString() }
    if ($null -ne $this.NewSkipMultilineEncoding) { $body["skipMultilineEncoding"] = $this.NewSkipMultilineEncoding }
    if ($null -ne $this.NewSecretReminderRepeatDays) { $body["secretReminderRepeatDays"] = $this.NewSecretReminderRepeatDays }
    if (![string]::IsNullOrEmpty($this.NewSecretName)) { $body["newSecretName"] = $this.NewSecretName }
    if (![string]::IsNullOrEmpty($this.NewSecretValue)) { $body["secretValue"] = $this.NewSecretValue }
    if (![string]::IsNullOrEmpty($this.NewSecretComment)) { $body["secretComment"] = $this.NewSecretComment }
    if (![string]::IsNullOrEmpty($this.NewSecretReminderNote)) { $body["secretReminderNote"] = $this.NewSecretReminderNote }
    if ($null -ne $this.NewMetadata -and $this.NewMetadata.Length -gt 0) { $body["secretMetadata"] = $this.NewMetadata }
    return $body
  }
}

class DeleteSecretOptions {
  [JsonPropertyName("secretName")]
  [string] $SecretName = [string]::Empty
  [JsonPropertyName("workspaceId")]
  [string] $ProjectId = $null
  [JsonPropertyName("environment")]
  [string] $EnvironmentSlug = $null
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = "/"

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrEmpty($this.SecretName)) { throw [InfisicalException]::new("SecretName is required") }
    if ([string]::IsNullOrEmpty($this.SecretPath)) { throw [InfisicalException]::new("SecretPath is required") }
    if ([string]::IsNullOrEmpty($this.EnvironmentSlug)) { throw [InfisicalException]::new("EnvironmentSlug is required") }
  }
}

class IssueCertificateOptions {
  [JsonPropertyName("subscriberName")]
  [string] $SubscriberName = [string]::Empty
  [JsonPropertyName("projectId")]
  [string] $ProjectId = [string]::Empty

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.SubscriberName)) { throw [InfisicalException]::new("SubscriberName is required") }
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
  }
}

class SubscriberIssuedCertificate {
  [JsonPropertyName("certificate")]
  [string] $Certificate = [string]::Empty
  [JsonPropertyName("issuingCaCertificate")]
  [string] $IssuingCaCertificate = [string]::Empty
  [JsonPropertyName("certificateChain")]
  [string] $CertificateChain = [string]::Empty
  [JsonPropertyName("privateKey")]
  [string] $PrivateKey = [string]::Empty
  [JsonPropertyName("serialNumber")]
  [string] $SerialNumber = [string]::Empty
}

class RetrieveLatestCertificateBundleOptions {
  [JsonPropertyName("subscriberName")]
  [string] $SubscriberName = [string]::Empty
  [JsonPropertyName("projectId")]
  [string] $ProjectId = [string]::Empty

  [void] Validate() {
    if ([string]::IsNullOrEmpty($this.SubscriberName)) { throw [InfisicalException]::new("SubscriberName is required") }
    if ([string]::IsNullOrEmpty($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
  }
}

class CertificateBundle {
  [JsonPropertyName("certificate")]
  [string] $Certificate = [string]::Empty
  [JsonPropertyName("certificateChain")]
  [string] $CertificateChain = [string]::Empty
  [JsonPropertyName("privateKey")]
  [string] $PrivateKey = [string]::Empty
  [JsonPropertyName("serialNumber")]
  [string] $SerialNumber = [string]::Empty
}

class InfisicalSecret {
  [JsonPropertyName("id")]
  [string] $Id = [string]::Empty
  [JsonPropertyName("workspace")]
  [string] $ProjectId = [string]::Empty
  [JsonPropertyName("environment")]
  [string] $Environment = [string]::Empty
  [JsonPropertyName("version")]
  [int] $Version
  [JsonPropertyName("secretKey")]
  [string] $SecretKey = [string]::Empty
  [JsonPropertyName("secretValue")]
  [string] $SecretValue = [string]::Empty
  [JsonPropertyName("secretComment")]
  [string] $SecretComment = [string]::Empty
  [JsonPropertyName("secretReminderNote")]
  [string] $SecretReminderNote = $null
  [JsonPropertyName("secretReminderRepeatDays")]
  [System.Nullable[int]] $SecretReminderRepeatDays = $null
  [JsonPropertyName("skipMultilineEncoding")]
  [System.Nullable[bool]] $SkipMultilineEncoding = $null
  [JsonPropertyName("isRotatedSecret")]
  [bool] $IsRotatedSecret = $false
  [JsonPropertyName("rotationId")]
  [string] $RotationId = $null
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = [string]::Empty
  [JsonPropertyName("secretMetadata")]
  [SecretMetadata[]] $Metadata = @()
}

class SecretImport {
  [JsonPropertyName("secretPath")]
  [string] $SecretPath = [string]::Empty
  [JsonPropertyName("environment")]
  [string] $Environment = [string]::Empty
  [JsonPropertyName("secrets")]
  [InfisicalSecret[]] $Secrets = @()
}

class ListSecretsResponse {
  [JsonPropertyName("secrets")]
  [InfisicalSecret[]] $Secrets = @()
  [JsonPropertyName("imports")]
  [SecretImport[]] $Imports = @()
}

class GetSecretResponse {
  [JsonPropertyName("secret")]
  [InfisicalSecret] $Secret = [InfisicalSecret]::new()
}

class CreateSecretResponse {
  [JsonPropertyName("secret")]
  [InfisicalSecret] $Secret = [InfisicalSecret]::new()
}

class UpdateSecretResponse {
  [JsonPropertyName("secret")]
  [InfisicalSecret] $Secret = [InfisicalSecret]::new()
}

class DeleteSecretResponse {
  [JsonPropertyName("secret")]
  [InfisicalSecret] $Secret = [InfisicalSecret]::new()
}

class KmsKey {
  [JsonPropertyName("id")]
  [string] $Id
  [JsonPropertyName("name")]
  [string] $Name
  [JsonPropertyName("description")]
  [string] $Description
  [JsonPropertyName("isDisabled")]
  [bool] $IsDisabled
}

class ListKmsKeysOptions {
  [JsonPropertyName("projectId")]
  [string] $ProjectId
  [JsonPropertyName("limit")]
  [int] $Limit = 20
  [JsonPropertyName("offset")]
  [int] $Offset = 0
  [JsonPropertyName("orderBy")]
  [string] $OrderBy = "name"
  [JsonPropertyName("orderDirection")]
  [string] $OrderDirection = "asc"
}

class GetKmsKeyByIdOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class GetKmsKeyByNameOptions {
  [JsonPropertyName("keyName")]
  [string] $KeyName
  [JsonPropertyName("projectId")]
  [string] $ProjectId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyName)) { throw [InfisicalException]::new("KeyName is required") }
    if ([string]::IsNullOrWhiteSpace($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required for GetKmsKeyByName") }
  }
}

class CreateKmsKeyOptions {
  [JsonPropertyName("projectId")]
  [string] $ProjectId
  [JsonPropertyName("name")]
  [string] $Name
  [JsonPropertyName("description")]
  [string] $Description
  [JsonPropertyName("keyUsage")]
  [string] $KeyUsage = "encrypt-decrypt"
  [JsonPropertyName("encryptionAlgorithm")]
  [string] $EncryptionAlgorithm = "aes-256-gcm"

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.ProjectId)) { throw [InfisicalException]::new("ProjectId is required") }
    if ([string]::IsNullOrWhiteSpace($this.Name)) { throw [InfisicalException]::new("Name is required") }
  }
}

class UpdateKmsKeyOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId = [string]::Empty
  [JsonIgnore(Condition = "WhenWritingNull")]
  [JsonPropertyName("name")]
  [string] $Name = $null
  [JsonIgnore(Condition = "WhenWritingNull")]
  [JsonPropertyName("isDisabled")]
  [System.Nullable[bool]] $IsDisabled = $null
  [JsonIgnore(Condition = "WhenWritingNull")]
  [JsonPropertyName("description")]
  [string] $Description = $null

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class DeleteKmsKeyOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class RetrieveKmsPublicKeyOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class ExportKmsPrivateKeyOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class BulkExportPrivateKeysOptions {
  [JsonPropertyName("keyIds")]
  [string[]] $KeyIds

  [void] Validate() {
    if ($null -eq $this.KeyIds -or $this.KeyIds.Length -eq 0) { throw [InfisicalException]::new("KeyIds array cannot be empty") }
  }
}

class EncryptKmsDataOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId = [string]::Empty
  [JsonPropertyName("plaintext")]
  [string] $Plaintext

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
    if ([string]::IsNullOrWhiteSpace($this.Plaintext)) { throw [InfisicalException]::new("Plaintext is required") }
  }
}

class DecryptKmsDataOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId = [string]::Empty
  [JsonPropertyName("ciphertext")]
  [string] $Ciphertext

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
    if ([string]::IsNullOrWhiteSpace($this.Ciphertext)) { throw [InfisicalException]::new("Ciphertext is required") }
  }
}

class SignKmsDataOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId = [string]::Empty
  [JsonPropertyName("signingAlgorithm")]
  [string] $SigningAlgorithm
  [JsonPropertyName("data")]
  [string] $Data
  [JsonPropertyName("isDigest")]
  [System.Nullable[bool]] $IsDigest = $false

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
    if ([string]::IsNullOrWhiteSpace($this.SigningAlgorithm)) { throw [InfisicalException]::new("SigningAlgorithm is required") }
    if ([string]::IsNullOrWhiteSpace($this.Data)) { throw [InfisicalException]::new("Data is required") }
  }
}

class VerifyKmsSignatureOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId = [string]::Empty
  [JsonPropertyName("data")]
  [string] $Data
  [JsonPropertyName("signature")]
  [string] $Signature
  [JsonPropertyName("signingAlgorithm")]
  [string] $SigningAlgorithm
  [JsonPropertyName("isDigest")]
  [System.Nullable[bool]] $IsDigest = $false

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
    if ([string]::IsNullOrWhiteSpace($this.Data)) { throw [InfisicalException]::new("Data is required") }
    if ([string]::IsNullOrWhiteSpace($this.Signature)) { throw [InfisicalException]::new("Signature is required") }
    if ([string]::IsNullOrWhiteSpace($this.SigningAlgorithm)) { throw [InfisicalException]::new("SigningAlgorithm is required") }
  }
}

class ListKmsSigningAlgorithmsOptions {
  [JsonPropertyName("keyId")]
  [string] $KeyId

  [void] Validate() {
    if ([string]::IsNullOrWhiteSpace($this.KeyId)) { throw [InfisicalException]::new("KeyId is required") }
  }
}

class KmsKeyResponse {
  [JsonPropertyName("key")]
  [object] $Key
}

class KmsKeysResponse {
  [JsonPropertyName("keys")]
  [object[]] $Keys
}

class KmsEncryptResponse {
  [JsonPropertyName("ciphertext")]
  [string] $Ciphertext
}

class KmsDecryptResponse {
  [JsonPropertyName("plaintext")]
  [string] $Plaintext
}

class KmsSignResponse {
  [JsonPropertyName("signature")]
  [string] $Signature
}

class KmsVerifyResponse {
  [JsonPropertyName("isValid")]
  [bool] $IsValid
}

class KmsPublicKeyResponse {
  [JsonPropertyName("publicKey")]
  [string] $PublicKey
}

class KmsPrivateKeyResponse {
  [JsonPropertyName("privateKey")]
  [string] $PrivateKey
}

class KmsBulkExportPrivateKeysResponse {
  [JsonPropertyName("keys")]
  [object[]] $Keys
}

class KmsSigningAlgorithmsResponse {
  [JsonPropertyName("signingAlgorithms")]
  [string[]] $SigningAlgorithms
}
#endregion

class InfisicalUniversalAuth {
  hidden [ValidateNotNullOrWhiteSpace()][string] $_clientId
  hidden [ValidateNotNullOrWhiteSpace()][string] $_clientSecret

  InfisicalUniversalAuth([string]$clientId, [securestring]$clientSecret) {
    $this._clientId = $clientId
    $this._clientSecret = ($clientSecret | xconvert Tostring)
  }
  InfisicalUniversalAuth() {}
}

class InfisicalTokenAuth {
  hidden [ValidateNotNullOrWhiteSpace()][string] $_token

  InfisicalTokenAuth([string]$token) {
    $this._token = $token
  }
  InfisicalTokenAuth() {}
}

class InfisicalAuth {
  hidden [InfisicalUniversalAuth] $_universalAuth
  hidden [InfisicalTokenAuth] $_tokenAuth
  hidden [InfisicalAuthMethod] $_authMethod

  InfisicalAuth([InfisicalUniversalAuth]$universalAuth) {
    $this._universalAuth = $universalAuth
    $this._authMethod = [InfisicalAuthMethod]::Universal
  }

  InfisicalAuth([InfisicalTokenAuth]$tokenAuth) {
    $this._tokenAuth = $tokenAuth
    $this._authMethod = [InfisicalAuthMethod]::Token
  }

  InfisicalAuth() {}

  hidden [InfisicalAuthMethod] GetAuthMethod() {
    return $this._authMethod
  }

  hidden [InfisicalUniversalAuth] GetUniversalAuth() {
    if ($this._authMethod -ne [InfisicalAuthMethod]::Universal) {
      throw [Exception]::new("Unable to get universal auth details. Auth method is set to $($this._authMethod)")
    }
    if ($null -eq $this._universalAuth) {
      throw [Exception]::new("Universal auth details are not set")
    }
    return $this._universalAuth
  }

  hidden [InfisicalTokenAuth] GetTokenAuth() {
    if ($this._authMethod -ne [InfisicalAuthMethod]::Token) {
      throw [Exception]::new("Unable to get token auth details. Auth method is set to $($this._authMethod)")
    }
    if ($null -eq $this._tokenAuth) {
      throw [Exception]::new("Token auth details are not set")
    }
    return $this._tokenAuth
  }
}

class InfisicalSdkSettings {
  [ValidateNotNullOrWhiteSpace()][string] $HostUri
  [ValidateNotNullOrEmpty()][securestring] $clientSecret

  InfisicalSdkSettings() {
    if (![string]::IsNullOrWhiteSpace($env:INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET)) {
      $this.clientSecret = $env:INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET | xconvert ToSecurestring
    }
    $this.HostUri = ![string]::IsNullOrWhiteSpace($env:INFISICAL_HOST_URI) ? $env:INFISICAL_HOST_URI : "https://app.infisical.com"
  }
}

class InfisicalSdkSettingsBuilder {
  hidden [InfisicalSdkSettings] $_settings = [InfisicalSdkSettings]::new()

  [InfisicalSdkSettingsBuilder] WithHostUri([string]$hostUri) {
    $this._settings.HostUri = $hostUri
    return $this
  }

  [InfisicalSdkSettings] Build() {
    $result = [InfisicalSdkSettings]::new()
    $result.HostUri = $this._settings.HostUri
    return $result
  }
}