Skip to content

Improve the post-install script - #353

Merged
gnh1201 merged 16 commits into
masterfrom
dev
Dec 1, 2025
Merged

gnh1201 merged 16 commits into
masterfrom
dev

Conversation

@gnh1201

@gnh1201 gnh1201 commented Dec 1, 2025

Copy link
Copy Markdown
Owner

User description

Improve the post-install script


PR Type

Enhancement, Other


Description

  • Refactored installer with modular component selection system

  • Created centralized DownloadUrls.psd1 manifest for all component URLs

  • Replaced afterInstall.ps1 with new postInstall.ps1 supporting telemetry

  • Added WinDivert and Android Platform Tools as selectable components

  • Updated adb.js to use dynamic android_platform_tools path

  • Removed tessdata submodules and cleaned up installer exclusions


Diagram Walkthrough

flowchart LR
  A["afterInstall.ps1<br/>hardcoded URLs"] -->|replaced| B["postInstall.ps1<br/>modular design"]
  C["DownloadUrls.psd1<br/>centralized manifest"] -->|feeds| B
  B -->|supports| D["Component Selection<br/>python, curl, yara, etc."]
  B -->|sends| E["PostHog Telemetry<br/>app_installed event"]
  F["adb.js<br/>static path"] -->|updated| G["dynamic android_platform_tools<br/>path resolution"]
Loading

File Walkthrough

Relevant files
Enhancement
2 files
adb.js
Update ADB binary path and version                                             
+3/-3     
postInstall.ps1
Implement modular post-install with telemetry                       
+860/-0 
Miscellaneous
5 files
afterInstall.ps1
Remove old post-install script                                                     
+0/-403 
tessdata
Remove tessdata git submodule                                                       
+0/-1     
tessdata_best
Remove tessdata_best git submodule                                             
+0/-1     
tessdata_fast
Remove tessdata_fast git submodule                                             
+0/-1     
binaries_meta.json
Remove obsolete binaries metadata file                                     
+0/-380 
Configuration changes
2 files
DownloadUrls.psd1
Create centralized component URL manifest                               
+121/-0 
setup.iss
Refactor installer components and integrate postInstall   
+33/-20 

Summary by CodeRabbit

  • New Features

    • Optional telemetry during installation and a data-driven, modular installer that lets users pick components per architecture; improved component selection and URL-driven downloads.
  • Bug Fixes

    • More robust architecture detection, retries and error handling during downloads, and clearer progress reporting.
  • Chores

    • Removed legacy installer metadata and detached large bundled metadata and tessdata references; bumped Android Debug Bridge version.

✏️ Tip: You can customize this high-level summary in your review settings.

gnh1201 and others added 13 commits December 1, 2025 12:29
Renamed afterInstall.ps1 to postInstall.ps1 and added telemetry support for PostHog. Updated Python embeddable package URLs to version 3.14.0. Revised setup.iss to improve component granularity, update author info, and integrate the new post-install script and telemetry parameters.
Introduces a DownloadUrls.psd1 manifest for component URLs and refactors postInstall.ps1 to support modular, architecture-aware downloads and installations. Adds selection logic for components, improves error handling, and updates setup.iss to support new GTK3 and GTK-server options. This change enables easier maintenance and extensibility for future components.
Corrected syntax errors in component definitions and registry entries, updated post-install PowerShell command formatting, added AppVersion custom message, and implemented GetSelectedComponents function for improved component selection handling.
Deleted tessdata, tessdata_best, and tessdata_fast submodules. Updated DownloadUrls.psd1 to fix Python x86 URL and set gtk3runtime arm64 to null. Improved architecture detection in postInstall.ps1 and cleaned up component selection logic. Modified setup.iss to remove exclusions for tessdata assets and cleaned up run/uninstall sections.
Replaces the $process_person_profile property with a product property set to 'welsonjs' in the telemetry event payload for PostHog. This clarifies the product being tracked during installation.
Introduces WinDivert and Android Platform Tools as selectable components in the installer. Updates DownloadUrls.psd1 with their download URLs, adds their handling in postInstall.ps1, and registers them in setup.iss for installation.
Updated the component name from 'android_tools' to 'android_platform_tools' in DownloadUrls.psd1 and postInstall.ps1 for consistency and clarity. Adjusted variable names and references accordingly.
Updated the component name from 'android_tools' to 'android_platform_tools' in setup.iss for consistency and clarity.
Removed unnecessary installer arguments and ensured installers run with process waiting for completion in postInstall.ps1. Cleaned up setup.iss to remove redundant 'Components' field for PowerShell execution. Minor formatting fix in DownloadUrls.psd1.
Introduces extraction and installation logic for WinDivert and Android Platform Tools components in postInstall.ps1. Also updates log messages for consistency and clarity.
Changed the default adb binary path to use the app data directory for improved portability. Updated copyright and contributor information. Bumped VERSIONINFO to 0.2.3.
Fix the file path in adb.js
Use the `DownloadUrls.psd1` file instead of binaries_meta.json
@sourcery-ai

sourcery-ai Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors the installer to use a new, component-aware PowerShell post-install script that downloads/extracts optional runtime tools at install time, wires it into Inno Setup with telemetry support, and adjusts ADB to use a new Android platform tools layout while cleaning up bundled assets and metadata files.

Sequence diagram for Inno Setup invoking the new component-aware post-install script

sequenceDiagram
    actor User
    participant InnoSetup
    participant GetSelectedComponents
    participant PostInstallPS1
    participant DownloadUrlsPsd1
    participant RemoteCDNs
    participant PostHogAPI
    participant AppDataWelsonJS
    participant TempDownloads

    User->>InnoSetup: Run WelsonJS installer
    InnoSetup->>User: Show component selection UI
    User-->>InnoSetup: Select components

    InnoSetup->>GetSelectedComponents: WizardSelectedComponents(False)
    GetSelectedComponents-->>InnoSetup: components_string

    InnoSetup->>PostInstallPS1: Start postInstall.ps1
        note over InnoSetup,PostInstallPS1: Pass TelemetryProvider, TelemetryApiKey, Version, DistinctId, Components

    PostInstallPS1->>PostInstallPS1: Resolve ScriptRoot and TargetDir
    PostInstallPS1->>DownloadUrlsPsd1: Import-PowerShellDataFile
    DownloadUrlsPsd1-->>PostInstallPS1: DownloadUrls table

    PostInstallPS1->>PostInstallPS1: Parse Components string
    PostInstallPS1->>PostInstallPS1: Detect native architecture

    alt TelemetryProvider is posthog and TelemetryApiKey present
        PostInstallPS1->>PostInstallPS1: Build anonymous event payload
        PostInstallPS1->>PostHogAPI: POST /i/v0/e
        PostHogAPI-->>PostInstallPS1: 2xx or error (ignored)
    end

    loop For each selected component
        PostInstallPS1->>PostInstallPS1: Get-DownloadUrl(component, arch)
        alt URL available
            PostInstallPS1->>TempDownloads: Download-File
            TempDownloads-->>PostInstallPS1: Archive/installer file
        else URL missing
            PostInstallPS1->>PostInstallPS1: Log skip for this component
        end
    end

    loop For each downloaded component
        alt Zip or similar archive
            PostInstallPS1->>AppDataWelsonJS: Extract-CompressedFile
        else TarGz archive
            PostInstallPS1->>AppDataWelsonJS: Extract-TarGzArchive
        else Native installer (gtk3runtime, npcap, nmap)
            PostInstallPS1->>RemoteCDNs: Start-Process installer
        end
    end

    PostInstallPS1-->>InnoSetup: Exit 0 on success
    InnoSetup-->>User: Show completion and shortcuts
Loading

File-Level Changes

Change Details Files
Replace the legacy after-install PowerShell script and baked-in binary metadata with a new post-install pipeline that drives downloads/extraction based on selected components and machine architecture.
  • Introduce postInstall.ps1 that resolves script root, loads a DownloadUrls.psd1 URL table, and parses the Inno Components string once into a reusable selection helper.
  • Implement architecture detection via Win32_Processor (with 32/64-bit fallback) and map component names/arch to URLs using Get-DownloadUrl.
  • Add robust helpers for directory preparation, HTTP downloads with retry, ZIP extraction, and tar.gz extraction using tar, with clear logging and non-fatal handling for optional pieces.
  • Implement a two-phase flow: download all selected component artifacts into %TEMP% and then extract/install them into per-component subdirectories under %APPDATA%\welsonjs or run external installers where needed.
  • Wire anonymous PostHog telemetry into the script, sending a single app_installed event when a key is provided, and ensure failures never break installation.
