Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling invalid signature, use default one. #931

Merged
merged 7 commits into from
Aug 18, 2023
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
26 changes: 23 additions & 3 deletions MailCore/API/MailApiError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,30 @@
import Foundation
import MailResources

/// Static definitions of Mail API error codes
enum MailApiErrorCode {
/// The email is not found
static let mailMessageNotFound = "mail__message_not_found"

/// Invalid credentials
static let invalidCredentials = "invalid_credentials"

/// The server does not know about the identity used in the request
static let identityNotFound = "identity__not_found"
}

public class MailApiError: MailError {
public static let apiMessageNotFound = MailApiError(code: "mail__message_not_found",
/// The email is not found
public static let apiMessageNotFound = MailApiError(code: MailApiErrorCode.mailMessageNotFound,
localizedDescription: MailResourcesStrings.Localizable
.errorMessageNotFound,
shouldDisplay: true)

public static let apiInvalidCredential = MailApiError(code: "invalid_credentials")
/// Invalid credentials
public static let apiInvalidCredential = MailApiError(code: MailApiErrorCode.invalidCredentials)

/// The server does not know bout the identity used in the request
public static let apiIdentityNotFound = MailApiError(code: MailApiErrorCode.identityNotFound, shouldDisplay: false)

static let allErrors: [MailApiError] = [
// General
Expand Down Expand Up @@ -112,7 +129,10 @@ public class MailApiError: MailError {
MailApiError(code: "attachment__store_to_drive_fail"),

// Message
MailApiError(code: "message__uid_is_not_valid")
MailApiError(code: "message__uid_is_not_valid"),

// Signatures / Identity
apiIdentityNotFound
]

static func mailApiErrorFromCode(_ code: String) -> MailApiError? {
Expand Down
52 changes: 48 additions & 4 deletions MailCore/Cache/DraftManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public final class DraftManager {
}

/// Save a draft server side
private func saveDraftRemotely(draft: Draft, mailboxManager: MailboxManager) async {
private func saveDraftRemotely(draft: Draft, mailboxManager: MailboxManager, retry: Bool = true) async {
guard draft.identityId != nil else {
SentrySDK.capture(message: "We are trying to send a draft without an identityId, this will fail.")
return
Expand All @@ -92,13 +92,47 @@ public final class DraftManager {
do {
try await mailboxManager.save(draft: draft)
} catch {
guard error.shouldDisplay else { return }
alertDisplayable.show(message: error.localizedDescription)
// Retry with default signature on missing identity
if retry,
let mailError = error as? MailApiError,
mailError == MailApiError.apiIdentityNotFound {
guard let updatedDraft = await setDefaultSignature(draft: draft, mailboxManager: mailboxManager) else {
return
}
await saveDraftRemotely(draft: updatedDraft, mailboxManager: mailboxManager, retry: false)
}
// show error if needed
else {
guard error.shouldDisplay else { return }
alertDisplayable.show(message: error.localizedDescription)
}
}
await draftQueue.endBackgroundTask(uuid: draft.localUUID)
}

public func send(draft: Draft, mailboxManager: MailboxManager) async -> Date? {
private func setDefaultSignature(draft: Draft, mailboxManager: MailboxManager) async -> Draft? {
try? await mailboxManager.refreshAllSignatures()
let storedSignatures = mailboxManager.getStoredSignatures()
guard let defaultSignature = storedSignatures.defaultSignature else {
return nil
}

var updatedDraft: Draft?
let realm = mailboxManager.getRealm()
try? realm.write {
guard let liveDraft = realm.object(ofType: Draft.self, forPrimaryKey: draft.localUUID) else {
return
}
liveDraft.identityId = "\(defaultSignature.id)"

realm.add(liveDraft, update: .modified)

updatedDraft = liveDraft.detached()
}
return updatedDraft
}

public func send(draft: Draft, mailboxManager: MailboxManager, retry: Bool = true) async -> Date? {
alertDisplayable.show(message: MailResourcesStrings.Localizable.snackbarEmailSending)

var sendDate: Date?
Expand All @@ -110,6 +144,16 @@ public final class DraftManager {
alertDisplayable.show(message: MailResourcesStrings.Localizable.snackbarEmailSent)
sendDate = cancelableResponse.scheduledDate
} catch {
// Retry with default signature on missing identity
if retry,
let mailError = error as? MailApiError,
mailError == MailApiError.apiIdentityNotFound {
guard let updatedDraft = await setDefaultSignature(draft: draft, mailboxManager: mailboxManager) else {
return nil
}
return await send(draft: updatedDraft, mailboxManager: mailboxManager, retry: false)
}

alertDisplayable.show(message: error.localizedDescription)
}
await draftQueue.endBackgroundTask(uuid: draft.localUUID)
Expand Down
10 changes: 10 additions & 0 deletions MailCore/Cache/MailboxManager/MailboxManager+Draft.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public extension MailboxManager {
try await deleteLocally(draft: draft)
throw error
} catch let error as MailApiError {
// Do not delete draft on invalid identity
guard error != MailApiError.apiIdentityNotFound else {
throw error
}

// The api returned an error
try await deleteLocally(draft: draft)
throw error
Expand All @@ -72,6 +77,11 @@ public extension MailboxManager {
}
}
} catch let error as MailApiError {
adrien-coye marked this conversation as resolved.
Show resolved Hide resolved
// Do not delete draft on invalid identity
guard error != MailApiError.apiIdentityNotFound else {
throw error
}

// The api returned an error for now we can do nothing about it so we delete the draft
try await deleteLocally(draft: draft)
throw error
Expand Down
Loading