PowerShellUniversal.Apps.LetsEncrypt.psm1

function New-UDLetsEncryptApp {
    <#
    .SYNOPSIS
    Creates a new Let's Encrypt management app.

    .DESCRIPTION
    Creates a new Let's Encrypt management app for PowerShell Universal.
    #>


    # Load all page scripts
    $DashboardPath = Join-Path $PSScriptRoot -ChildPath 'dashboards\LetsEncrypt'
    Get-ChildItem (Join-Path $DashboardPath -ChildPath 'pages') -Recurse -Filter *.ps1 | Foreach-Object {
        . $_.FullName
    }

    # Execute the main app script and return the app
    $AppScript = Join-Path $DashboardPath 'LetsEncrypt.ps1'
    & $AppScript
}

function New-AppBanner {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [String]
        $Headline,

        [Parameter()]
        [String]
        $Tagline,

        [Parameter(Mandatory)]
        [String]
        $Icon #shield-cat
    )

    end {
        New-UDStack -Content {
            New-UDCard -Content {
                New-UDStack -Direction row -Spacing 2 -AlignItems center -Content {
                    New-UDIcon -Icon $Icon -Size 8x
                    New-UDStack -Direction column -Content {
                        New-UDTypography -Variant h4 -Text $Headline -Style @{ 'margin-bottom' = '4px' }
                        
                        if ($Tagline) {
                            New-UDTypography -Variant subtitle1 -Text $Tagline -Style @{ 'opacity' = '0.8' }
                        }
                    }
                }
            } -Style @{ 
                'margin-bottom' = '24px'
                'background'    = 'linear-gradient(135deg, rgba(155, 39, 176, 0.1) 0%, rgba(104, 108, 126, 0.57) 100%)'
                'border-left'   = '4px solid #4744caff'
            }
        } -Spacing 2
    }
}

function Show-LetsEncryptTableModal {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [psobject]
        $TableData,

        [Parameter()]
        [PSObject[]]
        $TableColums
    )

    end {
        Show-UDModal -Content {
            New-UDTable -Data $TableData -Columns $TableColums
        } -Header {
            New-UDTypography -Text "Download Certificate Files" -Variant h5
        } -FullWidth -MaxWidth 'md'
    }
}

