Skip to content

Allow uploading and storing cracker binaries on the server - #2499

Open
s3inlc wants to merge 3 commits into
masterfrom
886-stack-1-upload
Open

s3inlc wants to merge 3 commits into
masterfrom
886-stack-1-upload

Conversation

@s3inlc

@s3inlc s3inlc commented Sep 17, 2026

Copy link
Copy Markdown
Member

Cracker binaries can now be stored on the server itself instead of only referencing an external download URL. Existing URL-based binaries are fully unaffected.

Upload (apiv2)

  • POST /api/v2/ui/crackers accepts an alternative to downloadUrl: sourceType/sourceData with three sources:
    • import: consume an archive uploaded through the existing chunked (TUS) upload to the import directory — the path for arbitrarily large archives, no PHP request-size limits involved
    • url: the server fetches the archive itself (http/https only)
    • inline: base64 archive data for small uploads
  • Only .7z archives are accepted (7z magic-byte validation); the archive filename is server-composed ({crackerType}-{version}.7z), and the downloadUrl is set automatically to the server's download endpoint — no client-supplied filenames or URLs
  • New nullable filename column on CrackerBinary doubles as the local-storage flag (NULL = external URL binary, as before)

Download

  • New generic endpoint GET /api/download.php/{kind}/{id} (kind registry, extensible to files/hashlists later) — authenticated with either an agent token (?token=) or an apiv2 Bearer JWT; streams with HTTP Range and ETag support
  • Agents require zero changes: the downloadBinary action appends the requesting agent's token to the URL of locally hosted binaries, so the existing fetch-and-extract flow just works
  • Deleting a binary (or a whole cracker type) also removes its stored archive; the downloadUrl of local binaries is server-owned and cannot be patched

@s3inlc
s3inlc added this pull request to stack #2501 September 17, 2026 12:36
@s3inlc
s3inlc requested a review from jessevz September 22, 2026 12:17
@s3inlc
s3inlc marked this pull request as ready for review September 22, 2026 12:17

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate issues affect storage permissions, URL handling, validation, authentication, and download correctness.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 5 High severity · 2 Medium severity

Open (7)
What changed in this PR

Adds server-hosted cracker binary uploads and an authenticated download endpoint while preserving agent integration.

Changes:

  • Supports inline, imported, and URL-based archive uploads with local storage.
  • Adds authenticated streaming downloads with range and ETag support.
  • Updates models, migrations, OpenAPI documentation, Docker setup, and tests.
