Skip to content

修复无法下载 SHA-1 为空字符串的文件的问题#6170

Open
Glavo wants to merge 1 commit into
HMCL-dev:mainfrom
Glavo:fix-empty-sha1
Open

修复无法下载 SHA-1 为空字符串的文件的问题#6170
Glavo wants to merge 1 commit into
HMCL-dev:mainfrom
Glavo:fix-empty-sha1

Conversation

@Glavo

@Glavo Glavo commented Jun 13, 2026

Copy link
Copy Markdown
Member

No description provided.

- validate cache lookups and writes with SHA-1 format checks
  instead of only rejecting null hashes
- throw an I/O error when caching is requested with a non-SHA-1
  checksum to avoid creating invalid cache entries
- skip checksum verification for empty download values so missing
  hashes no longer flow into cache and file validation paths
@Glavo Glavo changed the title 修复无法正确下载 SHA-1 为空字符串的文件的问题 修复无法下载 SHA-1 为空字符串的文件的问题 Jun 13, 2026
@Glavo

Glavo commented Jun 13, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces stricter checksum validation when caching files and libraries, specifically by checking if hashes are valid SHA-1 digests and ensuring checksums are not empty during file downloads. The review feedback correctly points out that hardcoding SHA-1 validation in CacheRepository breaks support for other hashing algorithms (such as MD5 or SHA-256) that the repository is designed to handle. The reviewer suggests implementing a dynamic isValidHash(algorithm, hash) method to support multiple algorithms and gracefully handle empty or null hashes to prevent unnecessary exceptions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.


protected boolean fileExists(String algorithm, String hash) {
if (hash == null) return false;
if (!DigestUtils.isSha1Digest(hash)) return false;

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.

high

fileExists 方法中,直接使用 DigestUtils.isSha1Digest(hash) 会导致非 SHA-1 算法(如 MD5、SHA-256 等)的校验失效。由于 CacheRepository 的设计是支持多种算法的(通过 algorithm 参数和对应的子目录),这里应该根据传入的 algorithm 来动态验证哈希值的有效性。建议使用一个通用的 isValidHash(algorithm, hash) 方法进行校验。

Suggested change
if (!DigestUtils.isSha1Digest(hash)) return false;
if (!isValidHash(algorithm, hash)) return false;

Comment on lines +117 to 136
private void checkHash(String hash) throws IOException {
if (!DigestUtils.isSha1Digest(hash)) {
throw new IOException("Not SHA-1 checksum: " + hash);
}
}

public void tryCacheFile(Path path, String algorithm, String hash) throws IOException {
checkHash(hash);

Path cache = getFile(algorithm, hash);
if (Files.isRegularFile(cache)) return;
FileUtils.copyFile(path, cache);
}

public Path cacheFile(Path path, String algorithm, String hash) throws IOException {
checkHash(hash);

Path cache = getFile(algorithm, hash);
FileUtils.copyFile(path, cache);
return cache;

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.

high

checkHash 方法中硬编码 DigestUtils.isSha1Digest(hash) 会导致非 SHA-1 算法在缓存时抛出 IOException。此外,当下载 SHA-1 为空字符串的文件时,FileDownloadTask 仍会尝试调用 cacheFile,这会导致抛出异常并打印警告日志。

建议:

  1. 实现一个通用的 isValidHash(algorithm, hash) 方法,根据不同的算法验证哈希长度和十六进制格式。
  2. 重构 checkHash 方法,使其接受 algorithm 参数并调用 isValidHash
  3. tryCacheFilecacheFile 中,如果 hash 为空或为 null,则直接返回(no-op),避免抛出异常和打印无意义的警告日志。
    private static boolean isValidHash(String algorithm, String hash) {
        if (hash == null) return false;
        int expectedLength = switch (algorithm.toUpperCase(Locale.ROOT)) {
            case "SHA-1", "SHA1" -> 40;
            case "MD5" -> 32;
            case "SHA-256", "SHA256" -> 64;
            case "SHA-512", "SHA512" -> 128;
            default -> -1;
        };
        if (expectedLength != -1) {
            if (hash.length() != expectedLength) return false;
        } else {
            if (hash.length() < 2) return false;
        }
        for (int i = 0; i < hash.length(); i++) {
            char ch = hash.charAt(i);
            if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F')) {
                return false;
            }
        }
        return true;
    }

    private void checkHash(String algorithm, String hash) throws IOException {
        if (!isValidHash(algorithm, hash)) {
            throw new IOException("Not " + algorithm + " checksum: " + hash);
        }
    }

    public void tryCacheFile(Path path, String algorithm, String hash) throws IOException {
        if (hash == null || hash.isEmpty()) return;
        checkHash(algorithm, hash);

        Path cache = getFile(algorithm, hash);
        if (Files.isRegularFile(cache)) return;
        FileUtils.copyFile(path, cache);
    }

    public Path cacheFile(Path path, String algorithm, String hash) throws IOException {
        if (hash == null || hash.isEmpty()) return path;
        checkHash(algorithm, hash);

        Path cache = getFile(algorithm, hash);
        FileUtils.copyFile(path, cache);
        return cache;
    }

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.

[Bug] 无法安装 GTNH: java.lang.StringIndexOutOfBoundsException: Range [0, 2) out of bounds for length 0

1 participant