Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,23 @@ jobs:
- name: npm ci
run: npm ci

- name: Tesseract broker test (Windows)
if: runner.os == 'Windows'
shell: pwsh
env:
CARGO_TERM_COLOR: never
run: |
$output = & cargo test --manifest-path src-tauri/Cargo.toml --lib adapters::driven::plugin::tesseract_broker_tests::tesseract_windows_fixture_receives_only_fixed_arguments -- --exact 2>&1
$exitCode = $LASTEXITCODE
$output | Write-Output
if ($exitCode -ne 0) {
exit $exitCode
}
$passed = @($output | Select-String -Pattern '^test result: ok\. 1 passed; 0 failed;')
if ($passed.Count -ne 1) {
throw 'The Windows Tesseract regression test did not run exactly once.'
}

- name: Tauri build
id: tauri-build
shell: bash
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/plugin-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ jobs:
test -s "${WASM_PATH}"

case "${PACKAGE_NAME}" in
vortex-mod-captcha-anticaptcha)
required="can_solve solve get_balance"
;;
vortex-mod-captcha-browser|vortex-mod-captcha-ocr)
required="can_solve solve"
;;
vortex-mod-containers)
required="can_decrypt detect decrypt"
;;
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CAPTCHA pipeline: persistent manual challenge queue, solve/skip/retry
actions, timeout handling, automatic download resumption, compact image
transport, bounded plugin inputs, and redacted challenge history (MAT-140).
- CAPTCHA solvers: configurable OCR → AntiCaptcha → browser cascade, typed
Tesseract host broker, keyring-backed AntiCaptcha credentials, persisted
per-solver attempts, and a dedicated human-assisted WebView (MAT-141).

### Security

Expand All @@ -23,6 +26,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- CAPTCHA browser windows now close directly from persisted terminal command
flows instead of relying on a lossy event subscriber (MAT-141).
- The Windows Tesseract broker regression fixture now returns success after
emitting its simulated OCR solution (MAT-141).
- CAPTCHA solver review hardening now preserves the complete solver audit while
bounding UI, IPC, guest-memory, and WASM payloads; binds each popup to one
challenge; clears inherited Tesseract data paths; and keeps keyring I/O off
async workers (MAT-141).
- CAPTCHA recovery now re-arms every pending timeout, and download removal
atomically coordinates engine cancellation with challenge cleanup (MAT-140).
- Contributor Automation: `actions/first-interaction` v3 requires both
Expand Down
36 changes: 36 additions & 0 deletions registry/registry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,42 @@ official = true
# the correct floor until the next plugin release fixes the manifest.
min_vortex_version = "0.2.0"

[[plugin]]
name = "vortex-mod-captcha-ocr"
description = "Local OCR solver for simple image CAPTCHAs via the typed Tesseract host broker"
author = "vortex-community"
version = "1.0.0"
category = "captcha"
repository = "https://github.com/mpiton/vortex-mod-captcha-ocr"
checksum_sha256 = "bbb6bdcb2d9cf89ff4136bdb39129686a00c92b0620050cb6f61168cb60ef181"
checksum_sha256_toml = "08fbee0b5464ad4eb55ee1da28088f4ad9b2179eb8ee82a5505edfd3bd91c660"
official = true
min_vortex_version = "0.3.0"

[[plugin]]
name = "vortex-mod-captcha-anticaptcha"
description = "Paid AntiCaptcha image solver with credentials isolated in the OS keyring"
author = "vortex-community"
version = "1.0.0"
category = "captcha"
repository = "https://github.com/mpiton/vortex-mod-captcha-anticaptcha"
checksum_sha256 = "6a18863455ee375511ed6a34de96dfb64df75096c4a968ab7d17b0805b8c993a"
checksum_sha256_toml = "b16268b0ae26b222c3048677d0d707f5338c87169466d7fbe0f7a682e213acc9"
official = true
min_vortex_version = "0.3.0"

[[plugin]]
name = "vortex-mod-captcha-browser"
description = "Human-assisted CAPTCHA fallback in a dedicated local Tauri WebView"
author = "vortex-community"
version = "1.0.0"
category = "captcha"
repository = "https://github.com/mpiton/vortex-mod-captcha-browser"
checksum_sha256 = "edfdb71e407af9a3b5910394d7e66326be13ab08d6bdea1b00a2ce65cfee0c4e"
checksum_sha256_toml = "99c4404a16fcf45023c0e74e05be40ef75fbf605b6f6b3c90b9f536effb8c7ea"
official = true
min_vortex_version = "0.3.0"