postInstall.ps1
data/DownloadUrls.psd1
data/binaries_meta.json
afterInstall.ps1
Update the Inno Setup script to use the new post-install script, introduce fine-grained install components, and remove previously bundled OCR assets in favor of on-demand downloads.
  • Rename the additional tools component to artifacts and add new optional components for Python, curl, websocat, YARA, WAMR, Tesseract data variants, GTK3 runtime, GTK server, Nmap/Npcap, WinDivert, and Android Platform Tools with appropriate Types.
  • Point registry entries and Start-menu launcher shortcuts at the new artifacts component so association/launcher install is controlled by it.
  • Replace afterInstall.ps1 with postInstall.ps1 in the [Run] section, passing telemetry configuration, app version, machine name, and selected components via a new GetSelectedComponents code function.
  • Switch service install/uninstall and launcher auto-run components from addtools to artifacts and remove the previous per-asset excludes on the app* source entry, relying on runtime downloads for tessdata assets.
  • Add custom messages for AppVersion and PostHogApiKey and update script metadata comments (updated_on and author line).
setup.iss
Adjust adb.js to align with the new Android Platform Tools installation layout and update meta information.
  • Change the default adb binary path to point to %APPDATA%\<AppName>\android_platform_tools\platform-tools\adb.exe instead of a bundled relative path.
  • Update the version string to 0.2.3 and simplify the header copyright/author comment to reference Catswords OSS contributors.
lib/adb.js
Define a centralized URL map for all downloadable components used by the post-install script.
  • Add data/DownloadUrls.psd1 with per-component, per-architecture URLs for Python, curl, YARA, WAMR, websocat, artifacts, GTK runtimes, Tesseract datasets, Npcap/Nmap, WinDivert, and Android Platform Tools.
  • Use any keys for arch-agnostic assets like tessdata variants and share URLs across architectures where appropriate.
data/DownloadUrls.psd1
Remove previously bundled Tesseract datasets and binary metadata now replaced by runtime downloads.
  • Delete prepackaged tessdata, tessdata_best, and tessdata_fast directories under app/assets.
  • Remove the obsolete binaries_meta.json file that previously described local binary artifacts.
app/assets/tessdata
app/assets/tessdata_best
app/assets/tessdata_fast
data/binaries_meta.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces afterInstall.ps1 with a new postInstall.ps1 installer that loads architecture-specific URLs from data/DownloadUrls.psd1, performs conditional download/extract/install flows with telemetry support; removes tessdata submodule gitlinks, deletes data/binaries_meta.json, updates setup.iss to invoke the new script and component set, and bumps lib/adb.js version/path.

Changes

Cohort / File(s) Summary
Installer script & wiring
postInstall.ps1, afterInstall.ps1, setup.iss
afterInstall.ps1 deleted; added postInstall.ps1 implementing architecture detection, component selection, data-driven URL resolution (via data/DownloadUrls.psd1), downloads with retries, extraction/install steps, Nmap/Npcap and GTK handling, error handling, and optional PostHog telemetry. setup.iss updated to call postInstall.ps1, add new components, adjust Run/registry entries, add GetSelectedComponents() and custom messages.
Download/config data
data/DownloadUrls.psd1, data/binaries_meta.json
Added data/DownloadUrls.psd1 (static per-component/per-arch URL mappings). Removed data/binaries_meta.json (previous binaries metadata deleted).
Tessdata submodules
app/assets/tessdata, app/assets/tessdata_best, app/assets/tessdata_fast
Deleted submodule commit/gitlink lines for tessdata variants (submodule references removed).
ADB version & path
lib/adb.js
Bumped exports.VERSIONINFO to "Android Debug Bridge Interface (adb.js) version 0.2.3" and changed default adb path to use SYS.getAppDataDir() + "\\android_platform_tools\\adb.exe".
Installer assets & runtime
app/..., artifacts/...
Installer component list and file/source mappings in setup.iss updated to include artifacts, runtimes (GTK), tessdata variants, python, curl, websocat, yara, wamr, nmap, windivert, android_platform_tools and to route Run/Uninstall entries through artifacts.

Sequence Diagram(s)

sequenceDiagram
    participant Installer as setup.iss
    participant PostInstall as postInstall.ps1
    participant DownloadCfg as data/DownloadUrls.psd1
    participant Telemetry as PostHog
    participant Remote as RemoteBinaries
    participant FS as FileSystem

    Installer->>PostInstall: Launch (Version, TelemetryProvider, Components, DistinctId)
    PostInstall->>DownloadCfg: Load URL mappings
    DownloadCfg-->>PostInstall: Return per-arch URLs

    PostInstall->>PostInstall: Detect native architecture
    PostInstall->>PostInstall: Parse selected components

    alt Telemetry enabled
        PostInstall->>Telemetry: Send app_installed event (non-blocking)
        Telemetry-->>PostInstall: Ack / Error
    end

    loop For each selected component
        PostInstall->>DownloadCfg: Resolve component URL for arch
        DownloadCfg-->>PostInstall: URL or null
        alt URL available
            PostInstall->>Remote: Download (with retries)
            Remote-->>FS: Save archive to TEMP
            PostInstall->>FS: Extract/install into AppData\<component>\
        else URL missing
            PostInstall-->>PostInstall: Log skip
        end
    end

    alt Component has external installer
        PostInstall->>FS: Execute installer (wait) and handle post-steps (VC_redist, Npcap/Nmap)
        FS-->>PostInstall: Install results
    end

    PostInstall->>Installer: Exit 0 / Exit 1
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • postInstall.ps1 (architecture detection, Get-DownloadUrl fallback logic, retry/download/extract semantics, installer invocation and wait handling, non-blocking telemetry).
    • data/DownloadUrls.psd1 (correctness of URL mappings and null fallbacks per-arch).
    • setup.iss wiring (component declarations, Run entries, and parameter passing to postInstall).

Possibly related PRs

Suggested labels

enhancement

Poem

🐇 I hopped through URLs and tiny trails,

I fetched the bits for x64 and arm,
I dug snug burrows in AppData's rails,
Telemetry winked — a soft little charm,
Now installers sleep safe on my farm.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Improve the post-install script' accurately reflects the main objective of the PR, which refactors the installer by replacing afterInstall.ps1 with a new modular postInstall.ps1 that supports telemetry and component selection.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review

qodo-code-review Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Telemetry PII exposure

Description: The installer sends a telemetry event with a persistent machine identifier
($env:COMPUTERNAME) to PostHog by default when a provider and API key are supplied, which
can uniquely identify a device and constitutes potential PII leakage without explicit
opt-in.
postInstall.ps1 [95-121]

Referred Code
# Build single event payload for PostHog /i/v0/e endpoint
# Anonymous event is default: $process_person_profile = false
$body = @{
    api_key     = $TelemetryApiKey
    event       = "app_installed"
    distinct_id = $finalDistinctId
    properties  = @{
        product    = "welsonjs"
        version    = $Version
        os         = "windows"
        source     = "post-install.ps1"
        components = $Components            # Keep raw string here
    }
    timestamp   = (Get-Date).ToString("o")   # ISO 8601 format
} | ConvertTo-Json -Depth 5

try {
    Invoke-RestMethod `
        -Uri "https://us.i.posthog.com/i/v0/e/" `
        -Method Post `
        -ContentType "application/json" `


 ... (clipped 6 lines)
Unsigned downloads

Description: The script downloads binaries directly over HTTPS from multiple third-party URLs (e.g.,
catswords.blob.core.windows.net, GitHub releases, SourceForge) without any integrity
verification (hash/signature), enabling a man-in-the-middle or supply-chain attack if
endpoints are compromised.
DownloadUrls.psd1 [41-45]

Referred Code
websocat = @{
    x64   = "https://catswords.blob.core.windows.net/welsonjs/websocat-1.14.0.x86_64-pc-windows-gnu.zip"
    arm64 = $null  # no official ARM64 build
    x86   = "https://catswords.blob.core.windows.net/welsonjs/websocat-1.14.0.i686-pc-windows-gnu.zip"
}
Hardcoded secret

Description: A hardcoded PostHog API key (PostHogApiKey) is embedded in the installer, exposing a
production telemetry credential that could be abused to inject or spoof events.
setup.iss [103-106]

Referred Code
AppName=WelsonJS
AppVersion=0.2.7.57
PostHogApiKey=phc_pmRHJ0aVEhtULRT4ilexwCjYpGtE9VYRhlA05fwiYt8

Untrusted installer execution

Description: The script executes external installers (Npcap, Nmap, then any found vc_redist.x86.exe)
discovered via recursive search under Program Files without validating publisher or path
hardening, which could allow DLL preloading or path hijack if the search path is
manipulated.
postInstall.ps1 [760-806]

Referred Code
if (Test-ComponentSelected -Name "nmap") {

    # Npcap
    if (Test-Path $NpcapInstaller) {
        Write-Host "[*] Running Npcap installer (wait): $NpcapInstaller"
        Start-Process -FilePath $NpcapInstaller -Wait -ErrorAction Stop
    }
    else {
        Write-Host "[WARN] Npcap installer not found. Skipping Npcap."
    }

    # Nmap
    if (Test-Path $NmapInstaller) {
        Write-Host "[*] Running Nmap installer (wait): $NmapInstaller"
        Start-Process -FilePath $NmapInstaller -Wait -ErrorAction Stop
    }
    else {
        Write-Host "[WARN] Nmap installer not found. Skipping Nmap."
    }

    # Find and run VC_redist.x86.exe inside Nmap installation directory


 ... (clipped 26 lines)
Logic error risks

Description: The Android Platform Tools extraction condition incorrectly checks for WinDivert archive
presence (Test-Path $WinDivertCompressed) before extracting android_platform_tools, which
can lead to unexpected logic paths and leftover mis-extracted archives that may be abused;
fix to check $AndroidPlatformToolsCompressed.
postInstall.ps1 [820-839]

Referred Code
    }
    else {
        Write-Host "[WARN] WinDivert archive not found. Skipping installation."
    }
}
else {
    Write-Host "[*] WinDivert component not selected. Skipping installation."
}