function New-LookupComponent {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [String]
        $LookupScript
    )
    begin {
        $LookupScript = '{0}\{1}' -f 'PowerShellUniversal.Apps.LetsEncrypt', $LookupScript
    }
    end {
        New-UDGrid -Item -SmallSize 6 -Content {
            New-UDCard -Content {
                New-UDGrid -Container -Spacing 2 -Content {
                    
                    # Purpose
                    New-UDGrid -Item -Content {
                        New-UDTypography -Variant body1 -Text 'Lookup Certificate'
                    }

                    # Domain textbox
                    New-UDGrid -Item -ExtraSmallSize 12 -Content {
                        New-UDTextbox -Id 'txtLookupDomain' -Label "Domain" -Placeholder 'Enter domain to lookup' -Icon (New-UDIcon -Icon search) -OnValidate {
                            if ([string]::IsNullOrEmpty($EventData)) {
                                New-UDValidationResult -ValidationError 'Domain is required'
                            } 
                            else {
                                New-UDValidationResult -Valid
                            }
                        }
                    }
                    
                    # Lookup button
                    New-UDGrid -Item -SmallSize 6 -Content {
                        New-UDButton -Icon search -Text "Get Certificate" -FullWidth -Color secondary -OnClick {
                            $Domain = (Get-UDElement -Id 'txtLookupDomain').value
                            $psuScript = Get-PSUScript -Name $LookupScript -Integrated
                            $Job = Invoke-PSUScript -Script $psuScript -Parameters @{Domain = $Domain } -Integrated
                        
                            # Show modal with job monitoring
                            Show-UDModal -Content {
                                New-UDElement -Id 'ModalJobOutput' -Tag 'pre' -Attributes @{
                                    style = @{
                                        'background-color' = '#1e1e1e'
                                        'color'            = '#00ff00'
                                        'border-radius'    = '4px'
                                        'padding'          = '16px'
                                        'max-height'       = '500px'
                                        'overflow-y'       = 'auto'
                                        'font-family'      = 'Consolas, Monaco, monospace'
                                        'font-size'        = '12px'
                                        'white-space'      = 'pre-wrap'
                                        'min-height'       = '300px'
                                        'width'            = '100%'
                                    }
                                } -Content {
                                    "Fetching certificate info for: $Domain...`r`n"
                                }
                            } -Header {
                                New-UDTypography -Text "Certificate Request Monitor" -Variant h5
                            } -FullWidth -MaxWidth 'lg' -Persistent
                                            
                            # Monitor job in background
                            while ($Job.Status -eq 'Running' -or $Job.Status -eq 'Queued') {
                                try {
                                    Set-UDElement -Id 'ModalJobOutput' -Content {
                                        "Retrieving files..."
                                    }
                                }
                                catch {
                                    Write-Host "Error getting job output: $($_.Exception.Message)"
                                }
                                                
                                $Job = Get-PSUJob -Id $Job.Id -TrustCertificate -ErrorAction SilentlyContinue
                                Start-Sleep -Seconds 2
                            }
                                            
                            # Get final output and close modal
                            try {
                                $FinalOutput = Get-PSUJobOutput -Job $Job -TrustCertificate -ErrorAction SilentlyContinue
                                Set-UDElement -Id 'ModalJobOutput' -Content {
                                    if ($FinalOutput -and $FinalOutput.Length -gt 0) {
                                        $finalText = ($FinalOutput | ForEach-Object { "$_`r`n" }) -join ""
                                        "$finalText`r`n`r`n--- Job $($Job.Status) ---"
                                    }
                                    else {
                                        "Job completed but no output was captured.`r`n`r`n--- Job $($Job.Status) ---"
                                    }
                                }
                            }
                            catch {
                                Set-UDElement -Id 'ModalJobOutput' -Content {
                                    "Error retrieving final job output: $($_.Exception.Message)`r`n`r`n--- Job $($Job.Status) ---"
                                }
                            }
                            $session:PSUJobData = Get-PSUJobPipelineOutput -Job $Job -TrustCertificate
                            Hide-UDModal
                            Sync-UDElement -ID 'CertificateTableContainer'
                        }
                    }
                }
            } -Style @{
                'padding'       = '24px'
                'box-shadow'    = '0 2px 8px rgba(0,0,0,0.2)'
                'border-radius' = '8px'
                'border'        = '1px solid rgba(255,255,255,0.1)'
                'background'    = 'rgba(0,0,0,0.05)'
            }
        }
    }
}

function New-LetsEncryptCertificate {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [String]
        $Domain
    )

    end {
        $token = @{CFToken = ($Secret:CloudflareToken | ConvertTo-SecureString -AsPlainText -Force) }
        $certArgs = @{
            Domain     = $Domain
            AcceptTOS  = $true
            Plugin     = 'Cloudflare'
            PluginArgs = $token
        }

        New-PACertificate @certArgs
    }
}

function Get-LetsEncryptCertificate {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [String]
        $Domain
    )

    end {
        Get-PACertificate -MainDomain $Domain
    }
}

function Invoke-LetsEncryptApi {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [String]
        $Domain
    )
    switch ($Method) {
        'GET' { 
            #$Domain = $RequestData['Domain']
            $LookupScript = '{0}\{1}' -f 'PowerShellUniversal.Apps.LetsEncrypt', 'Get-LetsEncryptCertificate'
            $psuScript = Get-PSUScript -Name $LookupScript -Integrated -TrustCertificate
            Invoke-PSUScript -Script $psuScript -Parameters @{Domain = $Domain } -Integrated -Wait -TrustCertificate
        }
        'POST' {
            $LookupScript = '{0}\{1}' -f 'PowerShellUniversal.Apps.LetsEncrypt', 'New-LetsEncryptCertificate'
            $psuScript = Get-PSUScript -Name $LookupScript -Integrated -TrustCertificate
            Invoke-PSUScript -Script $psuScript -Parameters @{Domain = $Domain } -Integrated -Wait -TrustCertificate
            #Get-PSUJobPipelineOutput -Job $Job -Integrated -TrustCertificate
        }
    }
}

if (-not (Get-Module -ListAvailable -Name 'Posh-ACME')) {
    Install-Module -Name 'Posh-ACME' -Scope AllUsers -Force
}