diff --git a/enzevalos_iphone/PermissionModel.swift b/enzevalos_iphone/PermissionModel.swift index 2392b679d4b7c1a39a03806b00b6ae3b1f963d7a..4ded1bf5ac52a65bc1b89f51089fbefa2226eb8a 100644 --- a/enzevalos_iphone/PermissionModel.swift +++ b/enzevalos_iphone/PermissionModel.swift @@ -9,15 +9,12 @@ import Contacts enum PermissionState { - case CONTACTPERMISSION, BACKGROUNDPERMISSION, FINISH + case CONTACTPERMISSION, NOTIFICATIONPERMISSION, CONTACTDENIED } class PermissionModel: ObservableObject { - @Published var currentState: PermissionState = .CONTACTPERMISSION - private var contactStore = CNContactStore() - init() { currentState = .CONTACTPERMISSION @@ -27,41 +24,42 @@ class PermissionModel: ObservableObject { func requestForAccess(_ completionHandler: @escaping (_ accessGranted: Bool) -> Void) { //requesting for authorization let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts) - + switch authorizationStatus { case .authorized: completionHandler(true) - + case .notDetermined: - self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in + self.contactStore.requestAccess(for: CNEntityType.contacts) { (access, accessError) -> Void in if access { completionHandler(access) } else { - if authorizationStatus == CNAuthorizationStatus.denied { - } + if authorizationStatus == CNAuthorizationStatus.denied { } completionHandler(false) } - }) - + } + default: completionHandler(false) } } - + func contactCheck(_ accessGranted: Bool) { if accessGranted { requestForNotifications() } else { - DispatchQueue.main.async(execute: { - self.showMessage(NSLocalizedString("AccessNotGranted", comment: ""), completion: self.requestForNotifications) - }); + DispatchQueue.main.async { self.currentState = .CONTACTDENIED } + do { sleep(3) } + self.requestForNotifications() } } func requestForNotifications(){ + DispatchQueue.main.async { + self.currentState = .NOTIFICATIONPERMISSION + } UNUserNotificationCenter.current().requestAuthorization(options: [ .badge], completionHandler: {didAllow, error in DispatchQueue.main.async { - self.currentState = .FINISH LetterboxModel.instance.afterPermissions() } }) @@ -69,14 +67,11 @@ class PermissionModel: ObservableObject { func showMessage(_ message: String, completion: (() -> Void)?) { let alertController = UIAlertController(title: "Letterbox", message: message, preferredStyle: UIAlertController.Style.alert) - + let dismissAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.default) { (action: UIAlertAction) -> Void in - if let cb = completion { - cb() - } + if let cb = completion { cb() } } alertController.addAction(dismissAction) } - - } + diff --git a/enzevalos_iphone/PreviewSampleData/SimulatorData.swift b/enzevalos_iphone/PreviewSampleData/SimulatorData.swift index ad19e1b50a6010f7f73b7cc3a0f245a37041a608..5040ecc758a501989153c8bec7803bf8a34fc808 100644 --- a/enzevalos_iphone/PreviewSampleData/SimulatorData.swift +++ b/enzevalos_iphone/PreviewSampleData/SimulatorData.swift @@ -192,6 +192,13 @@ struct ProxyMail: DisplayMail { return nil } + var encryptionType: CryptoScheme? { + if self.encryptionState != .NoEncryption { + return .PGP + } + return nil + } + var folderType: FolderType var isRead: Bool = false diff --git a/enzevalos_iphone/SwiftUI/Contact/ContactView.swift b/enzevalos_iphone/SwiftUI/Contact/ContactView.swift index aba0935a46e7feef5a54f9c86071afe5dfcb191c..9aa96309808f79e4bab044a93d4a4d7cb4d51988 100644 --- a/enzevalos_iphone/SwiftUI/Contact/ContactView.swift +++ b/enzevalos_iphone/SwiftUI/Contact/ContactView.swift @@ -15,6 +15,10 @@ struct ContactView <C: DisplayContact, M: DisplayMail>: View { public var fromMail: M? public var derivedFromKey: Bool = true +// init(contact: C, fromMail: M? = nil) { +// self.contact = contact +// } + var body: some View { TabView{ ForEach(Tabs, id: \.id ){ tab in diff --git a/enzevalos_iphone/SwiftUI/DisplayProtocols.swift b/enzevalos_iphone/SwiftUI/DisplayProtocols.swift index 7d936f3720af5b5e79d6360e2fde79c2a8583763..4af400ede769dea7d1ed96a5f78dfb33888ba461 100644 --- a/enzevalos_iphone/SwiftUI/DisplayProtocols.swift +++ b/enzevalos_iphone/SwiftUI/DisplayProtocols.swift @@ -175,6 +175,7 @@ protocol DisplayMail { // Crypto var signatureState: SignatureState { get } var encryptionState: EncryptionState { get } + var encryptionType: CryptoScheme? { get } var transportEnc: Bool { get } var signatureKey: K? { get } @@ -190,6 +191,12 @@ extension DisplayMail { // message contained new public key */ + var signatureType: CryptoScheme? { + get { + return signatureKey?.type ?? nil + } + } + var title: String { get { var key = "" diff --git a/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift b/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift index a326d7cec1413a3ac356c6c4eddc0aead964a4e6..5e42ec2087c9a149c5c332e56d744c2fc1281717 100644 --- a/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift +++ b/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift @@ -38,6 +38,7 @@ struct MailListView: View { .onAppear(perform: { self.updateMails() }) + .sheet(isPresented: $composeMail, content: { ComposeView() }) @@ -51,7 +52,6 @@ struct MailListView: View { .padding(-10) // Toolbar HStack { - self.idButton Spacer() self.lastUpdate Spacer() @@ -70,15 +70,7 @@ struct MailListView: View { } .resignKeyboardOnDragGesture() // hide keyboard when dragging } - - private var idButton: some View { - Button(action: { - print("Go to my id") - }, label: { - Text(NSLocalizedString("KeyID", comment: "id")) - }) - } - + private var composeButton: some View { Button(action: { composeMail = true diff --git a/enzevalos_iphone/SwiftUI/Onboarding/PermissionRequestView.swift b/enzevalos_iphone/SwiftUI/Onboarding/PermissionRequestView.swift index e1db4f287d7398a286d2291e25716a4b43bccaab..0793f64b677e1712a48dab41a1164853ba01ac16 100644 --- a/enzevalos_iphone/SwiftUI/Onboarding/PermissionRequestView.swift +++ b/enzevalos_iphone/SwiftUI/Onboarding/PermissionRequestView.swift @@ -9,27 +9,60 @@ import SwiftUI struct PermissionRequestView: View { - // TODO: Text should fit to permission request. @ObservedObject private var model = PermissionModel() - var title: LocalizedStringKey = "Permission.AccessContacts.Title" - var description: LocalizedStringKey = "Permission.AccessContacts.Description" + // contact access request background text + var contactPermissionTitle: LocalizedStringKey = "Permission.AccessContacts.Title" + var contactPermissionDescription: LocalizedStringKey = "Permission.AccessContacts.Description" + // notification access request background text + var notificationPermissionTitle: LocalizedStringKey = "Permission.Notification.Title" + var notificationPermissionDescription: LocalizedStringKey = "Permission.Notification.Description" + + // contact access denied background text + var contactPermissionDeniedTitle: LocalizedStringKey = "Permission.contactDenied.Title" + var contactPermissionDeniedDescription: LocalizedStringKey = "Permission.contactDenied.Description" + + // icons + var contactIcon = Image(systemName: "person.crop.circle.fill") + var notificationIcon = Image(systemName: "bell.fill") + var contactDeniedIcon = Image(systemName: "person.fill.xmark") + var body: some View { - VStack(alignment: .center){ - Text(title) - .font(.largeTitle) - .padding(.all) - Text(description) - .font(.body) - .padding(.all) + // view progression based on state of permission model + switch model.currentState { + + case .CONTACTPERMISSION : VStack{ + Text(contactIcon).font(.largeTitle) + Text(contactPermissionTitle).font(.largeTitle).padding(.all) + Text(contactPermissionDescription).font(.body).multilineTextAlignment(.center).padding(.all) Spacer() } + + case .NOTIFICATIONPERMISSION : VStack{ + Text(notificationIcon).font(.largeTitle) + Text(notificationPermissionTitle).font(.largeTitle).padding(.all) + Text(notificationPermissionDescription).font(.body).multilineTextAlignment(.center).padding(.all) + Spacer() + } + + case .CONTACTDENIED : VStack{ + Text(contactDeniedIcon).font(.largeTitle) + Text(contactPermissionDeniedTitle).font(.largeTitle).padding(.all) + Text(contactPermissionDeniedDescription).font(.body).multilineTextAlignment(.center).padding(.all) + Spacer() + } + } } -} + struct PermissionRequestView_Previews: PreviewProvider { static var previews: some View { PermissionRequestView() } } +} + + + + diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index b3fb78e97a6df7fbedd719a1832fd445e296f8c3..97c8e89c85f9dbb798290889e144fc8c6e6eacc9 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -20,8 +20,6 @@ import SwiftUI struct ReadMainView <M: DisplayMail>: View { @ObservedObject var model: ReadModel<M> - - var body: some View { TabView(selection: $model.currentTab){ ForEach(Tabs, id: \.id ){ tab in @@ -40,7 +38,7 @@ struct ReadMainView <M: DisplayMail>: View { Text(model.mail.subject) } - var Tabs:[Tab] { + var Tabs: [Tab] { get { return [ Tab( diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift index 6cb2d220bc47adcf3bf6b85e3237b34cac212a5f..335fde2c26014ff2688efe719d4c6a8bc0a2db77 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift @@ -30,6 +30,12 @@ struct SecurityBriefingView<M: DisplayMail>: View { Divider() authenticity Divider() + + // if mail is encrypted or/and signed, display "PGP" or "S/MIME" + if model.mail.encryptionType != nil || model.mail.signatureType != nil { + encryptionType + Divider() + } actions } } @@ -41,7 +47,34 @@ struct SecurityBriefingView<M: DisplayMail>: View { var title: some View { Text("ReadView.SecurityBriefing.Title") .font(.largeTitle) - .fixedSize(horizontal: false, vertical: true) + .fixedSize(horizontal: false, vertical: true) + } + + var encryptionType: some View { + var type: String { + get { + if let type = model.mail.encryptionType { + return type.description + } + else if let type = model.mail.signatureType { + return type.description + } + return "no crypto." + } + } + + + return HStack { + VStack(alignment: .leading) { + Text("EncryptionType") + .font(.headline) + .padding(padding) + (Text("ReadView.SecurityBriefing.EncryptionType.Text") + + Text(type).fontWeight(.bold) + Text(".")) + .padding(padding) + } + Spacer() + } } var confidentiality: some View { @@ -80,25 +113,28 @@ struct SecurityBriefingView<M: DisplayMail>: View { } var actions: some View { - VStack (alignment: .leading){ - Text("ReadView.SecurityBriefing.Actions.Title") - .font(.headline) - .padding(padding) - Text("ReadView.SecurityBriefing.Actions.Description") - .fontWeight(.light) - .padding(padding) - .fixedSize(horizontal: false, vertical: true) - ForEach(0..<model.mail.buttonActions.count) {index in - Button(action: { - self.choseAction(action: self.model.mail.buttonActions[index]) - }, label: { - Text(self.model.mail.buttonActions[index].title) - .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) - .addBorder(self.model.mail.buttonActions[index].color, width: 1, cornerRadius: 30) - .padding(.vertical, 10) - .padding(.horizontal, 20) - }) + HStack { + VStack (alignment: .leading){ + Text("ReadView.SecurityBriefing.Actions.Title") + .font(.headline) + .padding(padding) + Text("ReadView.SecurityBriefing.Actions.Description") + .fontWeight(.light) + .padding(padding) + .fixedSize(horizontal: false, vertical: true) + ForEach(0..<model.mail.buttonActions.count) {index in + Button(action: { + self.choseAction(action: self.model.mail.buttonActions[index]) + }, label: { + Text(self.model.mail.buttonActions[index].title) + .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) + .addBorder(self.model.mail.buttonActions[index].color, width: 1, cornerRadius: 30) + .padding(.vertical, 10) + .padding(.horizontal, 20) + }) + } } + Spacer() } } @@ -129,9 +165,8 @@ struct WarningView: View { ctaButton = ButtonStruct(titleKey: ctaTitle, action: ctaAction, type: .CTA) } moreButtons = warning.moreButtons - - } + var body: some View { VStack { Text(title) @@ -165,7 +200,7 @@ struct WarningView: View { } .padding(20) .addBorder(color, width: 3, cornerRadius: 30) - .padding(5) + .padding(10) } func choseAction (action: ButtonAction) { @@ -185,15 +220,18 @@ struct InfoView: View { var rating: Rating var body: some View { - VStack(alignment: .leading) { - Text(titleString) - .font(.headline) - .padding(padding) - HStack { - icon - Text(stateString) + HStack{ + VStack(alignment: .leading) { + Text(titleString) + .font(.headline) .padding(padding) + HStack { + icon + Text(stateString) + .padding(padding) + } } + Spacer() } } @@ -208,7 +246,7 @@ struct InfoView: View { image = Image(systemName: "hand.thumbsdown") color = Color(ThemeManager.unencryptedMessageColor()) case .Negativ: - image = Image(systemName: "xmark.ocatgon.fill") + image = Image(systemName: "xmark.octagon.fill") color = Color(ThemeManager.troubleMessageColor()) } image = image.resizable() @@ -239,15 +277,23 @@ struct DialogButtonLabel: View { .padding(10) .addBorder(color, width: 1, cornerRadius: 30) .padding(10) - } } struct SecurityBriefingView_Previews: PreviewProvider { - static var model = ReadModel(mail: ProxyData.SecureMail) + // 0: SecureMail, 1: PlainMail, 2: SignedOnlyMail, + // 3: MissingPKMail, 4: NotDecryptedMail, 5: CorruptedMail + static var model = ReadModel(mail: ProxyData.mails[0]) static var previews: some View { - model.currentTab = ReadPart.Security.value +// model.currentTab = ReadPart.Security.value let sim = Simulators<ReadMainView<ProxyMail>>() - return sim.previews(view: ReadMainView(model: model)) + return Group { + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[0]))) + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[1]))) + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[2]))) + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[3]))) + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[4]))) + sim.previews(view: ReadMainView(model: ReadModel(mail: ProxyData.mails[5]))) + } } } diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift index 6eaecfe5be0d59a6a2a89e2b524f4e60b43c0909..1c574ac0ca37b441bdbb5f09e518eb5d9b2b05bb 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift @@ -31,37 +31,24 @@ struct SmallContactListView <C: DisplayContact>: View { } if showList { ForEach(contacts, id: \.email) {contact in - Group { - HStack { - CircleImage(image: contact.myImage, radius: 40) - VStack (alignment: .leading, spacing: 2){ - Text(contact.name) - .font(.subheadline) - Text(contact.email) - .foregroundColor(.gray) - } - Spacer() - Button(action: {self.goToContact(contact: contact)}){ - Image(systemName: "chevron.right") + NavigationLink(destination: ContactView<C, MailRecord>(contact: contact, fromMail: nil)) { + HStack { + CircleImage(image: contact.myImage, radius: 40) + VStack (alignment: .leading, spacing: 2){ + Text(contact.name) + .font(.headline) + Text(contact.email) + .foregroundColor(.secondary) } + Spacer() + Image(systemName: "chevron.right") } - } - .onTapGesture { - self.goToContact(contact: contact) - } + } } } } .padding(10) } - - private func goToContact(contact: C) { - /* TODOguard let con = contact.keyRecord else { - return - } */ - return - // AppDelegate.getAppDelegate().readViewCoordinator?.pushContactView(contact: con) - } } diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift index b1f6f14b217836e545e62aaaa29f4532d3278346..de1f69c47b90a27a261a68e5c7f59fbd5919b58b 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift @@ -73,39 +73,36 @@ struct SenderViewMain <M: DisplayMail>: View { } private var icon: some View { - model.mail.sender.myImage - .resizable() - .frame(width: 130, height: 110) - .clipShape(Circle()) - .overlay(Circle().stroke(Color.white, lineWidth: 4)) - .shadow(radius: 10) - .offset(y: -110/2) - .padding(.bottom, -110/2) - .onTapGesture { - self.goToContact(contact: self.model.mail.sender) + NavigationLink(destination: ContactView(contact: model.mail.sender, fromMail: model.mail)) { + model.mail.sender.myImage + .resizable() + .frame(width: 130, height: 110) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.white, lineWidth: 4)) + .shadow(radius: 10) + .offset(y: -110/2) + .padding(.bottom, -110/2) } } private var sender: some View { VStack (alignment: .leading, spacing: 10) { - HStack { - VStack (alignment: .leading) { - Text(NSLocalizedString("Sender", comment: "Sender")) - .font(.headline) - .padding(.bottom, 10) - Text(model.mail.sender.name) - .font(.subheadline) - Text(model.mail.sender.email) - .foregroundColor(.gray) + Text(NSLocalizedString("Sender", comment: "Sender")) + .font(.headline) + .padding(.bottom, 10) + NavigationLink(destination: ContactView(contact: model.mail.sender, fromMail: model.mail)) { + HStack { + VStack (alignment: .leading) { + Text(model.mail.sender.name) + .font(.headline) + Text(model.mail.sender.email) + .foregroundColor(.secondary) + } } Spacer() - Button(action: {self.goToContact(contact: self.model.mail.sender)}){ - Image(systemName: "chevron.right") - } - } - .onTapGesture { - self.goToContact(contact: self.model.mail.sender) + Image(systemName: "chevron.right") } + HStack{ Text(String(format: NSLocalizedString("ReadView.Sender.Previous", comment: "100 previous received mails"), model.mail.sender.previousMails)) Spacer() @@ -157,14 +154,6 @@ struct SenderViewMain <M: DisplayMail>: View { } } } - - private func goToContact(contact: M.C) { - /* guard let con = contact.keyRecord else { - print("No record...") - return - } - AppDelegate.getAppDelegate().readViewCoordinator?.pushContactView(contact: con) */ - } } struct SenderView_Previews: PreviewProvider { diff --git a/enzevalos_iphone/de.lproj/Localizable.strings b/enzevalos_iphone/de.lproj/Localizable.strings index 7e2e3b37c840f085c0ce0e28b703bdae1b80c64b..1ed3481bf5e0dab216ef3c2ede056b2a469cb9ab 100644 --- a/enzevalos_iphone/de.lproj/Localizable.strings +++ b/enzevalos_iphone/de.lproj/Localizable.strings @@ -5,8 +5,13 @@ Created by jakobsbode on 06.10.16. Copyright © 2016 fu-berlin. All rights reserved. */ +"Permission.contactDenied.Title" = "Oops! Zugriff erlauben!"; +"Permission.contactDenied.Description" = "Bitte erlaube zugriff auf Kontakte In Einstellungen -> Datenschutz -> Kontakte"; +"Permission.Notification.Title" = "Mitteilungen erlauben"; +"Permission.Notification.Description" = "Letterbox möchte dich benachrichtigen. +Du kannst das jederzeit ändern. In der Einstellungen -> Mitteilungen -> Letterbox"; "Permission.AccessContacts.Title" = "Zugriff auf Kontakte"; -"Permission.AccessContacts.Description" = "Damit diese App richtig funktioniert, brauchen wir Zugriff auf deine Kontakte. Wir teilen diese Daten mit niemandem und senden sie auch nicht über das Internet."; +"Permission.AccessContacts.Description" = "Wir teilen diese Daten mit niemandem und senden sie auch nicht über das Internet."; "AccessNotGranted" = "Bitte schalte unter Einstellungen den Zugriff auf die Kontakte frei, wenn du möchtest, dass die App richtig funktioniert"; "Archive" = "Archiv"; "Address" = "Adresse"; @@ -61,7 +66,6 @@ "Junk" = "Spam"; "KeyAddresses" = "Mailadressen aus dem Schlüssel"; "KeyDetails" = "Schlüsseldetails"; -"KeyID" = "ID"; "KeyIsRevoked" = "Der Schlüssel wurde zurückgezogen. Zurückgezogen wurde er am "; "KeyIsVerified" = "Der Schlüssel ist verifiziert. Verifiziert wurde er am "; "KeyNotFound" = "Der Schlüssel konnte nicht gefunden werden. Dies ist ein Fehler, bitte wende dich an die Entwickler!"; @@ -449,3 +453,6 @@ "ReadView.PrefilledMail.AskForPK.Body" = "Hey, \nIch konnte die letzte Mail nicht verifizieren, weil ich deinen öffentlichen Schlüssel nicht habe. Kannst du mir deinen öffentlichen Schlüssel schicken? Vielen Dank und viele Grüße"; "ReadView.PrefilledMail.AskForPK.Subject" = "Fehlender öffentlicher Schlüssel"; "ReadView.PrefilledMail.AskForResend.Body" = "Hey, \nIch konnte deine letzte Mail nicht entschlüsseln, weil ich den geheimen Schlüssel nicht habe. Kannst du die Mail nochmal mit dem angehängten öffentlichen Schlüssel verschlüsseln? Vielen Dank und viele Grüße"; + + + diff --git a/enzevalos_iphone/en.lproj/Localizable.strings b/enzevalos_iphone/en.lproj/Localizable.strings index 49db30489cf8e9e4f6697ffa5220a816d45316d1..2a4afb112b63cd79ea0e7e4bde7771d101dac3f2 100644 --- a/enzevalos_iphone/en.lproj/Localizable.strings +++ b/enzevalos_iphone/en.lproj/Localizable.strings @@ -5,8 +5,12 @@ Created by jakobsbode on 06.10.16. Copyright © 2016 fu-berlin. All rights reserved. */ -"Permission.AccessContacts.Title" = "Access contacts"; -"Permission.AccessContacts.Description" = "This App requires access to your contacts to work properly. We do not share your data with others or transfer it over the internet."; +"Permission.contactDenied.Title" = "Oops! Please Allow!"; +"Permission.contactDenied.Description" = "Please Turn On Access Contacts In Settings -> Privacy -> Contacts ."; +"Permission.Notification.Title" = "Allow Notifications"; +"Permission.Notification.Description" = "Letterbox wants to notify you. You can change it anytime in Settings -> Notifications -> Letterbox"; +"Permission.AccessContacts.Title" = "Access Contacts"; +"Permission.AccessContacts.Description" = "Letterbox needs to access your contacts to work properly. Your data would be safe and not accessible by third parties or shared on the internet."; "AccessNotGranted" = "Please allow access to contacts in settings, if you want the app to work properly."; // TODO "Archive" = "Archive"; "Address" = "Address"; @@ -61,7 +65,6 @@ "Junk" = "Junk"; "KeyAddresses" = "Mail addresses from the key"; "KeyDetails" = "Key Details"; -"KeyID" = "ID"; "KeyIsRevoked" = "The Key was revoked. It was revoked on "; "KeyIsVerified" = "The Key is verified. It was verified on "; "KeyNotFound" = "No Key Found. This is an error, contact the developers!"; @@ -428,3 +431,5 @@ "ReadView.PrefilledMail.AskForPK.Body" = "Hey, \nI could not verify your last email because I do not have your public key. Can you send me your public key? Thank you and best regards"; "ReadView.PrefilledMail.AskForPK.Subject" = "Missing your public key"; "ReadView.PrefilledMail.AskForResend.Body" = "Hey, \nI could not decrypt your last email because I do not have the secret key. Can you resend the email again and encrypt the email for the attachted secret key? Thank you and best regards"; + + diff --git a/enzevalos_iphone/persistentData/MailRecord.swift b/enzevalos_iphone/persistentData/MailRecord.swift index a5bcbe71d8471d01d640f0133775e294bc7b325c..2dc354313b983d1d378b3e735dc9a903f5dd7637 100644 --- a/enzevalos_iphone/persistentData/MailRecord.swift +++ b/enzevalos_iphone/persistentData/MailRecord.swift @@ -100,6 +100,14 @@ extension MailRecord { extension MailRecord: DisplayMail { + var encryptionType: CryptoScheme? { + // TODO: Consider unable to decrypt case. Extend mail record? + if let key = decryptionKey { + return key.type + } + return nil + } + var signatureKeyID: String? { if let key = signatureKey { return key.keyID diff --git a/enzevalos_iphoneTests/GeneratedMocks.swift b/enzevalos_iphoneTests/GeneratedMocks.swift index 470e5ef2698321d52438cba07da8ec183c8a34a1..40eecd85e4ec643133e3f347e410ef2c177435b1 100644 --- a/enzevalos_iphoneTests/GeneratedMocks.swift +++ b/enzevalos_iphoneTests/GeneratedMocks.swift @@ -1,4 +1,4 @@ -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2021-03-09 16:51:40 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2021-03-10 16:07:04 +0000 // // AuthenticationModel.swift @@ -654,7 +654,7 @@ import Foundation } -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2021-03-09 16:51:40 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2021-03-10 16:07:04 +0000 // // AuthenticationViewModel.swift diff --git a/enzevalos_iphoneTests/testMails/signedSMIMEfromMac.eml b/enzevalos_iphoneTests/testMails/signedSMIMEfromMac.eml index 91f00a0843a257cefbb83336e307cd4500b7af8e..cedd9975e15a43792ab425930a2f688c15dd82d7 100644 --- a/enzevalos_iphoneTests/testMails/signedSMIMEfromMac.eml +++ b/enzevalos_iphoneTests/testMails/signedSMIMEfromMac.eml @@ -1,30 +1,30 @@ From: Oliver Wiese <oliver.wiese@fu-berlin.de> Content-Type: multipart/signed; - boundary="Apple-Mail=_58C9D0E1-2B0A-4882-8F02-411E8FCB5BF0"; + boundary="Apple-Mail=_9BE88FFD-313B-4C05-B770-19F608BDA482"; protocol="application/pkcs7-signature"; micalg=sha-256 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.4\)) -Subject: A signed smime mail from mac -X-Universally-Unique-Identifier: 4DCBCCEE-E252-4369-B8DA-8390C62F2AF3 -Message-Id: <D1D41054-2FAC-4B10-B692-5F3D296BA1E9@fu-berlin.de> -Date: Tue, 16 Feb 2021 17:16:58 +0100 +Subject: Signed SMIME Mail from Mac +X-Universally-Unique-Identifier: 446C1C0E-D181-4FE7-A3D7-EFE6936F1D9F +Message-Id: <2A97340F-AB0E-4981-9736-8EA9AD278B41@fu-berlin.de> +Date: Wed, 10 Mar 2021 17:04:27 +0100 To: bob@enzevalos.de ---Apple-Mail=_58C9D0E1-2B0A-4882-8F02-411E8FCB5BF0 +--Apple-Mail=_9BE88FFD-313B-4C05-B770-19F608BDA482 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii -A signed smime mail from mac ---Apple-Mail=_58C9D0E1-2B0A-4882-8F02-411E8FCB5BF0 +Signed SMIME Mail from Mac +--Apple-Mail=_9BE88FFD-313B-4C05-B770-19F608BDA482 Content-Disposition: attachment; filename=smime.p7s Content-Type: application/pkcs7-signature; name=smime.p7s Content-Transfer-Encoding: base64 -MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCEQcw +MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCESYw ggUSMIID+qADAgECAgkA4wvV+K8l2YEwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAkRFMSsw KQYDVQQKDCJULVN5c3RlbXMgRW50ZXJwcmlzZSBTZXJ2aWNlcyBHbWJIMR8wHQYDVQQLDBZULVN5 c3RlbXMgVHJ1c3QgQ2VudGVyMSUwIwYDVQQDDBxULVRlbGVTZWMgR2xvYmFsUm9vdCBDbGFzcyAy @@ -73,49 +73,50 @@ DlXwCbFqPnjMaDWpHPOVnj/z+N9rOHeJLI21rT7H8pTNoAauusyosa0zCLYkhmI2THhuUPDVbmCN T1IxQ5dGdfBi5G5mUcFCMWdQ5UnnOR7Ln8qGSN4IFP8VSytmm6A4nwDO/afr0X9XLchMX9wQEZc+ lgQCXISoKTlslPwQkgZ7nu7YRrQbtQMMONncsKk/cQYLsgMHM8KNSGMlJTx6e1du94oFOO+4oK4v 9NsH1VuEGMGpuEvObJAaguS5Pfp38dIfMwK/U+d2+dwmJUFvL6Yb+qQTkPp8ftkLYF3sv8pBoGH7 -EUkp2KgtdRXYShjqFu9VNCIaE40GMIIGPTCCBSWgAwIBAgIMHquxIGDgCGtc8ZZZMA0GCSqGSIb3 +EUkp2KgtdRXYShjqFu9VNCIaE40GMIIGXDCCBUSgAwIBAgIMJFhrl196HHUl2Ey0MA0GCSqGSIb3 DQEBCwUAMIGNMQswCQYDVQQGEwJERTFFMEMGA1UECgw8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVp bmVzIERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLDAdERk4tUEtJMSUw -IwYDVQQDDBxERk4tVmVyZWluIEdsb2JhbCBJc3N1aW5nIENBMB4XDTE4MDIyMDE0NDEyMloXDTIx -MDIxOTE0NDEyMlowgZoxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJl +IwYDVQQDDBxERk4tVmVyZWluIEdsb2JhbCBJc3N1aW5nIENBMB4XDTIxMDIyNjEyNDgwOVoXDTI0 +MDIyNjEyNDgwOVowgbsxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJl cmxpbjEiMCAGA1UECgwZRnJlaWUgVW5pdmVyc2l0YWV0IEJlcmxpbjEuMCwGA1UECwwlRmFjaGJl -cmVpY2ggTWF0aGVtYXRpayB1bmQgSW5mb3JtYXRpazEVMBMGA1UEAwwMT2xpdmVyIFdpZXNlMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx25g+X495DeptnwCaQ6cykfU3s2nICuN+XOA -Jlvu2alLN2qaySL2vmumySejVk2jZxC3Is5I/3GrYL6uCpLjp0w7LeEkmrfRGFYV1cMOMtKz+exv -M+xplyYf4ibVYPhPGR3oHy3VDdd1QQolqmADdS4MDeOHBknEqaWDvVSkSWt2Jm5QmnVuvEDmppsA -c4C3w8IR1MOU3TnVphlIrDF6ZrMxKvxzCrFEby8jE6paipgS+ZfZxRtCaqZUWW3Vu5CWWyz1CLOu -Ff0FZOX6uG8RdBeBm7NUagg8UXkDCKX08bMIYfShz+IoCy0aHV7Ks5I3+N6/2pHEmoWm/qpdkPta -fQIDAQABo4ICjDCCAogwQAYDVR0gBDkwNzAPBg0rBgEEAYGtIYIsAQEEMBEGDysGAQQBga0hgiwB -AQQDBzARBg8rBgEEAYGtIYIsAgEEAwcwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l -BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBTZ8ytnI7fxN4uilTbn+lUG1l6R0jAf -BgNVHSMEGDAWgBRrOpiL+fJTidrgrbIyHgkf6Ko7dDBcBgNVHREEVTBTgRlvbGl2ZXIud2llc2VA -ZnUtYmVybGluLmRlgRt3aWVzZW9saUB6ZWRhdC5mdS1iZXJsaW4uZGWBGU9saXZlci5XaWVzZUBm -dS1iZXJsaW4uZGUwgY0GA1UdHwSBhTCBgjA/oD2gO4Y5aHR0cDovL2NkcDEucGNhLmRmbi5kZS9k -Zm4tY2EtZ2xvYmFsLWcyL3B1Yi9jcmwvY2FjcmwuY3JsMD+gPaA7hjlodHRwOi8vY2RwMi5wY2Eu -ZGZuLmRlL2Rmbi1jYS1nbG9iYWwtZzIvcHViL2NybC9jYWNybC5jcmwwgdsGCCsGAQUFBwEBBIHO -MIHLMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5wY2EuZGZuLmRlL09DU1AtU2VydmVyL09DU1Aw -SQYIKwYBBQUHMAKGPWh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZGZuLWNhLWdsb2JhbC1nMi9wdWIv -Y2FjZXJ0L2NhY2VydC5jcnQwSQYIKwYBBQUHMAKGPWh0dHA6Ly9jZHAyLnBjYS5kZm4uZGUvZGZu -LWNhLWdsb2JhbC1nMi9wdWIvY2FjZXJ0L2NhY2VydC5jcnQwDQYJKoZIhvcNAQELBQADggEBAIZ4 -78RroIuTMr5QvBVINS9oX6HFIOHCPtSuuKRMpb6OHCmyye0NySJAVtK9ozDzomkShvMzMm5SmAoG -xubcqgb5ovg8eixwDvEj+QlKQ8hQHUNoYf4ExNeU+KDE0pSE6AM1GgnRB34Xtjpk/d+6nA6JKqxz -VSH00K3dSzVtrDdgnAdr4su8pTtgYNL2hlTzqkSj0MdzcyBq7PvmVlSE60umivECuQt+Sig6HEt2 -e2bgQ52ZVvKTpQ8oTj0+Mfw2ul2eYyRcLEz9Y2/GpwLXai5QQbClPmPRo1z0mFoYYe2R8QiwHHgS -11RI6lHw4wUHox0PrfDb8vZlz2jafZQendUxggOdMIIDmQIBATCBnjCBjTELMAkGA1UEBhMCREUx +cmVpY2ggTWF0aGVtYXRpayB1bmQgSW5mb3JtYXRpazEOMAwGA1UEBAwFV2llc2UxDzANBgNVBCoM +Bk9saXZlcjEVMBMGA1UEAwwMT2xpdmVyIFdpZXNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA1tXu5MsVxQ8Cn9RLiJPo74E/DwQaGk7jMODB4GyHMgdocL99RiWJkzv6edL1gHEGvVL/ +NWXP2CPgjD3ckpQJCbGIqtRRpOPkenxQzDzYmDn14YIbBDvWmCUNGEYr/YVkz8OcRYM12R7KnJ56 +YYQUZY/0KPd+C9wY79EsTRA+Gl9PYXp2yfBsA3d2IJxbmdP5mLU9GoJ/q8jqnIGk9IpPZ5sLfLbd +sMO7EbXblMMUpkDCLvau7/nTuVsf66VrxLwR5i9lMGoetK3uPQUIA4SDMvEnJUm1o+VSr+IxtIZy +bG5gO99uJ+6xxXcw8rQB1ejvTOrjf9LK8yD6V80lN9qI9wIDAQABo4ICijCCAoYwPgYDVR0gBDcw +NTAPBg0rBgEEAYGtIYIsAQEEMBAGDisGAQQBga0hgiwBAQQIMBAGDisGAQQBga0hgiwCAQQIMAkG +A1UdEwQCMAAwDgYDVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAd +BgNVHQ4EFgQUpC8bD5xOFMZIDBQF1RAv1QHZ+iswHwYDVR0jBBgwFoAUazqYi/nyU4na4K2yMh4J +H+iqO3QwXAYDVR0RBFUwU4EZb2xpdmVyLndpZXNlQGZ1LWJlcmxpbi5kZYEZT2xpdmVyLldpZXNl +QGZ1LWJlcmxpbi5kZYEbd2llc2VvbGlAemVkYXQuZnUtYmVybGluLmRlMIGNBgNVHR8EgYUwgYIw +P6A9oDuGOWh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZGZuLWNhLWdsb2JhbC1nMi9wdWIvY3JsL2Nh +Y3JsLmNybDA/oD2gO4Y5aHR0cDovL2NkcDIucGNhLmRmbi5kZS9kZm4tY2EtZ2xvYmFsLWcyL3B1 +Yi9jcmwvY2FjcmwuY3JsMIHbBggrBgEFBQcBAQSBzjCByzAzBggrBgEFBQcwAYYnaHR0cDovL29j +c3AucGNhLmRmbi5kZS9PQ1NQLVNlcnZlci9PQ1NQMEkGCCsGAQUFBzAChj1odHRwOi8vY2RwMS5w +Y2EuZGZuLmRlL2Rmbi1jYS1nbG9iYWwtZzIvcHViL2NhY2VydC9jYWNlcnQuY3J0MEkGCCsGAQUF +BzAChj1odHRwOi8vY2RwMi5wY2EuZGZuLmRlL2Rmbi1jYS1nbG9iYWwtZzIvcHViL2NhY2VydC9j +YWNlcnQuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBXTTIaa3C3miMEok7yGMkUyB16o0ctMzVhRexg +rARlBi4uYprn1URJGLRVmVzXb1H7DbSYEjJtCr6lJITQP0pcwQC1y47ObWqAVKNx+hDM5VsWwSB+ +xXlGjIuKb8ZLxCcTVIsvlSZw/i8XU4xfUB7GmgNtFK2lzAtPT8LlG0i3ph4Zshj7wzMJpxxbCgdG +IMGLtKIimmegpzIB4N0jecm4C5DcaYf1V874Fw5C5FxG8yvQLlGhbHGsVXqBeYyRzv0UY/kLLnHr +FO57Tq24uPZuDOg06nIQb/SUZ8qXwz0sqBt0j4NP6qqj/Ur7y81a8YRQaKFantJFh2jQu6uz5kOW +MYIDnTCCA5kCAQEwgZ4wgY0xCzAJBgNVBAYTAkRFMUUwQwYDVQQKDDxWZXJlaW4genVyIEZvZXJk +ZXJ1bmcgZWluZXMgRGV1dHNjaGVuIEZvcnNjaHVuZ3NuZXR6ZXMgZS4gVi4xEDAOBgNVBAsMB0RG +Ti1QS0kxJTAjBgNVBAMMHERGTi1WZXJlaW4gR2xvYmFsIElzc3VpbmcgQ0ECDCRYa5dfehx1JdhM +tDANBglghkgBZQMEAgEFAKCCAc8wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B +CQUxDxcNMjEwMzEwMTYwNDI3WjAvBgkqhkiG9w0BCQQxIgQgQK/YjIICeu1uq9WnnrVErVKTkvSR +vHPv/Kuk53C9A1Ewga8GCSsGAQQBgjcQBDGBoTCBnjCBjTELMAkGA1UEBhMCREUxRTBDBgNVBAoM +PFZlcmVpbiB6dXIgRm9lcmRlcnVuZyBlaW5lcyBEZXV0c2NoZW4gRm9yc2NodW5nc25ldHplcyBl +LiBWLjEQMA4GA1UECwwHREZOLVBLSTElMCMGA1UEAwwcREZOLVZlcmVpbiBHbG9iYWwgSXNzdWlu +ZyBDQQIMJFhrl196HHUl2Ey0MIGxBgsqhkiG9w0BCRACCzGBoaCBnjCBjTELMAkGA1UEBhMCREUx RTBDBgNVBAoMPFZlcmVpbiB6dXIgRm9lcmRlcnVuZyBlaW5lcyBEZXV0c2NoZW4gRm9yc2NodW5n c25ldHplcyBlLiBWLjEQMA4GA1UECwwHREZOLVBLSTElMCMGA1UEAwwcREZOLVZlcmVpbiBHbG9i -YWwgSXNzdWluZyBDQQIMHquxIGDgCGtc8ZZZMA0GCWCGSAFlAwQCAQUAoIIBzzAYBgkqhkiG9w0B -CQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMTAyMTYxNjE2NThaMC8GCSqGSIb3DQEJ -BDEiBCC8Fytiv1ZpmEb8bvmg27rVyebYhhu4n7CvuB65krlt7DCBrwYJKwYBBAGCNxAEMYGhMIGe -MIGNMQswCQYDVQQGEwJERTFFMEMGA1UECgw8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVzIERl -dXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLDAdERk4tUEtJMSUwIwYDVQQD -DBxERk4tVmVyZWluIEdsb2JhbCBJc3N1aW5nIENBAgweq7EgYOAIa1zxllkwgbEGCyqGSIb3DQEJ -EAILMYGhoIGeMIGNMQswCQYDVQQGEwJERTFFMEMGA1UECgw8VmVyZWluIHp1ciBGb2VyZGVydW5n -IGVpbmVzIERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLDAdERk4tUEtJ -MSUwIwYDVQQDDBxERk4tVmVyZWluIEdsb2JhbCBJc3N1aW5nIENBAgweq7EgYOAIa1zxllkwDQYJ -KoZIhvcNAQEBBQAEggEAMT5sbk0eX0B6kJjLa22vWULGUjKIo/klAOLzeTbejIdGy+kRxZP3Ztxy -cROX8JxHGMPslJ9lmnbmIYwCqb7JgIZjyelJNDESzPzo12krkhH0t8J3tUFC/TyKCQg1JBRNdT+L -08/7/xYJL7DOG1CXTiIQi7P29QpCGCisfuEKJ8ac3cZrT81EIfGnEoIAKam+RFlE4TDAZEBF8qgm -s6pxT8aSUjMnMP8ZtTHQpNbUsMqLkilXYsnSREleAbqptItWbJ+qsGJMcC4wc28tNGOLEsdYjGsH -eM+AIln6HACsMCpqXSkxgkc7T7F7DTlb+FwGe+UyaZOj1O3LzoS+b8jijAAAAAAAAA== ---Apple-Mail=_58C9D0E1-2B0A-4882-8F02-411E8FCB5BF0-- +YWwgSXNzdWluZyBDQQIMJFhrl196HHUl2Ey0MA0GCSqGSIb3DQEBAQUABIIBABR/msBlq4aqrh2W +2hbofRVT4XMRl7Brw9XZa2+9ZqNOwUemCpvqk61frnJE5adoyuCuX3v9633kmJZyenxVQr5Vfvlb +QL1lR+0yFqPWFoHqo34oVF/9CgMNxLm1iP6DjBx96ugWKGRcrQ+cXSdwKsiWbjE4SXbpdmNhisLi +FI7DVK0BSGkWk+3YuXdqGPfe77o/s1uLMjhldJuEgPC4hWqyvPsOKtUspNG4Imj/80Wnj+DJI+gW +uZaaBgHTsXJ31NYyNoVKCTuvzDTRdxm5+MY/ehoP1FNexjOhhUFYvvYvpAh4mlI6kI/vcaXWYtTn +i8rsvKhpg6/l/2dKGDOmQpgAAAAAAAA= +--Apple-Mail=_9BE88FFD-313B-4C05-B770-19F608BDA482--