# Android Platform Tools (component: android_platform_tools)
if (Test-ComponentSelected -Name "android_platform_tools") {
    if (Test-Path $WinDivertCompressed) {
        Extract-CompressedFile `
            -CompressedPath $AndroidPlatformToolsCompressed `
            -DestinationDirectory (Join-Path $TargetDir "android_platform_tools")
    }
    else {
        Write-Host "[WARN] Android Platform Tools archive not found. Skipping installation."
    }
}
Binary planting risk

Description: The ADB binary path is constructed using SYS.getAppDataDir() without sanitizing or
validating the resulting path; if the AppData directory is attacker-controlled or the
directory is writable by low-privileged users, this could facilitate binary planting for
execution.
adb.js [94-95]

Referred Code
this.binPath = SYS.getAppDataDir() + "\\android_platform_tools\\platform-tools\\adb.exe";
this._interface.setPrefix(this.binPath);
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: The installer performs critical actions (downloads, installs, registry changes, external
process runs) but only writes console messages without structured audit logs including
user, timestamp, action, and outcome.

Referred Code
Write-Host "    $Url"
Write-Host "    -> $DestinationPath"

# Ensure destination directory exists
$destDir = Split-Path -Parent $DestinationPath
if ($destDir -and -not (Test-Path $destDir)) {
    New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}

$maxRetries = 3
$attempt    = 0
$success    = $false

