Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions FlowCrypt.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@
9FC41183268118B1004C0A69 /* EmailProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EBC1266EBE0100F3BF5D /* EmailProviderMock.swift */; };
9FC413182683C492004C0A69 /* InMemoryPassPhraseStorageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC413172683C491004C0A69 /* InMemoryPassPhraseStorageTest.swift */; };
9FC413442683C912004C0A69 /* GmailServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC413432683C912004C0A69 /* GmailServiceTest.swift */; };
9FC7EAB3266A404D00F3BF5D /* PassPhraseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */; };
9FC7EB76266EB67B00F3BF5D /* EncryptedStorageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EB75266EB67B00F3BF5D /* EncryptedStorageProtocols.swift */; };
9FC7EBAA266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EBA9266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift */; };
9FD364862381EFCB00657302 /* SetupManuallyEnterPassPhraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD364852381EFCB00657302 /* SetupManuallyEnterPassPhraseViewController.swift */; };
Expand Down Expand Up @@ -611,7 +610,6 @@
9FC411892681191D004C0A69 /* PromiseTestExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromiseTestExtension.swift; sourceTree = "<group>"; };
9FC413172683C491004C0A69 /* InMemoryPassPhraseStorageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryPassPhraseStorageTest.swift; sourceTree = "<group>"; };
9FC413432683C912004C0A69 /* GmailServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GmailServiceTest.swift; sourceTree = "<group>"; };
9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassPhraseObject.swift; sourceTree = "<group>"; };
9FC7EB75266EB67B00F3BF5D /* EncryptedStorageProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedStorageProtocols.swift; sourceTree = "<group>"; };
9FC7EBA2266EB95300F3BF5D /* PassPhraseStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassPhraseStorageTests.swift; sourceTree = "<group>"; };
9FC7EBA9266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryPassPhraseStorage.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1088,7 +1086,6 @@
9F1B49E02624E19D00420472 /* Realm Models */ = {
isa = PBXGroup;
children = (
9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */,
D2F41372243CC7990066AFB5 /* UserObject.swift */,
D27B911C24EFE806002DF0A1 /* ContactObject.swift */,
D2E26F6924F25AB800612AF1 /* KeyAlgoObject.swift */,
Expand Down Expand Up @@ -2684,7 +2681,6 @@
D29AFFF92409767F00C1387D /* GoogleContactsResponse.swift in Sources */,
9F003D6125E1B4ED00EB38C0 /* TrashFolderProvider.swift in Sources */,
9FF0671025520D7100FCC9E6 /* MessageGateway.swift in Sources */,
9FC7EAB3266A404D00F3BF5D /* PassPhraseObject.swift in Sources */,
9F31AB8C23298B3F00CF87EA /* Imap+retry.swift in Sources */,
9F79229426696B9300DA3D80 /* KeyDataStorage.swift in Sources */,
9F82D352256D74FA0069A702 /* InboxViewContainerController.swift in Sources */,
Expand Down
23 changes: 14 additions & 9 deletions FlowCrypt/Controllers/Setup/SetupBackupsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,22 @@ extension SetupBackupsViewController {
return
}

// save pass phrase
matchingKeyBackups
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}
if !shouldStorePassPhrase {
// save pass phrase
matchingKeyBackups
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}
}

// save keys
keyStorage.addKeys(keyDetails: Array(matchingKeyBackups), source: .backup, for: user.email)
keyStorage.addKeys(keyDetails: Array(matchingKeyBackups),
passPhrase: shouldStorePassPhrase ? passPhrase : nil,
source: .backup,
for: user.email)

moveToMainFlow()
}
Expand Down
12 changes: 9 additions & 3 deletions FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,18 @@ extension SetupEKMKeyViewController {
passphrase: passPhrase
)
let parsedKey = try self.core.parseKeys(armoredOrBinary: encryptedPrv.encryptedKey.data())
self.keyStorage.addKeys(keyDetails: parsedKey.keyDetails, source: .ekm, for: self.user.email)
self.keyStorage.addKeys(keyDetails: parsedKey.keyDetails,
passPhrase: self.shouldStorePassPhrase ? passPhrase : nil,
source: .ekm,
for: self.user.email)
allFingerprints.append(contentsOf: parsedKey.keyDetails.flatMap { $0.fingerprints })
}
}
let passPhrase = PassPhrase(value: passPhrase, fingerprints: allFingerprints.unique())
self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase)

if !self.shouldStorePassPhrase {
let passPhrase = PassPhrase(value: passPhrase, fingerprints: allFingerprints.unique())
self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase)
}
}
.then(on: .main) { [weak self] in
self?.hideSpinner()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,15 @@ extension SetupGenerateKeyViewController {

try awaitPromise(self.backupService.backupToInbox(keys: [encryptedPrv.key], for: self.user))

let passPhrase = PassPhrase(value: passPhrase, fingerprints: encryptedPrv.key.fingerprints)

self.keyStorage.addKeys(keyDetails: [encryptedPrv.key], source: .generated, for: self.user.email)
self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase)
self.keyStorage.addKeys(keyDetails: [encryptedPrv.key],
passPhrase: self.shouldStorePassPhrase ? passPhrase: nil,
source: .generated,
for: self.user.email)

if !self.shouldStorePassPhrase {
let passPhrase = PassPhrase(value: passPhrase, fingerprints: encryptedPrv.key.fingerprints)
self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: false)
}

let updateKey = self.attester.updateKey(
email: userId.email,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,24 +241,27 @@ extension SetupManuallyEnterPassPhraseViewController {
let keysToUpdate = Array(Set(existedKeys).intersection(fetchedKeys))
let newKeysToAdd = Array(Set(fetchedKeys).subtracting(existedKeys))

keysStorage.addKeys(keyDetails: newKeysToAdd, source: .imported, for: email)
keysStorage.updateKeys(keyDetails: keysToUpdate, source: .imported, for: email)
keysStorage.addKeys(keyDetails: newKeysToAdd, passPhrase: passPhrase, source: .imported, for: email)
keysStorage.updateKeys(keyDetails: keysToUpdate, passPhrase: passPhrase, source: .imported, for: email)

keysToUpdate
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.updatePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}
if !shouldStorePassPhrase {
keysToUpdate
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.updatePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}

newKeysToAdd
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}
}

newKeysToAdd
.map {
PassPhrase(value: passPhrase, fingerprints: $0.fingerprints)
}
.forEach {
passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase)
}

hideSpinner()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ extension EncryptedStorage: LogOutHandler {
.filter { $0.email == email }
let keys = storage.objects(KeyInfo.self)
.filter { $0.account == email }
let passPhrases = storage.objects(PassPhraseObject.self)
.filter { keys.map(\.primaryFingerprint).contains($0.primaryFingerprint) }
let sessions = storage.objects(SessionObject.self)
.filter { $0.email == email }
let clientConfigurations = storage.objects(ClientConfigurationObject.self)
Expand All @@ -120,7 +118,6 @@ extension EncryptedStorage: LogOutHandler {
try storage.write {
storage.delete(keys)
storage.delete(sessions)
storage.delete(passPhrases)
storage.delete(clientConfigurations)
storage.delete(userToDelete)
}
Expand Down Expand Up @@ -159,30 +156,39 @@ extension EncryptedStorage {

// MARK: - Keys
extension EncryptedStorage {
func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) {
func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) {
guard let user = storage.objects(UserObject.self).first(where: { $0.email == email }) else {
logger.logError("Can't find user with given email to add keys. User should be already saved")
return
}
try! storage.write {
for key in keyDetails {
storage.add(try! KeyInfo(key, source: source, user: user))
storage.add(try! KeyInfo(key, passphrase: passPhrase, source: source, user: user))
}
}
}

func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) {
func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) {
guard let user = getUserObject(for: email) else {
logger.logError("Can't find user with given email to update keys. User should be already saved")
return
}
try! storage.write {
for key in keyDetails {
storage.add(try! KeyInfo(key, source: source, user: user), update: .all)
storage.add(try! KeyInfo(key, passphrase: passPhrase, source: source, user: user), update: .all)
}
}
}

func updateKeys(with primaryFingerprint: String, passphrase: String?) {
let keys = keysInfo()
.filter { $0.primaryFingerprint == primaryFingerprint }

try! storage.write {
keys.map { $0.passphrase = passphrase }
}
}

func keysInfo() -> [KeyInfo] {
let result = storage.objects(KeyInfo.self)
return Array(result)
Expand All @@ -209,25 +215,19 @@ extension EncryptedStorage {
// MARK: - PassPhrase
extension EncryptedStorage: PassPhraseStorageType {
func save(passPhrase: PassPhrase) {
try! storage.write {
storage.add(PassPhraseObject(passPhrase))
}
updateKeys(with: passPhrase.primaryFingerprint, passphrase: passPhrase.value)
}

func update(passPhrase: PassPhrase) {
try! storage.write {
storage.add(PassPhraseObject(passPhrase), update: .all)
}
updateKeys(with: passPhrase.primaryFingerprint, passphrase: passPhrase.value)
}

func remove(passPhrase: PassPhrase) {
try! storage.write {
storage.delete(PassPhraseObject(passPhrase))
}
updateKeys(with: passPhrase.primaryFingerprint, passphrase: nil)
}

func getPassPhrases() -> [PassPhrase] {
Array(storage.objects(PassPhraseObject.self)).map(PassPhrase.init)
keysInfo().compactMap(PassPhrase.init)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import Foundation

protocol KeyStorageType {
func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String)
func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String)
func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String)
func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String)
func publicKey() -> String?
func keysInfo() -> [KeyInfo]
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ extension Imap {
self.fetchMessage(in: folder, kind: kind, uids: uids)
}) else { return }

guard let messages = msgs as? [MCOIMAPMessage] else {
guard let messages = msgs else {
return reject(AppErr.cast("[MCOIMAPMessage]"))
}
return resolve(messages)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension Imap {
.start { error, messages, _ in // original method sig has 3 args, finalize expects 2 args
self.finalize("fetchMsgsByNumber", resolve, reject, retry: {
self.fetchMsgsByNumber(for: folder, kind: kind, set: set)
})(error, messages as? [MCOIMAPMessage])
})(error, messages)
}
}
}
Expand All @@ -49,7 +49,7 @@ extension Imap {
.start { error, messages, _ in // original method sig has 3 args, finalize expects 2 args
self.finalize("fetchMessagesByUIDOperation", resolve, reject, retry: {
self.fetchMessagesByUIDOperation(for: folder, kind: kind, set: set)
})(error, messages as? [MCOIMAPMessage])
})(error, messages)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extension Imap {

extension MCOIMAPSession {
func log() -> Self {
connectionLogger = { connectionID, type, data in
connectionLogger = { _, type, data in
guard let data = data, let string = String(data: data, encoding: .utf8) else { return }
Logger.nested("IMAP").logInfo("\(type):\(string)")
}
Expand All @@ -93,7 +93,7 @@ extension MCOIMAPSession {

extension MCOSMTPSession {
func log() -> Self {
connectionLogger = { connectionID, type, data in
connectionLogger = { _, type, data in
guard let data = data, let string = String(data: data, encoding: .utf8) else { return }
Logger.nested("SMTP").logInfo("\(type):\(string)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension Imap: RemoteFoldersProviderType {
reject(ImapError.providerError(error))
return
}
guard let folders = value as? [MCOIMAPFolder] else {
guard let folders = value else {
return reject(AppErr.cast("[MCOIMAPFolder]"))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ final class KeyDataStorage {
}

extension KeyDataStorage: KeyStorageType {
func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) {
encryptedStorage.updateKeys(keyDetails: keyDetails, source: source, for: email)
func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) {
encryptedStorage.updateKeys(keyDetails: keyDetails, passPhrase: passPhrase, source: source, for: email)
}

func publicKey() -> String? {
Expand All @@ -34,7 +34,7 @@ extension KeyDataStorage: KeyStorageType {
encryptedStorage.keysInfo()
}

func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) {
encryptedStorage.addKeys(keyDetails: keyDetails, source: source, for: email)
func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) {
encryptedStorage.addKeys(keyDetails: keyDetails, passPhrase: passPhrase, source: source, for: email)
}
}
22 changes: 11 additions & 11 deletions FlowCrypt/Functionality/Services/Key Services/KeyService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,19 @@ final class KeyService: KeyServiceType {
}

// append keys to ensure with a pass phrase
if let passPhrase = passPhrase {
let keysToEnsure = keysInfo.map {
PrvKeyInfo(
private: $0.private,
longid: $0.primaryLongid,
passphrase: passPhrase,
fingerprints: Array($0.allFingerprints)
)
}

privateKeys.append(contentsOf: keysToEnsure)
let keysToEnsure: [PrvKeyInfo] = keysInfo.compactMap {
guard let passPhraseValue = $0.passphrase ?? passPhrase else { return nil }

return PrvKeyInfo(
private: $0.private,
longid: $0.primaryLongid,
passphrase: passPhraseValue,
fingerprints: Array($0.allFingerprints)
)
}

privateKeys.append(contentsOf: keysToEnsure)

return .success(privateKeys)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ struct PassPhrase: Codable, Hashable, Equatable {
}
}

extension PassPhrase {
init?(keyInfo: KeyInfo) {
guard let passphrase = keyInfo.passphrase else { return nil }

self.init(value: passphrase,
fingerprints: Array(keyInfo.allFingerprints))
}
}

// MARK: - Pass Phrase Storage
protocol PassPhraseStorageType {
func save(passPhrase: PassPhrase)
Expand Down
4 changes: 3 additions & 1 deletion FlowCrypt/Models/Realm Models/KeyInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ final class KeyInfo: Object {
let allFingerprints = List<String>()
let allLongids = List<String>()

@objc dynamic var passphrase: String?
@objc dynamic var source: String = ""
@objc dynamic var user: UserObject!

convenience init(_ keyDetails: KeyDetails, source: KeySource, user: UserObject) throws {
convenience init(_ keyDetails: KeyDetails, passphrase: String?, source: KeySource, user: UserObject) throws {
self.init()

guard let privateKey = keyDetails.private else {
Expand All @@ -51,6 +52,7 @@ final class KeyInfo: Object {
self.`public` = keyDetails.public
self.allFingerprints.append(objectsIn: keyDetails.ids.map(\.fingerprint))
self.allLongids.append(objectsIn: keyDetails.ids.map(\.longid))
self.passphrase = passphrase
self.source = source.rawValue
self.user = user
}
Expand Down
Loading