[[plugin]]
name = "vortex-mod-mediafire"
description = "MediaFire free hoster — direct download URL resolution from public file pages"
Expand Down
10 changes: 10 additions & 0 deletions src-tauri/capabilities/captcha-browser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://schema.tauri.app/config/2",
"identifier": "captcha-browser",
"description": "Minimal capabilities for assisted CAPTCHA browser windows",
"windows": ["captcha-browser-*"],
"permissions": [
"captcha-browser-commands",
"core:window:allow-close"
]
}
1 change: 1 addition & 0 deletions src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Default capabilities for Vortex",
"windows": ["main"],
"permissions": [
"main-window-commands",
"core:default",
"core:tray:default",
"notification:allow-notify",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/gen/schemas/acl-manifests.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-tauri/gen/schemas/capabilities.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"default":{"identifier":"default","description":"Default capabilities for Vortex","local":true,"windows":["main"],"permissions":["core:default","core:tray:default","notification:allow-notify","notification:allow-request-permission","notification:allow-is-permission-granted","dialog:allow-save","dialog:allow-open"]},"dev-pilot":{"identifier":"dev-pilot","description":"tauri-pilot testing plugin (Unix debug builds only)","local":true,"windows":["main"],"permissions":["pilot:default"],"platforms":["linux","macOS"]}}
{"captcha-browser":{"identifier":"captcha-browser","description":"Minimal capabilities for assisted CAPTCHA browser windows","local":true,"windows":["captcha-browser-*"],"permissions":["captcha-browser-commands","core:window:allow-close"]},"default":{"identifier":"default","description":"Default capabilities for Vortex","local":true,"windows":["main"],"permissions":["main-window-commands","core:default","core:tray:default","notification:allow-notify","notification:allow-request-permission","notification:allow-is-permission-granted","dialog:allow-save","dialog:allow-open"]},"dev-pilot":{"identifier":"dev-pilot","description":"tauri-pilot testing plugin (Unix debug builds only)","local":true,"windows":["main"],"permissions":["pilot:default"],"platforms":["linux","macOS"]}}
12 changes: 12 additions & 0 deletions src-tauri/gen/schemas/desktop-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@
"Identifier": {
"description": "Permission identifier",
"oneOf": [
{
"description": "Allows assisted CAPTCHA windows to read and resolve only their challenge.",
"type": "string",
"const": "captcha-browser-commands",
"markdownDescription": "Allows assisted CAPTCHA windows to read and resolve only their challenge."
},
{
"description": "Allows the main window to invoke all Vortex application commands.",
"type": "string",
"const": "main-window-commands",
"markdownDescription": "Allows the main window to invoke all Vortex application commands."
},
{
"description": "No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n",
"type": "string",
Expand Down
12 changes: 12 additions & 0 deletions src-tauri/gen/schemas/linux-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@
"Identifier": {
"description": "Permission identifier",
"oneOf": [
{
"description": "Allows assisted CAPTCHA windows to read and resolve only their challenge.",
"type": "string",
"const": "captcha-browser-commands",
"markdownDescription": "Allows assisted CAPTCHA windows to read and resolve only their challenge."
},
{
"description": "Allows the main window to invoke all Vortex application commands.",
"type": "string",
"const": "main-window-commands",
"markdownDescription": "Allows the main window to invoke all Vortex application commands."
},
{
"description": "No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n",
"type": "string",
Expand Down
107 changes: 107 additions & 0 deletions src-tauri/permissions/app.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
[[permission]]
identifier = "main-window-commands"
description = "Allows the main window to invoke all Vortex application commands."
commands.allow = [
"download_start",
"download_pause",
"download_resume",
"download_cancel",
"download_skip_wait",
"captcha_solve",
"captcha_skip",
"captcha_retry",
"captcha_list",
"captcha_get_pending",
Comment thread
mpiton marked this conversation as resolved.
"captcha_credential_status",
"captcha_credential_set",
"captcha_credential_delete",
"download_change_directory",
"download_change_directory_bulk",
"download_retry",
"download_redownload",
"download_verify_checksum",
"download_open_file",
"download_open_folder",
"download_pause_all",
"download_resume_all",
"download_set_priority",
"download_move_to_top",
"download_move_to_bottom",
"download_reorder_queue",
"download_remove",
"download_clear_completed",
"download_clear_failed",
"download_list",
"download_detail",
"download_logs",
"download_count_by_state",
"plugin_install",
"plugin_uninstall",
"plugin_enable",
"plugin_disable",
"plugin_list",
"plugin_store_list",
"plugin_store_refresh",
"plugin_store_install",
"plugin_store_update",
"plugin_config_get",
"plugin_config_update",
"plugin_report_broken",
"link_resolve",
"link_check_online",
"link_detect_duplicates",
"link_group_playlists",
"link_group_split_archives",
"link_import_container",
"clipboard_toggle",
"clipboard_state",
"settings_get",
"settings_update",
"status_bar_get",
"command_get_media_metadata",
"download_media_start",
"history_list",
"history_search",
"history_get_by_id",
"history_export",
"history_delete_entry",
"history_clear",
"history_purge_older_than",
"reveal_in_folder",
"stats_get",
"stats_top_modules",
"browse_folder",
"browse_file",
"account_add",
"account_update",
"account_delete",
"account_validate",
"account_export",
"account_import",
"account_list",
"account_get",
"account_traffic_get",
"package_create",
"package_update",
"package_delete",
"package_set_password",
"package_set_priority",
"package_move_to_folder",
"package_toggle_auto_extract",
"package_add_download",
"package_remove_download",
"package_list",
"package_get",
"package_list_downloads",
"package_find_by_external_id",
]

[[permission]]
identifier = "captcha-browser-commands"
description = "Allows assisted CAPTCHA windows to read and resolve only their challenge."
commands.allow = [
"captcha_get_pending",
"captcha_solve",
"captcha_skip",
"captcha_retry",
]
8 changes: 8 additions & 0 deletions src-tauri/src/adapters/captcha_browser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use sha2::{Digest, Sha256};

const CAPTCHA_BROWSER_WINDOW_PREFIX: &str = "captcha-browser-";

pub(crate) fn browser_window_label(challenge_id: &str) -> String {
let digest = Sha256::digest(challenge_id.as_bytes());
format!("{CAPTCHA_BROWSER_WINDOW_PREFIX}{}", hex::encode(digest))
}
Loading
Loading