while (-not $success -and $attempt -lt $maxRetries) {
    $attempt++
    try {
        Invoke-WebRequest -Uri $Url -OutFile $DestinationPath -UseBasicParsing
        $success = $true
    }
    catch {
        Write-Host "[WARN] Download failed (attempt $attempt of $maxRetries): $($_.Exception.Message)"


 ... (clipped 572 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Extraction bug: In the Android Platform Tools install block the script checks the WinDivert archive path
instead of the Android archive path, causing a potential silent logic error despite
try/catch wrappers.

Referred Code
if (Test-ComponentSelected -Name "android_platform_tools") {
    if (Test-Path $WinDivertCompressed) {
        Extract-CompressedFile `
            -CompressedPath $AndroidPlatformToolsCompressed `
            -DestinationDirectory (Join-Path $TargetDir "android_platform_tools")
    }
    else {
        Write-Host "[WARN] Android Platform Tools archive not found. Skipping installation."
    }
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Hardcoded secret: The installer embeds a PostHog API key in cleartext which may be considered sensitive and
could be exposed in logs or binaries.

Referred Code
AppName=WelsonJS
AppVersion=0.2.7.57
PostHogApiKey=phc_pmRHJ0aVEhtULRT4ilexwCjYpGtE9VYRhlA05fwiYt8

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unsanitized URLs: External downloads use URLs from a manifest without integrity verification or signature
checks, potentially exposing supply-chain risk.

Referred Code
# ================================
# COMPRESSED / INSTALLER PATHS
# ================================
$PythonCompressed        = Join-Path $TmpDir "python.zip"
$CurlCompressed          = Join-Path $TmpDir "curl.zip"
$YaraCompressed          = Join-Path $TmpDir "yara.zip"
$WamrArchive             = Join-Path $TmpDir "wamr.tar.gz"
$WebsocatCompressed      = Join-Path $TmpDir "websocat.zip"
$ArtifactsCompressed     = Join-Path $TmpDir "artifacts.zip"
$GtkRuntimeInstaller     = Join-Path $TmpDir "gtk-runtime.exe"
$TessdataCompressed      = Join-Path $TmpDir "tessdata.zip"
$TessdataBestCompressed  = Join-Path $TmpDir "tessdata_best.zip"
$TessdataFastCompressed  = Join-Path $TmpDir "tessdata_fast.zip"
$NpcapInstaller          = Join-Path $TmpDir "npcap-setup.exe"
$NmapInstaller           = Join-Path $TmpDir "nmap-setup.exe"
$GtkServerCompressed     = Join-Path $TmpDir "gtkserver.zip"
$WinDivertCompressed     = Join-Path $TmpDir "windivert.zip"
$AndroidPlatformToolsCompressed = Join-Path $TmpDir "android-platform-tools.zip"

# ================================
# DOWNLOAD PHASE


 ... (clipped 208 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (link)

General comments:

  • In postInstall.ps1 the Android Platform Tools extraction block is checking Test-Path $WinDivertCompressed instead of $AndroidPlatformToolsCompressed, so the Android tools will never be installed even when downloaded; this should be corrected to use the Android archive variable consistently.
  • The download/install handling in postInstall.ps1 is very repetitive per component; consider centralizing the component metadata (archive variable, target folder, extractor type) into a hashtable and looping over it to reduce duplication and make adding/removing components less error-prone.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `postInstall.ps1` the Android Platform Tools extraction block is checking `Test-Path $WinDivertCompressed` instead of `$AndroidPlatformToolsCompressed`, so the Android tools will never be installed even when downloaded; this should be corrected to use the Android archive variable consistently.
- The download/install handling in `postInstall.ps1` is very repetitive per component; consider centralizing the component metadata (archive variable, target folder, extractor type) into a hashtable and looping over it to reduce duplication and make adding/removing components less error-prone.

## Individual Comments

### Comment 1
<location> `postInstall.ps1:568-577` </location>
<code_context>
+    }
+    
+    # Android Platform Tools (component: android_platform_tools)
+    if (Test-ComponentSelected -Name "android_platform_tools") {
+        if (Test-Path $WinDivertCompressed) {
+            Extract-CompressedFile `
+                -CompressedPath $AndroidPlatformToolsCompressed `
</code_context>

<issue_to_address>
**issue (bug_risk):** Android Platform Tools extraction is guarded by the WinDivert archive path, so the Android tools will never be installed.

In the Android Platform Tools block you’re checking `Test-Path $WinDivertCompressed` instead of `$AndroidPlatformToolsCompressed`, so extraction only happens when the WinDivert archive exists and fails when only `android_platform_tools` is selected. This seems like a copy/paste error; please update the `Test-Path` to use `$AndroidPlatformToolsCompressed` to align with the download path.
</issue_to_address>

### Comment 2
<location> `lib/adb.js:94` </location>
<code_context>

     // set the binary path
-    this.binPath = "bin\\platform-tools_r33.0.0-windows\\platform-tools\\adb.exe";
+    this.binPath = SYS.getAppDataDir() + "\\android_platform_tools\\platform-tools\\adb.exe";
     this._interface.setPrefix(this.binPath);
 }
</code_context>

<issue_to_address>
**issue (bug_risk):** New adb binary path assumes the Android Platform Tools component was installed, which may break adb usage if that component is not selected.

The old path targeted a bundled `adb.exe`, but the new path relies on `%APPDATA%\android_platform_tools`, which only exists if the `android_platform_tools` component is installed and its post-install script succeeds. Without that, `adb.js` will reference a missing binary. Please add a runtime check with a clear error if the file is absent, or fall back to the bundled path when the AppData location is unavailable.
</issue_to_address>

### Comment 3
<location> `setup.iss:95` </location>
<code_context>
-Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\afterInstall.ps1"""; WorkingDir: "{app}"; Components: addtools; Flags: waituntilterminated
-Filename: {app}\installService.bat; Components: addtools; Flags: nowait
-Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: addtools; Flags: nowait
+Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\postInstall.ps1"" -TelemetryProvider posthog -TelemetryApiKey ""{cm:PostHogApiKey}"" -Version ""{cm:AppVersion}"" -DistinctId ""{computername}"" -Components ""{code:GetSelectedComponents}"""; WorkingDir: "{app}"; Flags: waituntilterminated
+Filename: {app}\installService.bat; Components: artifacts; Flags: nowait
+Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: artifacts; Flags: nowait
</code_context>

<issue_to_address>
**🚨 issue (security):** Embedding a PostHog API key in the installer increases the risk of key leakage or misuse.

Passing `PostHogApiKey` into `postInstall.ps1` via installer metadata makes it trivially extractable, so anything shipped here should be assumed public. If this key has elevated or non-ingestion permissions, please switch to a public/ingestion-only key plus server-side config, or an anonymous endpoint if supported. At minimum, confirm that this key is restricted and cannot be used for sensitive operations.
</issue_to_address>

### Comment 4
<location> `postInstall.ps1:87-93` </location>
<code_context>
+
+            # Build single event payload for PostHog /i/v0/e endpoint
+            # Anonymous event is default: $process_person_profile = false
+            $body = @{
+                api_key     = $TelemetryApiKey
+                event       = "app_installed"
+                distinct_id = $finalDistinctId
+                properties  = @{
+                    product    = "welsonjs"
+                    version    = $Version
+                    os         = "windows"
+                    source     = "post-install.ps1"
+                    components = $Components            # Keep raw string here
+                }
+                timestamp   = (Get-Date).ToString("o")   # ISO 8601 format
+            } | ConvertTo-Json -Depth 5
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Using the machine name as the telemetry distinct_id has privacy implications and may be more identifying than necessary.

When `DistinctId` is missing, this falls back to `$env:COMPUTERNAME` as PostHog’s `distinct_id`, which is often user- or org-identifying. To keep telemetry effectively anonymous, consider generating a random UUID on first run and persisting it locally, or deriving an ID from a salted hash instead of sending the raw machine name.

```suggestion
        # Determine telemetry distinct id
        # 1. Prefer explicit DistinctId if provided.
        # 2. Otherwise, use a locally persisted anonymous id (do not send raw machine name).
        $anonymousTelemetryId = $null
        try {
            $telemetryIdDirectory = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WelsonJS"
            $telemetryIdFile      = Join-Path -Path $telemetryIdDirectory -ChildPath "telemetry-id.txt"

            if (Test-Path -LiteralPath $telemetryIdFile) {
                $anonymousTelemetryId = Get-Content -LiteralPath $telemetryIdFile -ErrorAction SilentlyContinue | Select-Object -First 1
            }

            if (-not $anonymousTelemetryId -or $anonymousTelemetryId.Trim() -eq "") {
                $anonymousTelemetryId = [guid]::NewGuid().ToString()
                if (-not (Test-Path -LiteralPath $telemetryIdDirectory)) {
                    New-Item -ItemType Directory -Path $telemetryIdDirectory -Force | Out-Null
                }
                $anonymousTelemetryId | Out-File -FilePath $telemetryIdFile -Encoding ASCII -Force
            }
        }
        catch {
            # If anything goes wrong generating/persisting the anonymous id,
            # fall back to a one-off GUID for this run (still avoids machine name).
            if (-not $anonymousTelemetryId -or $anonymousTelemetryId.Trim() -eq "") {
                $anonymousTelemetryId = [guid]::NewGuid().ToString()
            }
        }

        $finalDistinctId = if ($DistinctId -and $DistinctId.Trim() -ne "") {
            $DistinctId
        } else {
            $anonymousTelemetryId
        }

        if ($finalDistinctId -and $finalDistinctId.Trim() -ne "") {
```
</issue_to_address>

### Comment 5
<location> `setup.iss:114` </location>
<code_context>
phc_pmRHJ0aVEhtULRT4ilexwCjYpGtE9VYRhlA05fwiYt8
</code_context>

<issue_to_address>
**security (generic-api-key):** Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

*Source: gitleaks*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread lib/adb.js Outdated

// set the binary path
this.binPath = "bin\\platform-tools_r33.0.0-windows\\platform-tools\\adb.exe";
this.binPath = SYS.getAppDataDir() + "\\android_platform_tools\\platform-tools\\adb.exe";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): New adb binary path assumes the Android Platform Tools component was installed, which may break adb usage if that component is not selected.

The old path targeted a bundled adb.exe, but the new path relies on %APPDATA%\android_platform_tools, which only exists if the android_platform_tools component is installed and its post-install script succeeds. Without that, adb.js will reference a missing binary. Please add a runtime check with a clear error if the file is absent, or fall back to the bundled path when the AppData location is unavailable.

Comment thread setup.iss
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\afterInstall.ps1"""; WorkingDir: "{app}"; Components: addtools; Flags: waituntilterminated
Filename: {app}\installService.bat; Components: addtools; Flags: nowait
Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: addtools; Flags: nowait
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\postInstall.ps1"" -TelemetryProvider posthog -TelemetryApiKey ""{cm:PostHogApiKey}"" -Version ""{cm:AppVersion}"" -DistinctId ""{computername}"" -Components ""{code:GetSelectedComponents}"""; WorkingDir: "{app}"; Flags: waituntilterminated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 issue (security): Embedding a PostHog API key in the installer increases the risk of key leakage or misuse.

Passing PostHogApiKey into postInstall.ps1 via installer metadata makes it trivially extractable, so anything shipped here should be assumed public. If this key has elevated or non-ingestion permissions, please switch to a public/ingestion-only key plus server-side config, or an anonymous endpoint if supported. At minimum, confirm that this key is restricted and cannot be used for sensitive operations.

Comment thread postInstall.ps1
Comment on lines +87 to +93
$finalDistinctId = if ($DistinctId -and $DistinctId.Trim() -ne "") {
$DistinctId
} else {
$env:COMPUTERNAME
}

if ($finalDistinctId -and $finalDistinctId.Trim() -ne "") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 suggestion (security): Using the machine name as the telemetry distinct_id has privacy implications and may be more identifying than necessary.

When DistinctId is missing, this falls back to $env:COMPUTERNAME as PostHog’s distinct_id, which is often user- or org-identifying. To keep telemetry effectively anonymous, consider generating a random UUID on first run and persisting it locally, or deriving an ID from a salted hash instead of sending the raw machine name.

Suggested change
$finalDistinctId = if ($DistinctId -and $DistinctId.Trim() -ne "") {
$DistinctId
} else {
$env:COMPUTERNAME
}
if ($finalDistinctId -and $finalDistinctId.Trim() -ne "") {
# Determine telemetry distinct id
# 1. Prefer explicit DistinctId if provided.
# 2. Otherwise, use a locally persisted anonymous id (do not send raw machine name).
$anonymousTelemetryId = $null
try {
$telemetryIdDirectory = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WelsonJS"
$telemetryIdFile = Join-Path -Path $telemetryIdDirectory -ChildPath "telemetry-id.txt"
if (Test-Path -LiteralPath $telemetryIdFile) {
$anonymousTelemetryId = Get-Content -LiteralPath $telemetryIdFile -ErrorAction SilentlyContinue | Select-Object -First 1
}
if (-not $anonymousTelemetryId -or $anonymousTelemetryId.Trim() -eq "") {
$anonymousTelemetryId = [guid]::NewGuid().ToString()
if (-not (Test-Path -LiteralPath $telemetryIdDirectory)) {
New-Item -ItemType Directory -Path $telemetryIdDirectory -Force | Out-Null
}
$anonymousTelemetryId | Out-File -FilePath $telemetryIdFile -Encoding ASCII -Force
}
}
catch {
# If anything goes wrong generating/persisting the anonymous id,
# fall back to a one-off GUID for this run (still avoids machine name).
if (-not $anonymousTelemetryId -or $anonymousTelemetryId.Trim() -eq "") {
$anonymousTelemetryId = [guid]::NewGuid().ToString()
}
}
$finalDistinctId = if ($DistinctId -and $DistinctId.Trim() -ne "") {
$DistinctId
} else {
$anonymousTelemetryId
}
if ($finalDistinctId -and $finalDistinctId.Trim() -ne "") {

Comment thread setup.iss
function GetSelectedComponents(Value: string): string;
begin
Result := WizardSelectedComponents(False);
end;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (generic-api-key): Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

Source: gitleaks

@qodo-code-review

qodo-code-review Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Reintroduce logic to handle nested directories

The Extract-CompressedFile function in postInstall.ps1 has lost the logic to
"flatten" archives containing a single root folder. This behavior needs to be
restored to prevent dependencies from being installed in an incorrect, nested
directory structure.

Examples:

postInstall.ps1 [280-315]
function Extract-CompressedFile {
    param(
        [Parameter(Mandatory = $true)]
        [string]$CompressedPath,
        [Parameter(Mandatory = $true)]
        [string]$DestinationDirectory
    )

    Write-Host "[*] Extracting compressed file:"
    Write-Host "    $CompressedPath"

 ... (clipped 26 lines)

Solution Walkthrough:

Before:

function Extract-CompressedFile($CompressedPath, $DestinationDirectory) {
    # ...
    $tmpExtractDir = Join-Path $DestinationDirectory "_tmp_extract"
    Ensure-EmptyDirectory -Path $tmpExtractDir

    # Extracts archive content into the temp dir
    [System.IO.Compression.ZipFile]::ExtractToDirectory($CompressedPath, $tmpExtractDir)

    # Moves top-level items from temp dir to destination.
    # If archive has a single root folder, it gets moved,
    # creating an extra nested directory level.
    Get-ChildItem -Path $tmpExtractDir -Force | ForEach-Object {
        $targetPath = Join-Path $DestinationDirectory $_.Name
        # ...
        Move-Item -Path $_.FullName -Destination $targetPath
    }
    # ...
}

After:

function Extract-CompressedFile($CompressedPath, $DestinationDirectory) {
    # ...
    $tmpExtractDir = Join-Path $DestinationDirectory "_tmp_extract"
    # ...
    [System.IO.Compression.ZipFile]::ExtractToDirectory($CompressedPath, $tmpExtractDir)

    $entries = Get-ChildItem -Path $tmpExtractDir -Force
    
    # Check if archive contains a single root directory
    if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) {
        # Flatten: move contents of the single root directory
        Get-ChildItem -Path $entries[0].FullName -Force | ForEach-Object {
            Move-Item -Path $_.FullName -Destination (Join-Path $DestinationDirectory $_.Name) -Force
        }
    } else {
        # Move all top-level items as-is
        $entries | ForEach-Object {
            Move-Item -Path $_.FullName -Destination (Join-Path $DestinationDirectory $_.Name) -Force
        }
    }
    # ...
}
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical regression in the Extract-CompressedFile function that would break the installation of most components, as they are archived with a single root directory.

High
Possible issue
Fix incorrect variable in path check
Suggestion Impact:The commit updated the condition to check Test-Path $AndroidPlatformToolsCompressed instead of $WinDivertCompressed for the android_platform_tools component.

code diff:

@@ -828,7 +842,7 @@
     
     # Android Platform Tools (component: android_platform_tools)
     if (Test-ComponentSelected -Name "android_platform_tools") {
-        if (Test-Path $WinDivertCompressed) {
+        if (Test-Path $AndroidPlatformToolsCompressed) {
             Extract-CompressedFile `
                 -CompressedPath $AndroidPlatformToolsCompressed `
                 -DestinationDirectory (Join-Path $TargetDir "android_platform_tools")

Fix a copy-paste error in the installation logic for android_platform_tools by
checking for the correct variable, $AndroidPlatformToolsCompressed, instead of
$WinDivertCompressed.

postInstall.ps1 [829-839]

 # Android Platform Tools (component: android_platform_tools)
 if (Test-ComponentSelected -Name "android_platform_tools") {
-    if (Test-Path $WinDivertCompressed) {
+    if (Test-Path $AndroidPlatformToolsCompressed) {
         Extract-CompressedFile `
             -CompressedPath $AndroidPlatformToolsCompressed `
             -DestinationDirectory (Join-Path $TargetDir "android_platform_tools")
     }
     else {
         Write-Host "[WARN] Android Platform Tools archive not found. Skipping installation."
     }
 }

[Suggestion processed]

Suggestion importance[1-10]: 9

__

Why: This suggestion identifies a clear copy-paste bug where the if condition checks the wrong variable ($WinDivertCompressed), which would prevent the android_platform_tools component from ever being installed.

High
Prevent post-install race condition

To prevent a race condition, move the execution of installService.bat and
WelsonJS.Launcher.exe from the [Run] section of setup.iss into the
postInstall.ps1 script.

setup.iss [94-97]

 [Run]
 ; Filename: {app}\bin\gtk2-runtime-2.24.33-2021-01-30-ts-win64.exe;
 ; Filename: {app}\bin\nmap-7.92\VC_redist.x86.exe;
 ; Filename: {app}\bin\nmap-7.92\npcap-1.50.exe;
 Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\postInstall.ps1"" -TelemetryProvider posthog -TelemetryApiKey ""{cm:PostHogApiKey}"" -Version ""{cm:AppVersion}"" -DistinctId ""{computername}"" -Components ""{code:GetSelectedComponents}"""; WorkingDir: "{app}"; Flags: waituntilterminated
-Filename: {app}\installService.bat; Components: artifacts; Flags: nowait
-Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: artifacts; Flags: nowait
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out a potential race condition where the installer might try to run files before they are downloaded and extracted by the postInstall.ps1 script, and moving the logic is a valid improvement.

Medium
Improve archive extraction logic
Suggestion Impact:The commit added logic to detect a single top-level directory in the extracted archive and set the source root accordingly, effectively flattening such archives before moving contents to the destination.

code diff:

+    $entries    = Get-ChildItem -Path $tmpExtractDir -Force
+    $SourceRoot = $tmpExtractDir
+
+    if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) {
+        # ZIP contains exactly one top-level folder → unwrap that folder
+        $SourceRoot = $entries[0].FullName
+        Write-Host "[*] Detected single root folder inside zip: $($entries[0].Name)"
+        Write-Host "[*] Unwrapping folder content..."
+    }
+    else {
+        Write-Host "[*] Extracting multi-item archive (no root folder unwrapping needed)."
+    }
+
+    # Move all items from source root to final destination
+    Get-ChildItem -Path $SourceRoot -Force | ForEach-Object {
         $targetPath = Join-Path $DestinationDirectory $_.Name
+
         if (Test-Path $targetPath) {
-            # If the target exists, remove it (file or directory)
             Remove-Item -Path $targetPath -Recurse -Force
         }
         Move-Item -Path $_.FullName -Destination $targetPath
     }
 
-    # Remove the temporary extraction directory
+    # Cleanup
     Remove-Item -Path $tmpExtractDir -Recurse -Force

Modify the Extract-CompressedFile function to handle archives with a single root
directory by flattening the contents into the destination, preventing the
creation of an extra subfolder.

postInstall.ps1 [299-314]

 # Extract archive
 Add-Type -AssemblyName System.IO.Compression.FileSystem
 [System.IO.Compression.ZipFile]::ExtractToDirectory($CompressedPath, $tmpExtractDir)
 
-# Move all items from temp folder to final destination
-Get-ChildItem -Path $tmpExtractDir -Force | ForEach-Object {
-    $targetPath = Join-Path $DestinationDirectory $_.Name
-    if (Test-Path $targetPath) {
-        # If the target exists, remove it (file or directory)
-        Remove-Item -Path $targetPath -Recurse -Force
+# Check for single root directory to flatten the structure
+$entries = Get-ChildItem -Path $tmpExtractDir -Force
+
+if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) {
+    # Single root directory: move its contents to the destination
+    Write-Host "[*] Archive has a single root directory. Flattening..."
+    Get-ChildItem -Path $entries[0].FullName -Force | ForEach-Object {
+        Move-Item -Path $_.FullName -Destination $DestinationDirectory -Force
     }
-    Move-Item -Path $_.FullName -Destination $targetPath
+}
+else {
+    # Multiple top-level entries: move them all to the destination
+    Write-Host "[*] Archive has multiple top-level entries. Moving all..."
+    $entries | ForEach-Object {
+        Move-Item -Path $_.FullName -Destination $DestinationDirectory -Force
+    }
 }
 
 # Remove the temporary extraction directory
 Remove-Item -Path $tmpExtractDir -Recurse -Force

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that the new extraction logic lost the "flattening" feature for archives with a single root directory, and reintroducing it improves the installation's robustness and predictability.

Low
Learned
best practice
Validate and normalize parameters early

Validate and normalize parameters upfront (e.g., non-empty strings), returning
early for invalid telemetry settings to keep logic simple and safe.

postInstall.ps1 [8-91]

 param(
-    [string]$TelemetryProvider = "",
+    [ValidateNotNullOrEmpty()][string]$TelemetryProvider = "",
     [string]$TelemetryApiKey   = "",
     [string]$Version           = "",
     [string]$DistinctId        = "",
     [string]$Components        = ""
 )
-...
-if ($TelemetryProvider -and $TelemetryProvider.ToLower() -eq "posthog") {
 
-    # Skip telemetry if API key is missing
-    if (-not $TelemetryApiKey -or $TelemetryApiKey.Trim() -eq "") {
-        # No-op: continue script
-    }
-    else {
-        # Resolve distinct ID (fallback to machine name)
-        $finalDistinctId = if ($DistinctId -and $DistinctId.Trim() -ne "") {
-            $DistinctId
-        } else {
-            $env:COMPUTERNAME
-        }
+function Normalize-NonEmpty {
+    param([string]$v)
+    if ($null -eq $v) { return "" }
+    return $v.Trim()
+}
 
+$TelemetryProvider = (Normalize-NonEmpty $TelemetryProvider).ToLowerInvariant()
+$TelemetryApiKey   = Normalize-NonEmpty $TelemetryApiKey
+$Version           = Normalize-NonEmpty $Version
+$DistinctId        = Normalize-NonEmpty $DistinctId
+$Components        = Normalize-NonEmpty $Components
+
+if ($TelemetryProvider -ne "posthog" -or $TelemetryApiKey -eq "") {
+    $TelemetryProvider = ""
+}
+
+if ($TelemetryProvider -eq "posthog") {
+    $finalDistinctId = (if ($DistinctId -ne "") { $DistinctId } else { $env:COMPUTERNAME })
+    if ([string]::IsNullOrWhiteSpace($finalDistinctId)) { $finalDistinctId = [guid]::NewGuid().ToString() }
+    ...
+}
+

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Prefer specific input validation and early returns for user-supplied parameters to avoid null/empty or malformed values.

Low
  • Update

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
data/DownloadUrls.psd1 (1)

14-18: Third-party source for curl x86 build.

The x86 curl URL points to a SourceForge project (muldersoft/cURL) rather than the official curl.se distribution. Consider the supply chain security implications of using third-party builds, or document why the official source doesn't provide x86 builds.

postInstall.ps1 (1)

183-210: ARM architecture detection may need refinement.

Architecture value 5 represents 32-bit ARM, not necessarily ARM64. On Windows ARM64, the processor may report differently. Consider using $env:PROCESSOR_ARCHITECTURE as an additional check, which returns ARM64 on 64-bit ARM systems.

 switch ($proc.Architecture) {
     0       { $arch = "x86"   }   # 32-bit Intel/AMD
-    5       { $arch = "arm64" }   # treat ARM as arm64 target
+    5       {                     # ARM variant
+        if ([System.Environment]::Is64BitOperatingSystem) {
+            $arch = "arm64"
+        } else {
+            $arch = "x86"   # fallback for 32-bit ARM
+        }
+    }
     9       { $arch = "x64"   }   # 64-bit Intel/AMD
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35fefc9 and 3058d6c.

📒 Files selected for processing (9)
  • afterInstall.ps1 (0 hunks)
  • app/assets/tessdata (0 hunks)
  • app/assets/tessdata_best (0 hunks)
  • app/assets/tessdata_fast (0 hunks)
  • data/DownloadUrls.psd1 (1 hunks)
  • data/binaries_meta.json (0 hunks)
  • lib/adb.js (3 hunks)
  • postInstall.ps1 (1 hunks)
  • setup.iss (4 hunks)
💤 Files with no reviewable changes (5)
  • app/assets/tessdata
  • afterInstall.ps1
  • app/assets/tessdata_fast
  • app/assets/tessdata_best
  • data/binaries_meta.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Sourcery review
🔇 Additional comments (9)
data/DownloadUrls.psd1 (2)

1-121: Well-structured centralized configuration.

The URL configuration file is well-organized with clear section comments and proper handling of architecture-specific builds with $null for unsupported platforms. The "any" fallback pattern for architecture-independent packages (tessdata) is a good design choice.


5-9: No action needed for Python version selection. Python 3.14.0 is a stable release published October 7, 2025, and is suitable for production use. While the x86 variant uses the older 3.13.9, using different stable versions across architectures is acceptable if intentional (e.g., due to architecture-specific requirements or testing considerations). If version consistency is desired, updating x86 to 3.14.0 would be appropriate, but this is an optional optimization rather than a stability concern.

setup.iss (2)

104-105: Telemetry API key exposure is acceptable.

The PostHog API key (phc_...) is a public project API key designed for client-side use. This is the expected pattern for anonymous analytics telemetry.


111-114: LGTM - GetSelectedComponents implementation.

The function correctly uses WizardSelectedComponents(False) to return a comma-separated list of selected components without hierarchy prefixes, which aligns with the PowerShell script's parsing logic.

postInstall.ps1 (4)

86-91: COMPUTERNAME as telemetry identifier.

Using $env:COMPUTERNAME as the distinct_id provides machine-level correlation. While not directly identifying individuals, some organizations consider machine names sensitive. The setup.iss passes {computername} explicitly, so this is intentional. Users who prefer more anonymity could modify the installer.


292-294: Extraction clears existing directory contents.

Extract-CompressedFile calls Ensure-EmptyDirectory which removes existing content in the destination directory before extraction. This is intentional for clean installs but could cause data loss if users have customized files in these directories.


239-278: Good retry logic with exponential backoff consideration.

The download retry logic (3 attempts, 5-second delay) is solid. For robustness against transient network issues, consider exponential backoff, though the current fixed delay is acceptable for an installer.


854-860: Clean completion handling.

The script exits with appropriate codes (0 for success, 1 for failure) and provides clear completion messaging.

lib/adb.js (1)

94-94: ADB binary path is correctly aligned with the archive structure.

The Google-hosted platform-tools archive extracts with platform-tools/ at the root level, and adb.exe is located at platform-tools/adb.exe. The hardcoded path SYS.getAppDataDir() + "\\android_platform_tools\\platform-tools\\adb.exe" correctly accounts for both the extraction directory (android_platform_tools) and the archive's internal structure. No path adjustment is needed.

Comment thread postInstall.ps1
Comment thread setup.iss Outdated
Fix mistypos in the post-install script, Fix decompression process when the file contains single root

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
setup.iss (2)

43-43: Typo in component description.

"Download and Nmap and Npcap" should be "Download Nmap and Npcap".


104-105: API key embedded in installer metadata.

This key is exposed in the compiled installer and should be treated as public. Confirm this is an ingestion-only key with minimal permissions.

postInstall.ps1 (1)

87-91: Privacy consideration: machine name as telemetry identifier.

Using $env:COMPUTERNAME as the fallback distinct_id may be more identifying than intended for anonymous telemetry.

🧹 Nitpick comments (3)
lib/adb.js (1)

94-95: Add validation for the adb binary path.

The path now assumes android_platform_tools was installed to AppData. If this component wasn't selected during installation, calls to getDevices(), pull(), push(), etc. will fail. While sendShell silently catches errors, other methods don't handle missing binaries gracefully.

Consider adding a validation helper or fallback:

+    this.validateBinPath = function() {
+        var FSO = CreateObject("Scripting.FileSystemObject");
+        if (!FSO.FileExists(this.binPath)) {
+            throw new Error("ADB binary not found at: " + this.binPath + 
+                ". Ensure 'Android Platform Tools' component was installed.");
+        }
+        return this;
+    };
+
     // set the binary path
     this.binPath = SYS.getAppDataDir() + "\\android_platform_tools\\adb.exe";
     this._interface.setPrefix(this.binPath);

Alternatively, consumers can use setBinPath() to override with a custom location when the default isn't available.

postInstall.ps1 (2)

700-711: Consider silent installation flags for GTK runtime.

The installer runs without arguments, which may display a GUI requiring user interaction. For unattended installations, consider adding silent flags if supported.

         if (Test-Path $GtkRuntimeInstaller) {
             Write-Host "[*] Running GTK runtime installer (wait): $GtkRuntimeInstaller"
-            Start-Process -FilePath $GtkRuntimeInstaller -Wait -ErrorAction Stop
+            Start-Process -FilePath $GtkRuntimeInstaller -ArgumentList "/S" -Wait -ErrorAction Stop
         }

Verify the correct silent flag for the GTK runtime installer (commonly /S or /silent).


776-792: Npcap/Nmap installers may require user interaction.

These installers are executed without silent flags. Npcap in particular often prompts for driver installation approval. For fully automated installs, consider:

         if (Test-Path $NpcapInstaller) {
             Write-Host "[*] Running Npcap installer (wait): $NpcapInstaller"
-            Start-Process -FilePath $NpcapInstaller -Wait -ErrorAction Stop
+            # /S for silent, /winpcap_mode for compatibility
+            Start-Process -FilePath $NpcapInstaller -ArgumentList "/S" -Wait -ErrorAction Stop
         }

Note: Silent Npcap installation may require additional flags. Verify with Npcap documentation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3058d6c and c37d424.

📒 Files selected for processing (3)
  • lib/adb.js (3 hunks)
  • postInstall.ps1 (1 hunks)
  • setup.iss (4 hunks)
🧰 Additional context used
🪛 Gitleaks (8.29.1)
setup.iss

[high] 105-105: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Sourcery review
🔇 Additional comments (9)
lib/adb.js (1)

136-136: LGTM on version bump.

Version increment appropriately reflects the path resolution change.

setup.iss (2)

111-114: LGTM on component selection integration.

GetSelectedComponents correctly returns the comma-separated component list for the PowerShell script.


29-45: Well-structured component system.

The modular component definitions with appropriate type assignments (full, compact, custom) provide good flexibility for users.

postInstall.ps1 (6)

843-856: LGTM - Android Platform Tools extraction uses correct variable.

The Test-Path check correctly references $AndroidPlatformToolsCompressed.


257-278: Good retry logic implementation.

The 3-attempt retry with delay is reasonable. For robustness, consider exponential backoff for future improvements, but current implementation is acceptable.


292-298: Note: Extraction clears destination directory.

Ensure-EmptyDirectory on line 293 will remove any pre-existing content in the destination. This is likely intentional for clean installations but could cause data loss if users have customized files in these directories.

Confirm this is the intended behavior for component updates/reinstalls.


595-603: Good error handling with proper exit codes.

The structured try/catch with exit 1 on failure ensures the installer properly reports failures to the setup process.


148-170: Clean component selection implementation.

The Test-ComponentSelected helper with $AllComponentsSelected fallback provides good backward compatibility when no components are specified.


30-45: Robust data file loading with fallback.

Graceful handling of missing or malformed DownloadUrls.psd1 ensures the script doesn't crash, with appropriate warnings.

Comment thread postInstall.ps1
Comment on lines +192 to +197
switch ($proc.Architecture) {
0 { $arch = "x86" } # 32-bit Intel/AMD
5 { $arch = "arm64" } # treat ARM as arm64 target
9 { $arch = "x64" } # 64-bit Intel/AMD
default { $arch = "x86" } # fallback
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Win32_Processor Architecture property values Microsoft documentation

💡 Result:

Win32_Processor Architecture (uint16) values (per Microsoft Docs):

  • 0 = x86. [1]
  • 1 = MIPS. [1]
  • 2 = Alpha. [1]
  • 3 = PowerPC. [1]
  • 5 = ARM. [1]
  • 6 = ia64 (Itanium). [1]
  • 9 = x64. [1]
  • 12 = ARM64. [1]

Source: Microsoft Learn — Win32_Processor class (Architecture property). [1]


Correct ARM architecture mapping.

Per Microsoft documentation, Win32_Processor.Architecture value 5 is ARM (32-bit), while 12 is ARM64 (64-bit). The current mapping of 5 → arm64 is incorrect and will cause 64-bit ARM64 binaries to be downloaded on 32-bit ARM systems. Additionally, Architecture value 12 (ARM64) is not handled and will fall back to x86.

🤖 Prompt for AI Agents
In postInstall.ps1 around lines 192 to 197, the Win32_Processor.Architecture
mapping is wrong: value 5 is ARM (32-bit) and value 12 is ARM64 (64-bit), but
the current switch maps 5 → arm64 and omits 12; update the switch to map 5 to
"arm", 12 to "arm64", keep 9 → "x64" and 0 → "x86", and retain a sensible
default (e.g., "x86") so 32-bit ARM systems receive arm binaries and ARM64
systems receive arm64 binaries.

Add logo to postInstall.ps1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
postInstall.ps1 (2)

104-108: Privacy issue: Machine name used as telemetry identifier.

This fallback to $env:COMPUTERNAME exposes the machine name in telemetry, which is user-identifying and not anonymous. A previous review suggested generating a persistent random UUID instead.

Based on past review feedback, consider generating and persisting an anonymous UUID rather than sending the raw machine name.


209-214: Critical: Incorrect ARM architecture mapping.

Win32_Processor.Architecture value 5 is ARM (32-bit), not ARM64. Value 12 is ARM64 (64-bit) but is not handled and will fall back to x86. This causes incorrect binary downloads on ARM systems.

Per Microsoft documentation, update the switch to:

        switch ($proc.Architecture) {
            0       { $arch = "x86"   }   # 32-bit Intel/AMD
-            5       { $arch = "arm64" }   # treat ARM as arm64 target
+            5       { $arch = "arm"   }   # 32-bit ARM
            9       { $arch = "x64"   }   # 64-bit Intel/AMD
+            12      { $arch = "arm64" }   # 64-bit ARM
            default { $arch = "x86"   }   # fallback
        }
🧹 Nitpick comments (5)
postInstall.ps1 (5)

281-281: Consider adding timeout to prevent indefinite hangs.

Invoke-WebRequest without a timeout can hang indefinitely on unresponsive endpoints. Adding -TimeoutSec would improve resilience.

-            Invoke-WebRequest -Uri $Url -OutFile $DestinationPath -UseBasicParsing
+            Invoke-WebRequest -Uri $Url -OutFile $DestinationPath -UseBasicParsing -TimeoutSec 300

406-488: Optional: Reduce code duplication in download phase.

The download logic is highly repetitive across components. Consider extracting into a helper function to improve maintainability.

Example refactoring:

function Download-Component {
    param(
        [string]$ComponentName,
        [string]$DestinationPath
    )
    
    if (Test-ComponentSelected -Name $ComponentName) {
        $url = Get-DownloadUrl -Component $ComponentName -Arch $arch
        if ($url) {
            Download-File -Url $url -DestinationPath $DestinationPath
        }
        else {
            Write-Host "[*] $ComponentName URL not available for arch: $arch. Skipping download."
        }
    }
    else {
        Write-Host "[*] $ComponentName component not selected. Skipping download."
    }
}

# Then use: Download-Component -ComponentName "python" -DestinationPath $PythonCompressed

835-835: Consider logging VC_redist installer errors.

Using -ErrorAction SilentlyContinue suppresses installer errors. If the VC redistributable is required, installation failures will go unnoticed.

-            Start-Process -FilePath $vcRedist.FullName -Wait -ErrorAction SilentlyContinue
+            try {
+                Start-Process -FilePath $vcRedist.FullName -Wait -ErrorAction Stop
+            }
+            catch {
+                Write-Host "[WARN] VC_redist.x86 installer failed: $($_.Exception.Message)"
+            }

716-720: Consider checking for administrator privileges.

Installers like GTK runtime, Npcap, and Nmap typically require administrator privileges. The script doesn't check for or request elevation, which may cause silent failures.

Add an admin check at the script start:

function Test-Administrator {
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

if (-not (Test-Administrator)) {
    Write-Host "[WARN] Some components may require administrator privileges to install."
    Write-Host "[WARN] Consider running this script as administrator."
}

Also applies to: 794-796, 803-805


256-295: Recommend adding checksum validation for downloaded files.

The script downloads and executes files without verifying their integrity. If URLs in DownloadUrls.psd1 are compromised or DNS is poisoned, malicious files could be installed.

Consider adding SHA256 checksums to DownloadUrls.psd1 and validating after download:

function Verify-FileChecksum {
    param(
        [string]$FilePath,
        [string]$ExpectedHash
    )
    
    if (-not $ExpectedHash) {
        Write-Host "[WARN] No checksum provided for verification."
        return $true
    }
    
    $actualHash = (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash
    if ($actualHash -eq $ExpectedHash) {
        Write-Host "[*] Checksum verified: $FilePath"
        return $true
    }
    else {
        Write-Host "[ERROR] Checksum mismatch for $FilePath"
        Write-Host "        Expected: $ExpectedHash"
        Write-Host "        Actual  : $actualHash"
        return $false
    }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c37d424 and e3ec367.

📒 Files selected for processing (1)
  • postInstall.ps1 (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Analyze (javascript)

Fix the architecture number
@sonarqubecloud

sonarqubecloud Bot commented Dec 1, 2025

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
postInstall.ps1 (2)

104-108: Privacy concern: Machine name used as telemetry ID (duplicate issue).

This issue was previously flagged but remains unaddressed. Using $env:COMPUTERNAME as the fallback for distinct_id can expose identifying information. The previous suggestion to generate and persist a random UUID instead of sending the raw machine name is still valid and should be implemented for better privacy.


209-214: Critical: Missing ARM 32-bit architecture support (duplicate issue).

This issue was previously flagged but remains unaddressed. The switch statement is missing case 5 for ARM (32-bit). Per Microsoft documentation, Win32_Processor.Architecture value 5 represents ARM (32-bit), while 12 represents ARM64 (64-bit). The current code only handles 12, which means 32-bit ARM systems will incorrectly fall back to x86 binaries.

The previous review suggested adding case 5:

         switch ($proc.Architecture) {
             0       { $arch = "x86"   }   # 32-bit Intel/AMD
+            5       { $arch = "arm"   }   # 32-bit ARM
             12      { $arch = "arm64" }   # treat ARM as arm64 target
             9       { $arch = "x64"   }   # 64-bit Intel/AMD
             default { $arch = "x86"   }   # fallback
         }
🧹 Nitpick comments (1)
postInstall.ps1 (1)

835-835: Consider consistent error handling for installer execution.

The VC_redist installer uses -ErrorAction SilentlyContinue (line 835) while other installers (GTK runtime at line 720, Npcap at line 796, Nmap at line 805) use -ErrorAction Stop. If this is intentional because VC_redist is optional, consider adding a comment to clarify. Otherwise, using consistent error handling would improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3ec367 and 046bb14.

📒 Files selected for processing (1)
  • postInstall.ps1 (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Analyze (javascript)

Comment thread postInstall.ps1
Comment on lines +201 to +202
# 0 = x86, 5 = ARM, 9 = x64
# https://learn.microsoft.com/windows/win32/cimwin32prov/win32-processor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading comment about architecture values.

The comment is incomplete and doesn't mention value 12 (ARM64), which is actually handled in the code below. Per Microsoft documentation, the complete mapping should include: 0=x86, 5=ARM (32-bit), 9=x64, 12=ARM64.

Update the comment:

-    # 0 = x86, 5 = ARM, 9 = x64
-    # https://learn.microsoft.com/windows/win32/cimwin32prov/win32-processor
+    # 0 = x86, 5 = ARM (32-bit), 9 = x64, 12 = ARM64 (64-bit)
+    # https://learn.microsoft.com/windows/win32/cimwin32prov/win32-processor
🤖 Prompt for AI Agents
In postInstall.ps1 around lines 201 to 202, the architecture comment is
incomplete and omits the value 12 (ARM64); update the comment to list the full
mapping per Microsoft docs: 0 = x86, 5 = ARM (32-bit), 9 = x64, 12 = ARM64, and
keep the reference URL as-is.

Comment thread postInstall.ps1
Comment on lines +405 to +620
try {
# Python (component: python)
if (Test-ComponentSelected -Name "python") {
$url = Get-DownloadUrl -Component "python" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $PythonCompressed
}
else {
Write-Host "[*] Python URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] Python component not selected. Skipping download."
}

# curl (component: curl)
if (Test-ComponentSelected -Name "curl") {
$url = Get-DownloadUrl -Component "curl" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $CurlCompressed
}
else {
Write-Host "[*] curl URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] curl component not selected. Skipping download."
}

# YARA (component: yara)
if (Test-ComponentSelected -Name "yara") {
$url = Get-DownloadUrl -Component "yara" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $YaraCompressed
}
else {
Write-Host "[*] YARA URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] YARA component not selected. Skipping download."
}

# WAMR (component: wamr)
if (Test-ComponentSelected -Name "wamr") {
$url = Get-DownloadUrl -Component "wamr" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $WamrArchive
}
else {
Write-Host "[*] WAMR URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] WAMR component not selected. Skipping download."
}

# websocat (component: websocat)
if (Test-ComponentSelected -Name "websocat") {
$url = Get-DownloadUrl -Component "websocat" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $WebsocatCompressed
}
else {
Write-Host "[*] websocat URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] websocat component not selected. Skipping download."
}

# artifacts (component: artifacts)
if (Test-ComponentSelected -Name "artifacts") {
$url = Get-DownloadUrl -Component "artifacts" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $ArtifactsCompressed
}
else {
Write-Host "[*] artifacts URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] artifacts component not selected. Skipping download."
}

# GTK3 runtime (component: gtk3runtime)
if (Test-ComponentSelected -Name "gtk3runtime") {
$url = Get-DownloadUrl -Component "gtk3runtime" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $GtkRuntimeInstaller
}
else {
Write-Host "[*] gtk3runtime URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] gtk3runtime component not selected. Skipping download."
}

# GTK server (component: gtkserver)
if (Test-ComponentSelected -Name "gtkserver") {
$url = Get-DownloadUrl -Component "gtkserver" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $GtkServerCompressed
}
else {
Write-Host "[*] gtkserver URL not available for arch: $arch. Skipping download."
}
}
else {
Write-Host "[*] gtkserver component not selected. Skipping download."
}

# tessdata (component: tessdata)
if (Test-ComponentSelected -Name "tessdata") {
$url = Get-DownloadUrl -Component "tessdata" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $TessdataCompressed
}
else {
Write-Host "[*] tessdata URL not available. Skipping download."
}
}
else {
Write-Host "[*] tessdata component not selected. Skipping download."
}

# tessdata_best (component: tessdata_best)
if (Test-ComponentSelected -Name "tessdata_best") {
$url = Get-DownloadUrl -Component "tessdata_best" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $TessdataBestCompressed
}
else {
Write-Host "[*] tessdata_best URL not available. Skipping download."
}
}
else {
Write-Host "[*] tessdata_best component not selected. Skipping download."
}

# tessdata_fast (component: tessdata_fast)
if (Test-ComponentSelected -Name "tessdata_fast") {
$url = Get-DownloadUrl -Component "tessdata_fast" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $TessdataFastCompressed
}
else {
Write-Host "[*] tessdata_fast URL not available. Skipping download."
}
}
else {
Write-Host "[*] tessdata_fast component not selected. Skipping download."
}

# Nmap bundle (component: nmap) – includes Npcap + Nmap installer
if (Test-ComponentSelected -Name "nmap") {
# Npcap
$url = Get-DownloadUrl -Component "npcap" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $NpcapInstaller
}
else {
Write-Host "[*] npcap URL not available. Skipping npcap download."
}

# Nmap
$url = Get-DownloadUrl -Component "nmap" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $NmapInstaller
}
else {
Write-Host "[*] nmap URL not available. Skipping nmap download."
}
}
else {
Write-Host "[*] nmap component not selected. Skipping Npcap/Nmap download."
}

# windivert (component: windivert)
if (Test-ComponentSelected -Name "windivert") {
$url = Get-DownloadUrl -Component "windivert" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $WinDivertCompressed
}
else {
Write-Host "[*] WinDivert URL not available. Skipping download."
}
}
else {
Write-Host "[*] WinDivert component not selected. Skipping download."
}

# Android Platform Tools (component: android_platform_tools)
if (Test-ComponentSelected -Name "android_platform_tools") {
$url = Get-DownloadUrl -Component "android_platform_tools" -Arch $arch
if ($url) {
Download-File -Url $url -DestinationPath $AndroidPlatformToolsCompressed
}
else {
Write-Host "[*] Android Platform Tools URL not available. Skipping download."
}
}
else {
Write-Host "[*] Android Platform Tools component not selected. Skipping download."
}
}
catch {
Write-Host "[FATAL] Download phase failed."
if ($_ -is [System.Exception]) {
Write-Host $_.Exception.Message
} else {
Write-Host $_
}
exit 1
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider adding checksum validation for downloaded files.

Downloaded files are not validated for integrity using checksums or signatures. This creates a security risk if the download source is compromised or subject to man-in-the-middle attacks. While this may be acceptable for an initial implementation, consider storing expected checksums in DownloadUrls.psd1 and validating downloads before extraction.

Example implementation approach:

function Verify-FileChecksum {
    param(
        [string]$FilePath,
        [string]$ExpectedHash,
        [string]$Algorithm = "SHA256"
    )
    
    $actualHash = (Get-FileHash -Path $FilePath -Algorithm $Algorithm).Hash
    if ($actualHash -ne $ExpectedHash) {
        throw "Checksum mismatch for $FilePath"
    }
}

Then update DownloadUrls.psd1 to include hashes alongside URLs and validate after each download.

🤖 Prompt for AI Agents
In postInstall.ps1 around lines 405 to 620, downloaded artifacts are not
validated; add checksum validation by (1) extending DownloadUrls.psd1 to include
an expected hash (and algorithm, default SHA256) alongside each URL, (2)
implementing a Verify-FileChecksum function that computes Get-FileHash for the
downloaded file and compares it to the expected hash (throwing on mismatch), (3)
calling Verify-FileChecksum immediately after each successful Download-File call
(log a clear error and exit with non-zero on mismatch), and (4) ensure the catch
block reports checksum failures clearly; keep behavior configurable so missing
hashes skip verification with a warning.

@gnh1201
gnh1201 merged commit 19f6bd1 into master Dec 1, 2025
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant