diff --git a/LibrePass/API/LibrePassAPI.swift b/LibrePass/API/LibrePassAPI.swift index ddfd304..ce93a62 100644 --- a/LibrePass/API/LibrePassAPI.swift +++ b/LibrePass/API/LibrePassAPI.swift @@ -153,7 +153,7 @@ struct LibrePassClient { self.loginData = nil self.sharedKey = nil self.credentialsDatabase = nil - self.vault.vault = [] + self.vault = LibrePassDecryptedVault(lastSync: 0) } mutating func fetchCiphers() throws { @@ -215,6 +215,14 @@ struct LibrePassClient { newVaultToSync.append(false) } + for index in stride(from: self.vault.idstoDelete.count - 1, through: 0, by: -1) { + if let _ = try? self.delete(id: self.vault.idstoDelete[index]) { + if let _ = try? self.vault.remove(id: self.vault.idstoDelete[index], save: true) { + self.vault.idstoDelete.remove(at: index) + } + } + } + for encCipher in updated.ciphers { if self.vault.vault.firstIndex(where: { cipher in encCipher.id == cipher.id }) == nil { newVault.append(try LibrePassCipher(encCipher: encCipher, key: self.sharedKey!)) @@ -251,11 +259,11 @@ struct LibrePassClient { mutating func delete(id: String) throws { if networkMonitor.isConnected { _ = try self.client.request(path: "/api/cipher/" + id, body: nil, method: "DELETE") - - try self.vault.remove(id: id, save: true) } else { - throw LibrePassApiErrors.WithMessage(message: "Offline deletion is unsupported") + self.vault.idstoDelete.append(id) } + + try self.vault.remove(id: id, save: true) } func generateId() -> String { diff --git a/LibrePass/API/Vault.swift b/LibrePass/API/Vault.swift index 0b89353..d89d8f0 100644 --- a/LibrePass/API/Vault.swift +++ b/LibrePass/API/Vault.swift @@ -11,6 +11,7 @@ import CryptoKit struct LibrePassEncryptedVault: Codable { var vault: [LibrePassEncryptedCipher] = [] var toSync: [Bool] = [] + var idsToDelete: [String] = [] var lastSync: Int64 static func loadVault() throws -> Self { @@ -26,7 +27,7 @@ struct LibrePassEncryptedVault: Codable { } func decryptVault(key: SymmetricKey) throws -> LibrePassDecryptedVault { - var ciphers: LibrePassDecryptedVault = LibrePassDecryptedVault(toSync: self.toSync, lastSync: self.lastSync, key: key) + var ciphers: LibrePassDecryptedVault = LibrePassDecryptedVault(toSync: self.toSync, idstoDelete: self.idsToDelete, lastSync: self.lastSync, key: key) for (i, encCipher) in self.vault.enumerated() { try ciphers.addOrReplace(cipher: try LibrePassCipher(encCipher: encCipher, key: key), toSync: self.toSync[i], save: false) } @@ -42,6 +43,7 @@ struct LibrePassEncryptedVault: Codable { struct LibrePassDecryptedVault { var vault: [LibrePassCipher] = [] var toSync: [Bool] = [] + var idstoDelete: [String] = [] var lastSync: Int64 var key: SymmetricKey? @@ -77,7 +79,7 @@ struct LibrePassDecryptedVault { } func encryptVault() throws -> LibrePassEncryptedVault { - var encCiphers: LibrePassEncryptedVault = LibrePassEncryptedVault(toSync: self.toSync, lastSync: self.lastSync) + var encCiphers: LibrePassEncryptedVault = LibrePassEncryptedVault(toSync: self.toSync, idsToDelete: self.idstoDelete, lastSync: self.lastSync) for cipher in self.vault { encCiphers.vault.append(try LibrePassEncryptedCipher(cipher: cipher, key: self.key!)) } diff --git a/LibrePass/LibrePassApp.swift b/LibrePass/LibrePassApp.swift index 9f52755..b7601bc 100644 --- a/LibrePass/LibrePassApp.swift +++ b/LibrePass/LibrePassApp.swift @@ -38,7 +38,7 @@ struct MainWindow: View { } else { NavigationView { List { - NavigationLink(destination: LibrePassLoginWindow(lClient: $lClient, loggedIn: $loggedIn)) { + NavigationLink(destination: LibrePassLoginWindow(lClient: $lClient, loggedIn: $loggedIn, localLogIn: $localLogIn)) { Text("Log in") } NavigationLink(destination: LibrePassRegistrationWindow(lClient: $lClient)) { @@ -78,6 +78,7 @@ struct MainWindow: View { Text("Copyright © 2024 LibrePass Team") Text("LibrePass server: Medzik (Oskar) and contributors") Text("LibrePass app for iOS: Zapomnij (Jacek)") + Text("App is licensed under GPL v3 license") Link("See on Github", destination: URL(string: "https://github.com/LibrePass")!) .padding() diff --git a/LibrePass/LibrePassCipherView.swift b/LibrePass/LibrePassCipherView.swift index 085458d..b340b40 100644 --- a/LibrePass/LibrePassCipherView.swift +++ b/LibrePass/LibrePassCipherView.swift @@ -70,7 +70,7 @@ struct CipherLoginDataView: View { } Section(header: Text("Notes")) { - TextField("Notes", text: self.$notes) + TextField("Notes", text: self.$notes, axis: .vertical) } Section { @@ -107,8 +107,8 @@ struct CipherSecureNoteView: View { var body: some View { List { - TextFieldWithCopyButton(text: "Title", textBind: self.$title) - TextFieldWithCopyButton(text: "Note", textBind: self.$note) + TextField("Title", text: self.$title) + TextField("Note", text: self.$note, axis: .vertical) ButtonWithSpinningWheel(text: "Save", task: self.saveCipher) } @@ -151,7 +151,7 @@ struct CipherCardDataView: View { } Section(header: Text("Notes")) { - TextFieldWithCopyButton(text: "Notes", textBind: self.$notes) + TextField("Note", text: self.$notes, axis: .vertical) } Section { diff --git a/LibrePass/LibrePassLocalLogin.swift b/LibrePass/LibrePassLocalLogin.swift index ef4e168..c140452 100644 --- a/LibrePass/LibrePassLocalLogin.swift +++ b/LibrePass/LibrePassLocalLogin.swift @@ -24,26 +24,26 @@ struct LibrePassLocalLogin: View { ButtonWithSpinningWheel(text: "Unlock vault", task: self.login) } - Section(header: Text("If you're encountering crashes after update, try clearing local saved Vault. WARNING! THIS WILL DELETE VAULT SAVED ON THE DISK")) { + Section(header: Text("WARNING! THIS WILL DELETE VAULT SAVED ON THE DISK, but can fix crashes")) { ButtonWithSpinningWheel(text: "Clear vault", task: self.clearVault, color: Color.red) } } } func clearVault() throws { - self.errorString = " " - - let credentials = try LibrePassCredentialsDatabase.load() - self.lClient = try LibrePassClient(credentials: credentials, password: self.password) - - try self.lClient.fetchCiphers() - - self.lClient.unAuth() + if networkMonitor.isConnected { + let credentials = try LibrePassCredentialsDatabase.load() + self.lClient = try LibrePassClient(credentials: credentials, password: self.password) + + try self.lClient.fetchCiphers() + + self.lClient.unAuth() + } else { + throw LibrePassApiErrors.WithMessage(message: "Offline clearing vault can't be done") + } } func login() throws { - self.errorString = " " - let credentials = try LibrePassCredentialsDatabase.load() self.lClient = try LibrePassClient(credentials: credentials, password: self.password) try self.lClient.syncVault() diff --git a/LibrePass/LibrePassLoginWindow.swift b/LibrePass/LibrePassLoginWindow.swift index 06efc95..07e1433 100644 --- a/LibrePass/LibrePassLoginWindow.swift +++ b/LibrePass/LibrePassLoginWindow.swift @@ -15,6 +15,7 @@ struct LibrePassLoginWindow: View { @State private var apiServer = "https://api.librepass.org" @Binding var loggedIn: Bool + @Binding var localLogIn: Bool var body: some View { List { @@ -42,5 +43,6 @@ struct LibrePassLoginWindow: View { try lClient.login(email: self.email, password: self.password) try self.lClient.fetchCiphers() self.loggedIn = true + self.localLogIn = true } } diff --git a/LibrePass/LibrePassManagerWindow.swift b/LibrePass/LibrePassManagerWindow.swift index 21fbebb..15f2f0b 100644 --- a/LibrePass/LibrePassManagerWindow.swift +++ b/LibrePass/LibrePassManagerWindow.swift @@ -57,6 +57,15 @@ struct LibrePassManagerWindow: View { .foregroundStyle(Color.red) } + + Button(action: { + self.lClient.unAuth() + self.loggedIn = false + }) { + Image(systemName: "lock") + .foregroundColor(Color.yellow) + } + Button(action: { self.refreshIndicator = true }) { @@ -73,16 +82,6 @@ struct LibrePassManagerWindow: View { } } - .onAppear { - DispatchQueue.main.asyncAfter(deadline: .now()) { - while !self.loggedIn { - - } - - self.refreshIndicator = true - } - } - .alert(self.errorString, isPresented: self.$showAlert) { Button("OK", role: .cancel) { lClient.unAuth() @@ -119,7 +118,9 @@ struct LibrePassManagerWindow: View { } func syncVault() throws { - try self.lClient.syncVault() + if networkMonitor.isConnected { + try self.lClient.syncVault() + } } func deleteCiphers() throws {