Skip to content

Validate shader downloads and respect saved consent - #11

Merged
CoasterFreakDE merged 2 commits into
mainfrom
codex/shader-consent-status
Nov 4, 2026
Merged

CoasterFreakDE merged 2 commits into
mainfrom
codex/shader-consent-status

Conversation

@CoasterFreakDE

Copy link
Copy Markdown
Member

Problem and changes

Shader offers could ignore a saved rejection, send multiple failure statuses, and use an unchecked server-provided hash as a file path. Validate SHA-1 identifiers, verify downloads and cached files, remember rejections, and send one download failure status. The README explains how to reset a saved choice.

Validation

  • gradlew clean build runClientGameTest --no-daemon passed locally on Java 25. The client game test covers saved rejection, invalid paths, a failed connection, incorrect and correct hashes, and corrupt cache recovery using a local HTTP fixture.
  • The previously released client was exercised with Iris 1.11.7 and Sodium 0.9.2: a valid cached shader applied, rejection returned DENIED, and a download failure returned failure statuses. Successful Iris rendering with this updated build has not yet been retested.

Downloads still run synchronously and have no size limit; that pre-existing limitation remains.

@diffy-bot

diffy-bot Bot commented Nov 4, 2026

Copy link
Copy Markdown

Summary of changes

Files changed

  • modified: README.MD
  • modified: build.gradle.kts
  • modified: src/client/kotlin/com/liamxsage/shaderapi/client/ShaderReceivePayloadHandler.kt
  • added: src/gametest/java/com/liamxsage/shaderapi/ShaderConsentClientTest.java
  • added: src/gametest/resources/fabric.mod.json

TL;DR

  • Client now requires offers to include a 40-hex-digit SHA-1 hash, verifies cached and downloaded packs against it, and remembers per-server accept/deny decisions. Download logic improved (temp files, timeouts, hash verification). A client-side game test suite for consent/caching behavior was added. Build config updated to enable a client game-test module.

README.MD

  • Added documentation about the new hash requirement and how acceptance/rejection is remembered:
    • "Offers must provide a 40-digit SHA-1 hash; downloaded and cached packs are checked against it."
    • Explains how to change a saved decision by removing server group's entry from config/shaderapi.json while the game is closed.

build.gradle.kts

  • Added fabricApi configuration for tests:
    • createSourceSet = true
    • modId = "shaderapi_test"
    • enableGameTests = false

This enables a separate client gametest module.

ShaderReceivePayloadHandler.kt (client)

Major behavioral and robustness changes:

  • New imports: OutputStream, DigestInputStream, MessageDigest (for hashing).
  • Use of per-server saved decision:
    • Retrieves decision from ConfigManager.getShaderPackAcceptState(serverGroup).
    • If decision == DENY: sends DENIED status and returns (no UI prompt).
    • If decision == ACCEPT: proceeds to download/apply immediately.
  • Offer hash validation:
    • Rejects offers whose hash does not match Regex("[0-9a-fA-F]{40}") and logs a warning, sending DOWNLOAD_FAILED.
  • Caching and verification improvements:
    • testForShaderPack now:
      • Ensures file.isFile
      • Verifies SHA-1 via new hashMatches(file, hash) method (uses MessageDigest + DigestInputStream + HexFormat)
      • Deletes cached file if hash mismatch and logs a warning
      • Logs validation failures instead of printing stack traces
  • New hashMatches(file, hash) helper:
    • Computes SHA-1 of the file and compares hex (case-insensitive).
  • downloadShaderPack improvements:
    • Uses a dedicated downloads directory and File.createTempFile for safe temporary file handling.
    • Adds connection timeouts (connectTimeout 10s, readTimeout 30s).
    • Streams download to temporary file, verifies SHA-1 with hashMatches before renaming to final "$hash.zip".
    • Uses renameTo to move to destination; returns destination file or null.
    • Ensures connection.disconnect() and deletes temp file in finally.
    • Logs warnings on exceptions instead of printing stack traces or directly sending status responses.
  • Removed:
    • testForServerGroupAlwaysAccept helper (logic integrated using saved decision).
    • usage of reflection-based exception class naming (exception::class.jvmName) in some response paths; replaced with logging.
  • Minor: added newline at EOF.

Behavioral effect:

  • Offers with invalid hash format are rejected early.
  • Cached files are verified and deleted if corrupted.
  • Downloads are written to temp files, verified, then atomically renamed.
  • Saved DENY avoids prompting; saved ACCEPT skips user confirm and attempts download.

New gametest: ShaderConsentClientTest.java

  • Adds an extensive client-side gametest covering:
    • Saved DENY behavior: server should receive DENIED immediately and no prompt should appear.
    • Handling of invalid offer hashes (e.g., "../../unsafe"): should remain DENIED.
    • Saved ACCEPT behavior: failed downloads must produce DOWNLOAD_FAILED.
    • Tests a local HTTP fixture to validate:
      • Unsafe hashes must not write outside the downloads directory.
      • Mismatched downloads are not cached/applied.
      • Matching downloads are cached before invoking Iris, and apply failures are reported.
      • Corrupt cached files are replaced by a verified download.
  • Uses an embedded HttpServer to serve a small "test" payload and inspects file contents & request counts.
  • Registers global receivers for payloads and status response to observe behavior.
  • Cleans up test files after execution.

New gametest resources: fabric.mod.json

  • Defines a client-targeted mod module:
    • id "shaderapi_test", version "1.0.0"
    • entrypoint for fabric-client-gametest: com.liamxsage.shaderapi.ShaderConsentClientTest

Suggestions (issues found)

  • Use a stronger hash than SHA-1:
    • SHA-1 is considered weak for collision resistance. Prefer SHA-256 (or better) for integrity verification going forward.
  • Ensure consistent status reporting to servers:
    • The code now logs exceptions instead of sending status responses in some failure branches. Verify that server notification behavior remains as intended in all error cases (e.g., IO failures while validating cache).
  • Verify Java version / API compatibility:
    • The code uses HexFormat (Java 17+). Ensure the project targets a compatible JDK for build/runtime.
  • Atomic rename behavior & temp file cleanup:
    • renameTo semantics vary across platforms/filesystems. Consider Files.move(..., ATOMIC_MOVE) (NIO) for a more robust, atomic rename and to ensure no leftover temp files or accidental deletes.
  • Test robustness & permissions:
    • Gametest manipulates filesystem and opens a local HTTP server. Ensure CI/test environments allow binding to ephemeral ports and writing to the game directory. Consider more isolation (temp directories) if necessary.

You can generate a new summary by commenting @diffy-bot.

@CoasterFreakDE
CoasterFreakDE merged commit 4a11e6a into main Nov 4, 2026
4 checks passed
@CoasterFreakDE
CoasterFreakDE deleted the codex/shader-consent-status branch November 4, 2026 17:52
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.

1 participant