From 55b682b4b0cf7e836be1cd099e4010178440d439 Mon Sep 17 00:00:00 2001 From: Lysann Tranvouez Date: Mon, 9 Mar 2026 22:16:15 +0100 Subject: [PATCH] improve directory deletion/editing handling --- pass/de.lproj/Localizable.strings | 1 + pass/en.lproj/Localizable.strings | 2 +- passKit/Helpers/AppError.swift | 2 +- passKit/Models/PasswordStore.swift | 13 +++- .../password-store-empty-dirs.git/HEAD | 1 + .../password-store-empty-dirs.git/config | 6 ++ .../password-store-empty-dirs.git/description | 1 + .../info/exclude | 6 ++ .../44/73d8218dcffe837e18d56d74c240e565461aea | Bin 0 -> 131 bytes .../4c/f9f177c4c015836fca6a31f9c3917e89ae29ec | Bin 0 -> 53 bytes .../50/96ac11d1376ea9b22ddedac1130f45ec618d11 | Bin 0 -> 57 bytes .../ce/013625030ba8dba906f756967f9e9ca394464a | Bin 0 -> 21 bytes .../d5/64d0bc3dd917926892c55e3706cc116d5b165e | Bin 0 -> 53 bytes .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin 0 -> 15 bytes .../fb/cbb5819e1c864ef33cfffa179a71387a5d90d0 | Bin 0 -> 131 bytes .../password-store-empty-dirs.git/packed-refs | 2 + passKitTests/Models/PasswordStoreTest.swift | 59 +++++++++++++++++- 17 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/HEAD create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/config create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/description create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/info/exclude create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/44/73d8218dcffe837e18d56d74c240e565461aea create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/4c/f9f177c4c015836fca6a31f9c3917e89ae29ec create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/50/96ac11d1376ea9b22ddedac1130f45ec618d11 create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/d5/64d0bc3dd917926892c55e3706cc116d5b165e create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/objects/fb/cbb5819e1c864ef33cfffa179a71387a5d90d0 create mode 100644 passKitTests/Fixtures/password-store-empty-dirs.git/packed-refs diff --git a/pass/de.lproj/Localizable.strings b/pass/de.lproj/Localizable.strings index 8177a35..355b200 100644 --- a/pass/de.lproj/Localizable.strings +++ b/pass/de.lproj/Localizable.strings @@ -72,6 +72,7 @@ "KeyImportError." = "Schlüssel kann nicht importiert werden."; "FileNotFoundError." = "Die Datei '%@' kann nicht gelesen werden."; "PasswordDuplicatedError." = "Passwort kann nicht hinzugefügt werden; es existiert bereits."; +"CannotDeleteNonEmptyDirectoryError." = "Ordner muss erst leer sein um gelöscht werden zu können."; "GitResetError." = "Der zuletzt synchronisierte Commit kann nicht identifiziert werden."; "GitCreateSignatureError." = "Es konnte keine valide Signatur für den Author/Committer angelegt werden."; "GitPushNotSuccessfulError." = "Die Übertragung der lokalen Änderungen war nicht erfolgreich. Stelle bitte sicher, dass auf dem Remote-Repository alle Änderungen commitet sind."; diff --git a/pass/en.lproj/Localizable.strings b/pass/en.lproj/Localizable.strings index 10d8b30..a4f74e3 100644 --- a/pass/en.lproj/Localizable.strings +++ b/pass/en.lproj/Localizable.strings @@ -73,7 +73,7 @@ "KeyImportError." = "Cannot import the key."; "FileNotFoundError." = "File '%@' cannot be read."; "PasswordDuplicatedError." = "Cannot add the password; password is duplicated."; -"CannotDeleteDirectoryError." = "Cannot delete directories; delete passwords instead."; +"CannotDeleteNonEmptyDirectoryError." = "Delete passwords from the directory before deleting the directory itself."; "GitResetError." = "Cannot identify the latest synced commit."; "GitCreateSignatureError." = "Cannot create a valid author/committer signature."; "GitPushNotSuccessfulError." = "Pushing local changes was not successful. Make sure there are no uncommitted changes on the remote repository."; diff --git a/passKit/Helpers/AppError.swift b/passKit/Helpers/AppError.swift index 8bcc84b..28ceb73 100644 --- a/passKit/Helpers/AppError.swift +++ b/passKit/Helpers/AppError.swift @@ -15,7 +15,7 @@ public enum AppError: Error, Equatable { case keyImport case readingFile(fileName: String) case passwordDuplicated - case cannotDeleteDirectory + case cannotDeleteNonEmptyDirectory case gitReset case gitCommit case gitCreateSignature diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 78c92c4..b918ab4 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -273,13 +273,15 @@ public class PasswordStore { } public func delete(passwordEntity: PasswordEntity) throws { - if passwordEntity.isDir { - throw AppError.cannotDeleteDirectory + if !passwordEntity.children.isEmpty { + throw AppError.cannotDeleteNonEmptyDirectory } let deletedFileURL = passwordEntity.fileURL(in: storeURL) let deletedFilePath = passwordEntity.path - try gitRm(path: passwordEntity.path) + if !passwordEntity.isDir { + try gitRm(path: passwordEntity.path) + } try deletePasswordEntities(passwordEntity: passwordEntity) try deleteDirectoryTree(at: deletedFileURL) try gitCommit(message: "RemovePassword.".localize(deletedFilePath)) @@ -287,6 +289,11 @@ public class PasswordStore { } public func edit(passwordEntity: PasswordEntity, password: Password, keyID: String? = nil) throws -> PasswordEntity? { + guard !passwordEntity.isDir else { + // caller should ensure this, so this is not a user-facing error + throw AppError.other(message: "Cannot edit a directory") + } + var newPasswordEntity: PasswordEntity? = passwordEntity let url = passwordEntity.fileURL(in: storeURL) diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/HEAD b/passKitTests/Fixtures/password-store-empty-dirs.git/HEAD new file mode 100644 index 0000000..b870d82 --- /dev/null +++ b/passKitTests/Fixtures/password-store-empty-dirs.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/config b/passKitTests/Fixtures/password-store-empty-dirs.git/config new file mode 100644 index 0000000..e6da231 --- /dev/null +++ b/passKitTests/Fixtures/password-store-empty-dirs.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/description b/passKitTests/Fixtures/password-store-empty-dirs.git/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/passKitTests/Fixtures/password-store-empty-dirs.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/info/exclude b/passKitTests/Fixtures/password-store-empty-dirs.git/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/passKitTests/Fixtures/password-store-empty-dirs.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/objects/44/73d8218dcffe837e18d56d74c240e565461aea b/passKitTests/Fixtures/password-store-empty-dirs.git/objects/44/73d8218dcffe837e18d56d74c240e565461aea new file mode 100644 index 0000000000000000000000000000000000000000..6fa149a030a864de0d0dd70acc3d69ad9e8ae592 GIT binary patch literal 131 zcmV-}0DS*=0V^p=O;s>7G-oh0FfcPQQP4{-NY~9wVF;MEM)0C}-pWn7_ih~&=68LQ z*ehsa00astnMJzgnI##z`6U^tMY?I3IjIajKR=cqIUw4ce=5uH=i!NUo$EB;KvbvZ l7L-)#0`)LlO}Vhg_NMrxj7dl1%-PNe=0=Of0RVWLF+DgWJPiN< literal 0 HcmV?d00001 diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/objects/4c/f9f177c4c015836fca6a31f9c3917e89ae29ec b/passKitTests/Fixtures/password-store-empty-dirs.git/objects/4c/f9f177c4c015836fca6a31f9c3917e89ae29ec new file mode 100644 index 0000000000000000000000000000000000000000..1c17f204ab847733104e72fef4ac750bd82d3e28 GIT binary patch literal 53 zcmV-50LuS(0V^p=O;s>9V=y!@Ff%bxNXyJg)hnqeVK~QVrpnB{;`U0m?_tyG=gnC> L#mx%x literal 0 HcmV?d00001 diff --git a/passKitTests/Fixtures/password-store-empty-dirs.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/passKitTests/Fixtures/password-store-empty-dirs.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 new file mode 100644 index 0000000000000000000000000000000000000000..711223894375fe1186ac5bfffdc48fb1fa1e65cc GIT binary patch literal 15 WcmbD(;O_Aj@1=EF ziU5wdlg13z29x7}F{f$bXaaxG`5bH-tY+t(^+-&Ly4=