Skip to content

fix: encrypt files added to an encrypted archive (#253) - #266

Merged
sarensw merged 1 commit into
mainfrom
sarensw/saving-an-encrypted-archive-adds-new-files-witho
Sep 21, 2026
Merged

sarensw merged 1 commit into
mainfrom
sarensw/saving-an-encrypted-archive-adds-new-files-witho

Conversation

@sarensw

@sarensw sarensw commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Adding a file to an encrypted zip, or to a 7z whose names are not encrypted, wrote the new file without a password. The archive kept its lock in the status bar, and the added file extracted without one.

What it was

A Save updates the archive with options that carry no password, and 7-Zip copies the entries it keeps as they are: the old files stayed encrypted, everything added came out in plain. A Save As that keeps the format and sets no new password took the same path. A 7z with encrypted names was spared, because 7-Zip reuses the password it needed to read them (#247).

Every save goes through SevenZipArchive.writeArchive, whichever engine read the archive, so that is where the fix is.

What changed

What an update writes anew into an encrypted archive takes the archive's own password, unless the save sets a new one:

  • The cipher follows the archive's. A ZipCrypto zip — what zip -e makes — stays ZipCrypto, so the tools that read it before, unzip and Archive Utility among them, still read all of it. It is 7-Zip's own rule for a zip it updates: AES as soon as one entry uses it.
  • The password is tried first on the entry with the least to decrypt. Nothing in a zip, or in a 7z with plain names, tells a wrong password before something is decrypted, and a typo when the archive was opened would lock the added files away under a password nobody knows. A wrong one is asked for again, the way Save As already asks.
  • A missing one is asked for. When the prompt was dismissed as the archive was opened, the save asks. Cancelling writes nothing.
  • A zip password 7-Zip cannot write with — Info-ZIP's zip takes any, 7-Zip only plain ASCII — refuses the addition with the reason instead of storing it in plain.

Removing a file from such a 7z failed for the same reason: 7-Zip packs the rest of the solid block again and had no password to read it with ("UpdateItems failed"). A 7z removal now takes the password too. Every 7z removal asks, although only one cutting into a solid block needs it; the ponytail: note in SevenZipWriter.swift says how to narrow that.

Tests

In SaveOptionsStateTests, through the archive window:

  • aFileAddedToALockedArchiveIsLockedToo — AES zip, ZipCrypto zip, 7z with plain names, 7z with encrypted names; Save and Save As; read by 7-Zip and by XAD. The added file is encrypted, in the archive's cipher, the password was asked for once, and unzip still reads the ZipCrypto one.
  • aSaveAsksForThePasswordItLacks — dismissed at opening, or wrong at opening: the save asks, a cancel changes nothing, the answer is used.
  • aZipPasswordTooOddToWriteWithRefusesTheAddition — a Unicode ZipCrypto password.

In SaveOptionsWriteTests:

  • EncryptedRemovalTests.aRemovalLeavesTheRestLocked — a 7z asks for the password (missing, wrong, right) and keeps the rest encrypted; a zip removes without one.

Each fails without the fix. Removing the password check or the cipher line makes them fail too.

Not in here

  • Editing an existing 7z is not enabled in the app at all; that is Edit existing 7z archives #265, with what it needs.
  • With XAD reading a zip, deleting a file can delete another entry, and so can deleting inside an archive opened within the archive. That comes as its own PR.

Closes #253

Summary by CodeRabbit

  • Bug Fixes
    • Saving new files to encrypted archives now preserves the archive’s encryption settings.
    • Saves request the source password when it is required and reject invalid or unsupported passwords without modifying the archive.
    • Removing files from encrypted archives now keeps the remaining entries encrypted.
    • Save As operations on encrypted archives no longer fail unnecessarily when writing back to the original file.

Adding a file to an encrypted zip, or to a 7z whose names are not
encrypted, wrote the new file without a password. The archive kept its
lock in the status bar, and the added file extracted without one.

A Save updates the archive with options that carry no password, and
7-Zip copies what it keeps as it is: the old files stayed encrypted,
everything added came out in plain. A Save As that keeps the format and
sets no new password took the same path. A 7z with encrypted names was
spared, because 7-Zip reuses the password it needed to read them.

The writer now gives what an update writes anew into an encrypted
archive the archive's own password, unless the save sets a new one:

- The cipher follows the archive's. A ZipCrypto zip stays ZipCrypto, so
  the tools that read it before, unzip and Archive Utility among them,
  still read all of it. It is 7-Zip's own rule for a zip it updates.
- The password is tried first on the entry with the least to decrypt.
  Nothing in a zip, or in a 7z with plain names, tells a wrong password
  before something is decrypted, and a typo when the archive was opened
  would lock the added files away under a password nobody knows. A
  wrong one is asked for again, the way Save As already asks.
- Without one, because the prompt was dismissed when the archive was
  opened, the save asks. Cancelling writes nothing.
- A zip password 7-Zip cannot write with, which Info-ZIP's zip allows,
  refuses the addition with the reason instead of storing it in plain.

Removing a file from such a 7z failed for the same reason: 7-Zip packs
the rest of its solid block again and had no password to read it with.
A 7z removal now takes the password too.

Closes #253
@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 110246f7-8138-4863-86b5-3c074c1d2d03

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad723c and e1a5b24.

📒 Files selected for processing (3)
  • Modules/Sources/Swift7zip/SevenZipWriter.swift
  • Modules/Tests/CoreTests/SaveOptionsStateTests.swift
  • Modules/Tests/CoreTests/SaveOptionsWriteTests.swift

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The writer now reuses a source archive’s password and cipher when adding content without explicit options. It validates passwords before writing and preserves encryption during removals. Tests cover encrypted zip and 7z archives, password prompts, invalid passwords, and reader engines.

Changes

Encrypted archive writes

Layer / File(s) Summary
Resolve source encryption settings
Modules/Sources/Swift7zip/SevenZipWriter.swift
writeArchive infers the source password and encryption cipher when new content is added to an encrypted archive. It validates the password and allows encrypted Save As operations onto the source file.
Validate locked archive saves
Modules/Tests/CoreTests/SaveOptionsStateTests.swift
Tests cover encrypted zip and 7z additions, both reader engines, copy and in-place saves, password prompts, cancellation, cipher preservation, and unsupported zip passwords.
Validate encrypted removals
Modules/Tests/CoreTests/SaveOptionsWriteTests.swift
Tests verify that removals leave retained entries encrypted and require correct passwords for 7z archives.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant SaveAsState
  participant SevenZipWriter
  participant EncryptedSource
  participant ArchiveOutput
  SaveAsState->>SevenZipWriter: Save archive with pending content
  SevenZipWriter->>EncryptedSource: Validate sourcePassword
  EncryptedSource-->>SevenZipWriter: Return source cipher
  SevenZipWriter->>ArchiveOutput: Write new and retained entries with encryption
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: encrypting files added to encrypted archives. It is concise and directly related to the implementation and objectives.
Linked Issues check ✅ Passed Issue [#253] requires encrypted additions to remain encrypted, password reuse or retry, cancellation without changes, cipher preservation, and rejection of unsupported ZIP passwords. `SevenZipWriter.w…
Out of Scope Changes check ✅ Passed The changes remain connected to issue [#253]. The 7z removal handling and its tests support the same encrypted-update path because 7z repacks data when entries are removed. The reviewed changes contai…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sarensw
sarensw merged commit 31d100f into main Sep 21, 2026
6 checks passed
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.

Saving an encrypted archive adds new files without a password

1 participant