Skip to content

fix: Fix Chinese password compression failure#351

Merged
pengfeixx merged 1 commit intolinuxdeepin:develop/snipefrom
pengfeixx:fix-340777
Jan 20, 2026
Merged

fix: Fix Chinese password compression failure#351
pengfeixx merged 1 commit intolinuxdeepin:develop/snipefrom
pengfeixx:fix-340777

Conversation

@pengfeixx
Copy link
Contributor

@pengfeixx pengfeixx commented Jan 20, 2026

Fix Chinese password compression failure

Log: Fix Chinese password compression failure

Summary by Sourcery

Fix ZIP password handling to correctly support Chinese-character passwords during compression and extraction.

Bug Fixes:

  • Resolve failures when compressing and extracting ZIP archives that use Chinese-character passwords by applying the existing passwordUnicode encoding logic consistently.
  • Correct detection of Chinese passwords in ZIP compression by checking Unicode codepoint ranges instead of using the previous regular expression approach.

Enhancements:

  • Add diagnostic logging around password encoding decisions and encryption setup to aid debugging of password-related ZIP issues.
  • Introduce a persistent buffer member for encoded password data to ensure it remains valid throughout the compression process.

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 20, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Updates zip password handling to use a custom Unicode-to-byte conversion for Chinese characters, ensures the encoded password data remains valid during compression, and replaces regex-based Chinese detection with a direct character-range check, adding logging to help diagnose encoding behavior.

Sequence diagram for Chinese password compression and extraction

sequenceDiagram
  actor User
  participant MainWindow
  participant LibzipPlugin
  participant Libzip

  User->>MainWindow: select files and enter password
  MainWindow->>MainWindow: slotCompress(val)
  MainWindow->>MainWindow: check each QChar in m_stCompressParameter.strPassword
  MainWindow->>MainWindow: set zipPasswordIsChinese flag
  MainWindow->>LibzipPlugin: start compression with options

  LibzipPlugin->>LibzipPlugin: passwordUnicode(options.strPassword, 0)
  LibzipPlugin->>Libzip: zip_file_set_encryption(..., passwordBytes.constData)
  LibzipPlugin->>Libzip: zip_set_default_password(..., passwordBytes.constData)
  Libzip-->>LibzipPlugin: return status
  LibzipPlugin-->>MainWindow: compression result
  MainWindow-->>User: show compression success or error
Loading

Class diagram for updated LibzipPlugin and MainWindow password handling

classDiagram

class LibzipPlugin {
  +QMap<QString,int> m_mapRealDirValue
  +QSet<QString> m_setLongName
  +bool m_bLnfs
  +QByteArray m_passwordData
  +PluginFinishType extractFiles(files, options)
  +bool writeEntry(archive, entry, options)
  +QByteArray passwordUnicode(strPassword, iIndex)
  +void setPassword(password)
}

class MainWindow {
  +CompressParameters m_stCompressParameter
  +void slotCompress(val)
}

class CompressParameters {
  +QString strMimeType
  +QString strPassword
}

MainWindow "1" *-- "1" CompressParameters
MainWindow ..> LibzipPlugin : uses
Loading

File-Level Changes

Change Details Files
Use passwordUnicode for all zip password/encryption calls so Chinese passwords are encoded correctly
  • Replace direct toUtf8() usage for extraction default password with passwordUnicode conversion and pass its QByteArray data to libzip
  • For compression/encryption, pre-encode the password using passwordUnicode and reuse the resulting bytes when setting AES encryption on files
3rdparty/libzipplugin/libzipplugin.cpp
Improve password Unicode conversion diagnostics and handling for Chinese vs non-Chinese passwords
  • Add qInfo logging when a Chinese-containing password is detected in passwordUnicode, showing which codec is used
  • Add qInfo logging when a non-Chinese password is encoded via UTF-8 in passwordUnicode
3rdparty/libzipplugin/libzipplugin.cpp
Detect Chinese characters in zip passwords without using regex
  • Replace regex-based Chinese character detection in the compression UI with an explicit per-character Unicode range check for CJK Unified Ideographs
src/source/mainwindow.cpp
Track encoded password lifetime during compression
  • Introduce a QByteArray member m_passwordData on LibzipPlugin to hold encoded password bytes, ensuring the backing storage remains valid while libzip uses the pointer
