HackerOne.psm1

function Set-H1ApiKey {
    param (
        [Parameter(Mandatory)][string]$Username,
        [Parameter(Mandatory)][string]$ApiToken
    )

    $secureToken = ConvertTo-SecureString $ApiToken -AsPlainText -Force
    $secureBytes = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureToken)
    $plainToken  = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($secureBytes)

    $encrypted = ConvertTo-SecureString $plainToken -AsPlainText -Force | ConvertFrom-SecureString

    $creds = @{
        Username = $Username
        Token    = $encrypted
    }

    $path = Join-Path $HOME ".h1navigator"
    if (-not (Test-Path $path)) {
        New-Item -ItemType Directory -Path $path | Out-Null
    }

    $creds | ConvertTo-Json | Set-Content -Path (Join-Path $path "creds.json")

    Write-Host "✅ HackerOne API credentials stored securely at `$HOME\.h1navigator\creds.json"
}

function Get-H1ApiKey {
    $path = Join-Path $HOME ".h1navigator\creds.json"
    if (-not (Test-Path $path)) {
        throw "❌ API credentials not found. Please run Set-H1ApiKey first."
    }

    $json = Get-Content -Raw -Path $path | ConvertFrom-Json
    $token = $json.Token | ConvertTo-SecureString
    $plainToken = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR(
        [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($token)
    )

    return @{
        Username = $json.Username
        Token    = $plainToken
    }
}



function Get-H1Programs {
    param (
        [switch]$ForceRefresh
    )

    $cachePath = Join-Path $HOME ".h1navigator\programs.json"

    if (-not $ForceRefresh -and (Test-Path $cachePath)) {
        try {
            $json = Get-Content -Raw -Path $cachePath | ConvertFrom-Json
            return $json
        } catch {
            Write-Warning "⚠️ Failed to read local cache, refetching..."
        }
    }

    $creds = Get-H1ApiKey
    $headers = @{
        Authorization = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($creds.Username):$($creds.Token)"))
    }

    $allPrograms = @()
    $page = 1
    $hasMore = $true

    while ($hasMore) {
        $url = "https://api.hackerone.com/v1/hackers/programs?page[number]=$page"
        try {
            $response = Invoke-RestMethod -Uri $url -Headers $headers

            $batch = $response.data | ForEach-Object {
                [PSCustomObject]@{
                    Name             = $_.attributes.name
                    Handle           = $_.attributes.handle
                    OffersBounties   = $_.attributes.offers_bounties
                    State            = $_.attributes.state
                    SubmissionState  = $_.attributes.submission_state
                    PolicySnippet    = ($_.attributes.policy -split "`n")[0]
                }
            }

            $allPrograms += $batch
            $page += 1
            $hasMore = $response.links.next -ne $null
        } catch {
            throw "❌ Failed on page $page : $_"
        }
    }

    # Save to disk
    if (-not (Test-Path (Split-Path $cachePath))) {
        New-Item -ItemType Directory -Path (Split-Path $cachePath) -Force | Out-Null
    }

    $allPrograms | ConvertTo-Json -Depth 3 | Set-Content -Path $cachePath -Encoding UTF8
    return $allPrograms
}



function Search-H1Programs {
    [CmdletBinding()]
    param (
        [string]$Keyword,
        [switch]$BountyOnly,

        [ValidateSet('open','closed')]
        [string]$SubmissionState,

        [switch]$Names,
        [switch]$ForceRefresh
    )

    $programs = Get-H1Programs -ForceRefresh:$ForceRefresh

    if ($Keyword) {
        $programs = $programs | Where-Object {
            $_.Name -match $Keyword -or $_.PolicySnippet -match $Keyword
        }
    }

    if ($BountyOnly) {
        $programs = $programs | Where-Object { $_.OffersBounties }
    }

    if ($PSBoundParameters.ContainsKey('SubmissionState')) {
        $programs = $programs | Where-Object {
            $_.SubmissionState -ieq $SubmissionState
        }
    }

    if ($Names) {
        return $programs | Select-Object -ExpandProperty Name
    }

    return $programs
}



function Get-H1Policy {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)][string]$Handle
    )

    $url = "https://hackerone.com/$Handle"
    Write-Host "🌐 Opening $url ..."
    Start-Process $url
}