File Summary
src/​migrations/​postgres/​20260917114300_cracker-binary-local-upload.sql Adds local filename storage.
src/​migrations/​mysql/​20260917114300_cracker-binary-local-upload.sql Adds filename storage and expands URL capacity.
src/​inc/​utils/​DownloadUtils.php Provides download streaming and range handling. Moderate (3 votes): suffix and open-ended ranges are parsed incorrectly. Moderate (1 vote): 416 responses use an incorrect Content-Range.
src/​inc/​utils/​CrackerUtils.php Handles archive upload, caching, lifecycle, and cleanup. Critical (3 votes): URL-only creation now requires server-side fetching, breaking existing external URLs. Moderate (1 vote): URL edits have the same compatibility break. Critical (3 votes): scheme-only URL validation permits SSRF. Critical (1 vote): inline base64 input is unbounded before size checks.
src/​inc/​Util.php Adds URL downloading and backend URL generation. Critical (1 vote): request Host can be persisted into agent download URLs.
src/​inc/​StartupConfig.php Configures cracker storage.
src/​inc/​startup/​setup.php Initializes the cracker directory.
src/​inc/​startup/​setup.json Updates initial cracker data.
src/​inc/​downloadapi/​DownloadRegistry.php Registers download handlers.
src/​inc/​downloadapi/​DownloadAuthMiddleware.php Adds agent and JWT authentication.
src/​inc/​downloadapi/​DownloadApp.php Defines download routes. Moderate (1 vote): IDs accept nonnumeric prefixes. Moderate (1 vote): bearer authentication failures can become HTTP 500 responses.
src/​inc/​downloadapi/​CrackerBinaryDownloadHandler.php Serves local cracker archives.
src/​inc/​defines/​DDirectories.php Adds the cracker directory key.
src/​inc/​apiv2/​openapi/​SpecOverrides.php Documents cracker upload fields.
src/​inc/​apiv2/​openapi/​ModelApiPathBuilder.php Applies request descriptions.
src/​inc/​apiv2/​model/​CrackerBinaryAPI.php Implements upload creation and update rules. Moderate (2 votes): updates allow downloadUrl: null despite the database constraint.
src/​inc/​apiv2/​common/​AbstractHelperAPI.php Reuses download utilities.
src/​inc/​apiv2/​auth/​JwtAuthenticationFactory.php Shares JWT configuration.
src/​inc/​agentapi/​model/​DownloadBinaryAction.php Adds agent-token URLs for local archives.
src/​dba/​models/​generator.php Updates model metadata.
src/​dba/​models/​CrackerBinaryFactory.php Maps the filename field.
src/​dba/​models/​CrackerBinary.php Adds local archive metadata. Moderate (1 vote): nullable API validation conflicts with the non-null database column.
src/​api/​v2/​index.php Uses shared JWT authentication.
src/​api/​download.php Adds the download API entry point.
openapi.json Updates the generated API specification. Moderate (1 vote): the schema lacks conditional requirements for upload sources.
Dockerfile Creates and configures cracker storage. Critical (2 votes): existing Docker volumes may leave the directory owned by root and unwritable by www-data.
ci/​phpunit/​TestBase.php Updates test model construction.
ci/​phpunit/​inc/​UtilTest.php Tests backend URL generation.
ci/​phpunit/​inc/​utils/​CrackerUtilsTest.php Tests archive lifecycle behavior.
ci/​phpunit/​inc/​utils/​CrackerBinaryUtilsTest.php Updates cracker fixtures.
ci/​phpunit/​inc/​apiv2/​openapi/​SpecOverridesTest.php Tests schema descriptions.
ci/​phpunit/​fixtures/​openapi/​crackerbinarytype.spec.json Updates OpenAPI fixtures.
ci/​phpunit/​downloadapi/​DownloadAppTest.php Tests download authentication and streaming.
ci/​phpunit/​dba/​MassUpdateSetTest.php Updates model fixtures.
ci/​phpunit/​dba/​AbstractModelFactoryTest.php Updates model fixtures.
ci/​apiv2/​utils.py Adds upload and archive test helpers.
ci/​apiv2/​test_taskwrapper.py Uses valid downloadable archives.
ci/​apiv2/​test_cracker.py Tests upload, caching, and deletion flows.
ci/​apiv2/​test_agent_protocol.py Tests agent downloads and token handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Dockerfile
ENV HASHTOPOLIS_LOG_PATH=${HASHTOPOLIS_PATH}/log
ENV HASHTOPOLIS_CONFIG_PATH=${HASHTOPOLIS_PATH}/config
ENV HASHTOPOLIS_BINARIES_PATH=${HASHTOPOLIS_PATH}/binaries
ENV HASHTOPOLIS_CRACKERS_PATH=${HASHTOPOLIS_PATH}/crackers
Comment thread src/inc/Util.php
Comment on lines +1329 to +1330
}
return rtrim(Util::buildServerUrl() . SConfig::getInstance()->getVal(DConfig::BASE_URL), '/');
Comment on lines +84 to +88
try {
CrackerUtils::storeLocalCopy($binary);
}
catch (HttpError $e) {
Factory::getCrackerBinaryFactory()->delete($binary);
Comment on lines +117 to +121
case "inline":
$archiveData = base64_decode($sourceData, true);
if ($archiveData === false) {
throw new HttpError("sourceData not valid base64 encoding");
}
Comment on lines +133 to +137
case "url":
$scheme = parse_url($sourceData, PHP_URL_SCHEME);
if ($scheme != "http" && $scheme != "https") {
throw new HttpError("Only http and https URLs are supported as sourceData!");
}
Comment on lines +131 to +133
$refreshLocalCopy = $binary->getFilename() === null
&& ($data[CrackerBinary::DOWNLOAD_URL] ?? null) !== null
&& $data[CrackerBinary::DOWNLOAD_URL] != $binary->getDownloadUrl();
Comment on lines +43 to +51
$range = explode('-', $range);
$c_start = (int)$range[0];
if ((isset($range[1]) && is_numeric($range[1]))) {
$c_end = (int)$range[1];
}
else {
$c_end = $size;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants