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
40 changes: 19 additions & 21 deletions FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,10 @@ private actor Service {
variant: .curve25519,
userIds: [userId]
)
try await appContext.getBackupService().backupToInbox(keys: [encryptedPrv.key], for: user)

try appContext.encryptedStorage.putKeypairs(
keyDetails: [encryptedPrv.key],
passPhrase: storageMethod == .persistent ? passPhrase: nil,
source: .generated,
for: user.email
)
try await submitKeyToAttester(email: userId.email, publicKey: encryptedPrv.key.public)
try await appContext.getBackupService().backupToInbox(keys: [encryptedPrv.key], for: user)
try await putKeypairsInEncryptedStorage(encryptedPrv: encryptedPrv, storageMethod: storageMethod, passPhrase: passPhrase)

if storageMethod == .memory {
let passPhrase = PassPhrase(
Expand All @@ -119,42 +115,44 @@ private actor Service {
try appContext.passPhraseService.savePassPhrase(with: passPhrase, storageMethod: .memory)
}

await submitKeyToAttesterAndShowAlertOnFailure(
email: userId.email,
publicKey: encryptedPrv.key.public,
viewController: viewController
)

// sending welcome email is not crucial, so we don't handle errors
_ = try? await attester.testWelcome(
email: userId.email,
pubkey: encryptedPrv.key.public
)
}

private func submitKeyToAttesterAndShowAlertOnFailure(
@MainActor
private func putKeypairsInEncryptedStorage(encryptedPrv: CoreRes.GenerateKey, storageMethod: StorageMethod, passPhrase: String) throws {
try appContext.encryptedStorage.putKeypairs(
keyDetails: [encryptedPrv.key],
passPhrase: storageMethod == .persistent ? passPhrase: nil,
source: .generated,
for: user.email
)
}

private func submitKeyToAttester(
email: String,
publicKey: String,
viewController: ViewController
) async {
publicKey: String
) async throws {
do {
_ = try await attester.update(
email: email,
pubkey: publicKey,
token: appContext.dataService.token
)
} catch {
let message = "Failed to submit Public Key"
await viewController.showAlert(error: error, message: message)
throw CreateKeyError.submitKey(error)
}
}

private func getUserId() throws -> UserId {
guard let email = appContext.dataService.email, !email.isEmpty else {
throw CreateKeyError.missedUserEmail
throw CreateKeyError.missingUserEmail
}
guard let name = appContext.dataService.currentUser?.name, !name.isEmpty else {
throw CreateKeyError.missedUserName
throw CreateKeyError.missingUserName
}
return UserId(email: email, name: name)
}
Expand Down
5 changes: 4 additions & 1 deletion FlowCrypt/Functionality/DataManager/DataService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ extension DataService: DataServiceType {
appDelegateGoogleSessionContainer: nil // needed only when signing in/out
).accessToken
default:
return nil
guard let currentUser = currentUser else {
return nil
}
return Imap(user: currentUser).imapSess?.oAuth2Token
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ private struct ComposedErrorHandler: ErrorHandler {
handlers: [
KeyServiceErrorHandler(),
BackupServiceErrorHandler(),
CreateKeyErrorHandler()
]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,37 @@ import UIKit

enum CreateKeyError: Error {
case weakPassPhrase(_ strength: CoreRes.ZxcvbnStrengthBar)
// Missing user email
case missedUserEmail
// Missing user name
case missedUserName
// Pass phrases don't match
/// Missing user email
case missingUserEmail
/// Missing user name
case missingUserName
/// Pass phrases don't match
case doesntMatch
// silent abort
/// Silent abort
case conformingPassPhraseError
/// Failed to submit key
case submitKey(Error)
}

extension CreateKeyError: CustomStringConvertible {
var description: String {
switch self {
case .weakPassPhrase(let strength):
return "Pass phrase strength: \(strength.word.word)\ncrack time: \(strength.time)\n\nWe recommend to use 5-6 unrelated words as your Pass Phrase."
case .missingUserEmail:
return "backupServiceError_email".localized
case .missingUserName:
return "backupServiceError_name".localized
case .doesntMatch:
return "pass_phrase_match_error".localized
case .submitKey(let error):
return "submit_key_error".localized
+ "\n"
+ "\(error.errorMessage)"
case .conformingPassPhraseError:
return ""
}
}
}

// KeyServiceError
Expand All @@ -44,31 +67,3 @@ struct KeyServiceErrorHandler: ErrorHandler {
return true
}
}

// CreateKeyError
struct CreateKeyErrorHandler: ErrorHandler {
func handle(error: Error, for viewController: UIViewController) -> Bool {
let errorMessage: String?

switch error as? CreateKeyError {
case .weakPassPhrase(let strength):
errorMessage = "Pass phrase strength: \(strength.word.word)\ncrack time: \(strength.time)\n\nWe recommend to use 5-6 unrelated words as your Pass Phrase."
case .missedUserEmail:
errorMessage = "backupServiceError_email".localized
case .missedUserName:
errorMessage = "backupServiceError_name".localized
case .doesntMatch:
errorMessage = "pass_phrase_match_error".localized
case .conformingPassPhraseError:
errorMessage = nil
case .none:
errorMessage = nil
}

guard let message = errorMessage else { return false }

viewController.showAlert(message: message)

return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import Foundation

extension Imap: MessageGateway {
func sendMail(input: MessageGatewayInput, progressHandler: ((Float) -> Void)?) async throws {
try await withCheckedThrowingContinuation { [weak smtpSess] (continuation: CheckedContinuation<Void, Error>) in
guard let session = smtpSess else {
return continuation.resume(returning: ())
try await withCheckedThrowingContinuation { [weak self] (continuation: CheckedContinuation<Void, Error>) in
guard let session = self?.smtpSess else {
return continuation.resume(throwing: ImapError.noSession)
}

session.sendOperation(with: input.mime)
Expand Down
16 changes: 12 additions & 4 deletions FlowCrypt/Functionality/Services/ApiCall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,24 @@ struct ApiError: LocalizedError {

extension ApiError {
static func create(from httpError: HttpErr, request: ApiCall.Request) -> Self {
guard
let data = httpError.data,
let object = try? JSONDecoder().decode(HttpError.self, from: data)
else {
guard let data = httpError.data else {
return ApiError(
errorDescription: httpError.error?.localizedDescription ?? "",
internalError: httpError.error
)
}

guard let object = try? JSONDecoder().decode(HttpError.self, from: data) else {
let errorDescription = httpError.error?.localizedDescription
?? String(data: data, encoding: .utf8)
?? "missing error description"

return ApiError(
errorDescription: errorDescription,
internalError: httpError.error
)
}

var message = "\(request.apiName) \(object.code) \(object.message)"
message += "\n"
message += "\(request.method) \(request.url)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extension BackupService: BackupServiceType {
}
}

@MainActor
func backupToInbox(keys: [KeyDetails], for userId: UserId) async throws {
let isFullyEncryptedKeys = keys.map(\.isFullyDecrypted).contains(false)

Expand Down
2 changes: 2 additions & 0 deletions FlowCrypt/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,5 @@
"imap_error_no_session" = "Session isn't established";
"imap_error_provider" = "Provider error %@";
"imap_error_msg_info" = "Can't parse message without \"%@\"";

"submit_key_error" = "Failed to submit Public Key";
13 changes: 10 additions & 3 deletions FlowCryptAppTests/ExtensionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,20 @@ extension ExtensionTests {
timeZone: .current,
year: year,
month: 1,
day: 24
day: 24,
hour: 18,
minute: 34,
second: 9
).date)
// Jan 24, 2020
let otherYearDate = Date(timeIntervalSince1970: 1579883652)

XCTAssertTrue(dateFormatter.date(from: DateFormatter().formatDate(sameDayDate)) != nil)
XCTAssertEqual(DateFormatter().formatDate(sameYearDate), "Jan 24")
XCTAssertEqual(DateFormatter().formatDate(otherYearDate), "Jan 24, 2020")
if Calendar.current.isDateInToday(sameYearDate) {
XCTAssertEqual(dateFormatter.formatDate(sameYearDate), "18:34")
} else {
XCTAssertEqual(dateFormatter.formatDate(sameYearDate), "Jan 24")
}
XCTAssertEqual(dateFormatter.formatDate(otherYearDate), "Jan 24, 2020")
}
}