3rdparty/libzipplugin/libzipplugin.h

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The newly added m_passwordData member is never used; either remove it or wire it into the password handling so its purpose (extending password lifetime) is actually fulfilled.
  • The new qInfo() calls in writeEntry and passwordUnicode log password length and encoding details, which may leak sensitive information; consider removing or guarding these logs in production builds.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The newly added `m_passwordData` member is never used; either remove it or wire it into the password handling so its purpose (extending password lifetime) is actually fulfilled.
- The new `qInfo()` calls in `writeEntry` and `passwordUnicode` log password length and encoding details, which may leak sensitive information; consider removing or guarding these logs in production builds.

## Individual Comments

### Comment 1
<location> `3rdparty/libzipplugin/libzipplugin.cpp:673-677` </location>
<code_context>
     // 设置压缩的加密算法
     if (options.bEncryption && !options.strEncryptionMethod.isEmpty()) { //ReadOnlyArchiveInterface::password()
         int ret = 0;
+        QByteArray passwordBytes = passwordUnicode(options.strPassword, 0);
+        qInfo() << "Setting encryption for file, method:" << options.strEncryptionMethod 
+                << "password length:" << options.strPassword.length()
+                << "encoded bytes length:" << passwordBytes.length();
         if (QLatin1String("AES128") == options.strEncryptionMethod) {
-            ret = zip_file_set_encryption(archive, uindex, ZIP_EM_AES_128, options.strPassword.toUtf8().constData());
+            ret = zip_file_set_encryption(archive, uindex, ZIP_EM_AES_128, passwordBytes.constData());
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Avoid logging detailed password metadata (lengths) in qInfo for security/privacy reasons.

These `qInfo()` calls log password-related metadata (length and encoded length), and similar logging was added in `passwordUnicode` for Chinese detection. Even without the actual password, this information can aid password guessing and will likely persist in logs. Please remove these logs, or restrict them to a debug-only/very-verbose path that is disabled in production.

Suggested implementation:

```cpp
        QByteArray passwordBytes = passwordUnicode(options.strPassword, 0);
        if (QLatin1String("AES128") == options.strEncryptionMethod) {

```

The review comment also refers to similar logging added inside `passwordUnicode` for Chinese detection. For full compliance with the security/privacy concern, you should locate that logging in `passwordUnicode` (likely in the same file or related source file) and either:
1. Remove it entirely, or
2. Wrap it in a very-verbose/debug-only mechanism that is disabled in production (e.g., behind a compile-time flag or an environment-variable-guarded `qDebug()`).

Apply the same principle: avoid logging password content or metadata (lengths, encodings) that can persist in logs.
</issue_to_address>

### Comment 2
<location> `3rdparty/libzipplugin/libzipplugin.cpp:1223-1228` </location>
<code_context>

         // chinese
         if (b) {
+            qInfo() << "Password contains Chinese characters, using codec:" << m_listCodecs[iIndex];
             QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
             QTextCodec *gbk = QTextCodec::codecForName(m_listCodecs[iIndex].toUtf8().data());
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Reduce per-password qInfo logging to avoid noisy logs and potential password side-channel leakage.

These `qInfo()` calls in `passwordUnicode` run for every password and log whether it contains Chinese characters and which codec is used. Beyond the security concerns about leaking password characteristics to logs, this will generate a lot of noise when many archives are processed. Please either remove these logs after you finish diagnosing the issue or move them behind a debug-only mechanism that is disabled in normal operation.

```suggestion
        // chinese
        if (b) {
#ifdef QT_DEBUG
            qDebug() << "Password contains Chinese characters, using codec:" << m_listCodecs[iIndex];
#endif
            QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
            QTextCodec *gbk = QTextCodec::codecForName(m_listCodecs[iIndex].toUtf8().data());
            // QTextCodec *gbk = QTextCodec::codecForName("UTF-8");
            QByteArray gb_bytes = gbk->fromUnicode(strUnicode);
            return gb_bytes; //获取其char *115645 【专业版】【1060】【归档管理器】【5.12.0.2】无法解压中文密码的zip压缩包(含有长名称)
        } else {
#ifdef QT_DEBUG
            qDebug() << "Password is non-Chinese, using UTF-8 encoding";
#endif
            return strPassword.toUtf8();
        }
```
</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 on lines 673 to 674
QByteArray passwordBytes = passwordUnicode(options.strPassword, 0);
qInfo() << "Setting encryption for file, method:" << options.strEncryptionMethod
<< "password length:" << options.strPassword.length()
<< "encoded bytes length:" << passwordBytes.length();
if (QLatin1String("AES128") == options.strEncryptionMethod) {
Copy link

Choose a reason for hiding this comment

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

🚨 suggestion (security): Avoid logging detailed password metadata (lengths) in qInfo for security/privacy reasons.

These qInfo() calls log password-related metadata (length and encoded length), and similar logging was added in passwordUnicode for Chinese detection. Even without the actual password, this information can aid password guessing and will likely persist in logs. Please remove these logs, or restrict them to a debug-only/very-verbose path that is disabled in production.

Suggested implementation:

        QByteArray passwordBytes = passwordUnicode(options.strPassword, 0);
        if (QLatin1String("AES128") == options.strEncryptionMethod) {

The review comment also refers to similar logging added inside passwordUnicode for Chinese detection. For full compliance with the security/privacy concern, you should locate that logging in passwordUnicode (likely in the same file or related source file) and either:

  1. Remove it entirely, or
  2. Wrap it in a very-verbose/debug-only mechanism that is disabled in production (e.g., behind a compile-time flag or an environment-variable-guarded qDebug()).

Apply the same principle: avoid logging password content or metadata (lengths, encodings) that can persist in logs.

Comment on lines 1223 to 1224
// chinese
if (b) {
qInfo() << "Password contains Chinese characters, using codec:" << m_listCodecs[iIndex];
QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
QTextCodec *gbk = QTextCodec::codecForName(m_listCodecs[iIndex].toUtf8().data());
// QTextCodec *gbk = QTextCodec::codecForName("UTF-8");
Copy link

Choose a reason for hiding this comment

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

🚨 suggestion (security): Reduce per-password qInfo logging to avoid noisy logs and potential password side-channel leakage.

These qInfo() calls in passwordUnicode run for every password and log whether it contains Chinese characters and which codec is used. Beyond the security concerns about leaking password characteristics to logs, this will generate a lot of noise when many archives are processed. Please either remove these logs after you finish diagnosing the issue or move them behind a debug-only mechanism that is disabled in normal operation.

Suggested change
// chinese
if (b) {
qInfo() << "Password contains Chinese characters, using codec:" << m_listCodecs[iIndex];
QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
QTextCodec *gbk = QTextCodec::codecForName(m_listCodecs[iIndex].toUtf8().data());
// QTextCodec *gbk = QTextCodec::codecForName("UTF-8");
// chinese
if (b) {
#ifdef QT_DEBUG
qDebug() << "Password contains Chinese characters, using codec:" << m_listCodecs[iIndex];
#endif
QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
QTextCodec *gbk = QTextCodec::codecForName(m_listCodecs[iIndex].toUtf8().data());
// QTextCodec *gbk = QTextCodec::codecForName("UTF-8");
QByteArray gb_bytes = gbk->fromUnicode(strUnicode);
return gb_bytes; //获取其char *115645 【专业版】【1060】【归档管理器】【5.12.0.2】无法解压中文密码的zip压缩包(含有长名称)
} else {
#ifdef QT_DEBUG
qDebug() << "Password is non-Chinese, using UTF-8 encoding";
#endif
return strPassword.toUtf8();
}

Fix Chinese password compression failure

Log: Fix Chinese password compression failure
@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要针对压缩/解压过程中的密码编码处理进行了改进,特别是针对非ASCII字符(如中文)的处理。以下是对代码的详细审查和改进建议:

1. 语法逻辑审查

优点:

  • 修改后的代码将密码编码逻辑统一封装到了 passwordUnicode 函数中(虽然该函数定义未在 diff 中展示,但从调用方式可以推断),提高了代码的一致性。
  • mainwindow.cpp 中,将正则表达式检查改为直接遍历字符检查 Unicode 范围,逻辑更清晰,避免了正则表达式的开销。

问题与建议:

  1. passwordUnicode 函数的使用不一致

    • libzipplugin.cpp 中,passwordUnicode 被用于临时编码密码(QByteArray passwordBytes = passwordUnicode(m_strPassword, 0);),但返回的 QByteArray 是局部变量。
    • libzipplugin.h 中新增了成员变量 m_passwordData,但 diff 中未看到它的使用。如果意图是缓存编码后的密码,应该在 passwordUnicode 调用处使用 m_passwordData 而不是局部变量。
  2. passwordUnicode 的参数 0 含义不明

    • passwordUnicode(m_strPassword, 0) 的第二个参数 0 可能表示编码方式(如 0 代表 UTF-8),但未在代码中明确说明。建议使用具名常量或枚举(如 Encoding::UTF8)以提高可读性。

2. 代码质量审查

优点:

  • 修改后的代码减少了重复逻辑(如 toUtf8() 的重复调用)。
  • mainwindow.cpp 中,直接遍历字符检查 Unicode 范围比正则表达式更直观。

问题与建议:

  1. passwordUnicode 函数的可见性

    • 如果 passwordUnicode 是类的私有方法,建议在 libzipplugin.h 中声明其签名,以便其他开发者了解其存在和用途。
  2. 错误处理缺失

    • zip_set_default_passwordzip_file_set_encryption 的返回值未检查(虽然 zip_file_set_encryption 检查了 ret != 0,但未处理错误)。建议增加错误日志或返回值检查。
  3. 字符串比较优化

    • libzipplugin.cpp 中,QLatin1String("AES128") == options.strEncryptionMethod 的比较可以优化为 options.strEncryptionMethod.compare("AES128", Qt::CaseInsensitive) == 0,以避免临时 QLatin1String 的构造。

3. 代码性能审查

优点:

  • mainwindow.cpp 中,直接遍历字符比正则表达式更高效,尤其是当密码较短时。

问题与建议:

  1. 重复编码密码

    • extractFiles 中,每次需要密码时都会调用 passwordUnicode 重新编码。如果密码不变,可以缓存编码后的结果(如使用 m_passwordData)。
  2. Unicode 检查的性能

    • mainwindow.cpp 中,ch.unicode() 的调用可以优化为直接比较 ch 的 Unicode 值(如 ch >= 0x4E00 && ch <= 0x9FA5),但 Qt 的 QChar 已经优化了这类操作,影响不大。

4. 代码安全审查

优点:

  • 修改后的代码统一了密码编码方式,减少了因编码不一致导致的安全问题(如乱码或错误的密码验证)。

问题与建议:

  1. 密码在内存中的存储

    • QByteArray 存储的密码数据在内存中是明文。建议在不再需要时显式清零(如 passwordBytes.fill(0)),以减少内存泄露的风险。
  2. 密码编码的明确性

    • passwordUnicode 的编码方式应明确(如强制使用 UTF-8),避免因平台默认编码不同导致的安全问题。
  3. 错误信息泄露

    • libzipplugin.cpp 中,emit error(("Failed to set compression options for entry: %1")) 未填充 %1 占位符,可能导致信息泄露或调试困难。建议修复为 emit error(QString("Failed to set compression options for entry: %1").arg(entry))

改进后的代码示例

libzipplugin.h

class LibzipPlugin : public ReadWriteArchiveInterface {
    // ... 其他成员 ...
private:
    QByteArray passwordUnicode(const QString &password, int encoding); // 声明 passwordUnicode
    QByteArray m_passwordData; // 缓存编码后的密码
};

libzipplugin.cpp

QByteArray LibzipPlugin::passwordUnicode(const QString &password, int encoding) {
    if (encoding == 0) { // 假设 0 代表 UTF-8
        return password.toUtf8();
    }
    // 其他编码方式...
}

PluginFinishType LibzipPlugin::extractFiles(const QList<FileEntry> &files, const QString &destination) {
    // ... 其他代码 ...
    if (needPassword) {
        // ... 其他代码 ...
        if (m_passwordData.isEmpty()) {
            m_passwordData = passwordUnicode(m_strPassword, 0); // 缓存编码后的密码
        }
        zip_set_default_password(archive, m_passwordData.constData());
        // ... 其他代码 ...
    }
}

mainwindow.cpp

void MainWindow::slotCompress(const QVariant &val) {
    // ... 其他代码 ...
    if ("application/zip" == m_stCompressParameter.strMimeType) {
        for (const QChar &ch : m_stCompressParameter.strPassword) {
            if (ch >= 0x4E00 && ch <= 0x9FA5) { // 直接比较 Unicode 值
                zipPasswordIsChinese = true;
                break;
            }
        }
    }
}

总结

这段代码的改进方向是正确的,但可以进一步优化:

  1. 统一密码编码逻辑并缓存结果。
  2. 增加错误处理和日志记录。
  3. 明确 passwordUnicode 的参数含义。
  4. 修复错误信息占位符问题。
  5. 考虑内存中密码的安全性。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, pengfeixx

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@pengfeixx pengfeixx merged commit da44e6a into linuxdeepin:develop/snipe Jan 20, 2026
15 checks passed
@pengfeixx pengfeixx deleted the fix-340777 branch January 20, 2026 06:01
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.

3 participants