From 77384130fe7d36e91ed8399dec53fbd499b41082 Mon Sep 17 00:00:00 2001 From: Oliver Wiese <oliver.wiese@fu-berlin.de> Date: Thu, 9 Apr 2020 12:51:04 +0200 Subject: [PATCH] add security briefing --- enzevalos_iphone.xcodeproj/project.pbxproj | 4 + enzevalos_iphone/Dialog/DialogOption.swift | 41 +++++ .../PersistentMail +CoreDataProperties.swift | 6 + .../SwiftUI/Data/DisplayProtocols.swift | 27 ++++ .../SwiftUI/Data/SimulatorData.swift | 2 + .../SwiftUI/Read/ReadMainView.swift | 2 +- .../Read/Tabbed Views/MessageViewMain.swift | 11 +- .../Tabbed Views/SecurityBriefingView.swift | 149 ++++++++++++++++++ .../Read/Tabbed Views/SenderViewMain.swift | 10 +- enzevalos_iphone/en.lproj/Localizable.strings | 15 ++ 10 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 06c31b27..9a3f8ad0 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -120,6 +120,7 @@ 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */; }; 4775D7A8243F0D630052F2CC /* DisplayProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4775D7A7243F0D630052F2CC /* DisplayProtocols.swift */; }; 4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4775D7A9243F0E260052F2CC /* SimulatorData.swift */; }; + 4775D7AC243F18BC0052F2CC /* SecurityBriefingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4775D7AB243F18BC0052F2CC /* SecurityBriefingView.swift */; }; 477670C4228453FB00043604 /* ButtonCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 477670C3228453FB00043604 /* ButtonCell.xib */; }; 477670C6228454F700043604 /* ButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477670C5228454F700043604 /* ButtonCell.swift */; }; 478154A721FF3F0900A931EC /* Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154A621FF3F0900A931EC /* Warning.swift */; }; @@ -569,6 +570,7 @@ 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyParameterProtocol.swift; sourceTree = "<group>"; }; 4775D7A7243F0D630052F2CC /* DisplayProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayProtocols.swift; sourceTree = "<group>"; }; 4775D7A9243F0E260052F2CC /* SimulatorData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorData.swift; sourceTree = "<group>"; }; + 4775D7AB243F18BC0052F2CC /* SecurityBriefingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityBriefingView.swift; sourceTree = "<group>"; }; 477670C3228453FB00043604 /* ButtonCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ButtonCell.xib; sourceTree = "<group>"; }; 477670C5228454F700043604 /* ButtonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonCell.swift; sourceTree = "<group>"; }; 478154A621FF3F0900A931EC /* Warning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Warning.swift; sourceTree = "<group>"; }; @@ -1290,6 +1292,7 @@ 47C822632438A84C005BCE73 /* SenderViewChildren */, 47C8224824379EAE005BCE73 /* MessageViewChildren */, 47C8224B24379EAE005BCE73 /* AttachmentChildren */, + 4775D7AB243F18BC0052F2CC /* SecurityBriefingView.swift */, ); path = "Tabbed Views"; sourceTree = "<group>"; @@ -2256,6 +2259,7 @@ 47C8226D2438C2CF005BCE73 /* ReadViewModel.swift in Sources */, 47C822602437A143005BCE73 /* CornerRounder.swift in Sources */, 8428A85D1F436A05007649A5 /* Badges.swift in Sources */, + 4775D7AC243F18BC0052F2CC /* SecurityBriefingView.swift in Sources */, 971D404A2428C87E002FCD31 /* BadgeCaseView.swift in Sources */, 47C8225B24379EAE005BCE73 /* MessageViewMain.swift in Sources */, 8428A8651F436A11007649A5 /* BadgeCaseCollectionViewCell.swift in Sources */, diff --git a/enzevalos_iphone/Dialog/DialogOption.swift b/enzevalos_iphone/Dialog/DialogOption.swift index e6b13a20..7a220e3a 100644 --- a/enzevalos_iphone/Dialog/DialogOption.swift +++ b/enzevalos_iphone/Dialog/DialogOption.swift @@ -71,6 +71,47 @@ struct DialogStruct: Dialog { enum ButtonAction { case AskSenderToConfirm, AskSenderToSendPK, AskSenderToResendForPK, InvitePerson, IgnoreMail, AskUserToImportSK, ImportSK, ImportPK, MoreInformation, ExportSK, OK, IgnoreWarning, SendPK + + var title: LocalizedStringKey { + get { + switch self { + case .AskSenderToConfirm: return "Security.Dialog.Button.Title.Confirmation" + case .AskSenderToSendPK: return "Security.Dialog.Button.Title.Ask.ForPK" + case .AskSenderToResendForPK: return "Security.Dialog.Button.Title.Ask.Resend.ForPK" + case .InvitePerson: return "Security.Dialog.Button.Title.Invite" + case .IgnoreMail: return "Security.Dialog.Button.Title.Ignore.Mail" + case .AskUserToImportSK: return "MISSING" + case .ImportSK: return "Security.Dialog.Button.Title.Import.SK" + case .ImportPK: return "MISSING" + case .MoreInformation: return "MoreInformation" + case .ExportSK: return "MISSING" + case .OK: return "Security.Dialog.Button.Title.OK" + case .IgnoreWarning: return "MISSING" + case .SendPK: return "Security.Dialog.Button.Title.Send.PK" + } + } + } + + var color: Color { + get { + let defaultColor = Color.blue + switch self { + case .AskSenderToConfirm: return defaultColor + case .AskSenderToSendPK: return defaultColor + case .AskSenderToResendForPK: return defaultColor + case .InvitePerson: return defaultColor + case .IgnoreMail: return defaultColor + case .AskUserToImportSK: return defaultColor + case .ImportSK: return defaultColor + case .ImportPK: return defaultColor + case .MoreInformation: return defaultColor + case .ExportSK: return defaultColor + case .OK: return defaultColor + case .IgnoreWarning: return defaultColor + case .SendPK: return defaultColor + } + } + } } enum DialogOption: Dialog { diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index 9151291c..dac47b60 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -469,6 +469,12 @@ extension PersistentMail: DisplayMail { func markAsRead(isRead: Bool) { self.isRead = isRead } + + var transportEnc: Bool { + get { + return true + } + } } extension Attachment: DisplayAttachment { diff --git a/enzevalos_iphone/SwiftUI/Data/DisplayProtocols.swift b/enzevalos_iphone/SwiftUI/Data/DisplayProtocols.swift index 74cc34e9..616e42fe 100644 --- a/enzevalos_iphone/SwiftUI/Data/DisplayProtocols.swift +++ b/enzevalos_iphone/SwiftUI/Data/DisplayProtocols.swift @@ -31,8 +31,26 @@ enum ResponseType { enum CryptoState { case UnableToDecrypt, InvalidSignature, NoCrypto, PlainMissingPublicKeyToVerify, PlainButValidSignature, EncValidSign, EncNoSignature, EncButMissingPublicKeyToVerify + + var buttonActions: [ButtonAction] { + get { + switch self { + case .UnableToDecrypt: return [.AskUserToImportSK, .AskSenderToResendForPK] + case .InvalidSignature: return [.AskSenderToConfirm, .IgnoreMail] + case .NoCrypto: return [.InvitePerson] + case .PlainMissingPublicKeyToVerify: return [.AskSenderToSendPK] + case .PlainButValidSignature: return [.SendPK] + case .EncValidSign: return [] + case .EncNoSignature: return [.AskSenderToConfirm] + case .EncButMissingPublicKeyToVerify: return [.AskSenderToSendPK] + } + } + } + + } + protocol DisplayAttachment { var myName: String { get } var myData: Data { get } @@ -77,6 +95,7 @@ protocol DisplayMail { // Crypto var signedState: SignatureState { get } var encState: EncryptionState { get } + var transportEnc: Bool { get } var persistentMail: PersistentMail? { get } @@ -135,6 +154,7 @@ extension DisplayMail { } } + var dialog: DialogStruct { get { // TODO: Do we add new public key stuff? @@ -240,6 +260,13 @@ extension DisplayMail { } } + var buttonActions: [ButtonAction] { + get { + let (_, state) = evaluateSecurity() + return state.buttonActions + } + } + var warnings: [DialogStruct] { get { var result = [DialogStruct] () diff --git a/enzevalos_iphone/SwiftUI/Data/SimulatorData.swift b/enzevalos_iphone/SwiftUI/Data/SimulatorData.swift index d5e46ee7..770db50a 100644 --- a/enzevalos_iphone/SwiftUI/Data/SimulatorData.swift +++ b/enzevalos_iphone/SwiftUI/Data/SimulatorData.swift @@ -173,6 +173,8 @@ struct PseuoMail: DisplayMail { return nil } + var transportEnc: Bool = true + } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index 27c8aef4..cefafae8 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -43,7 +43,7 @@ struct ReadMainView <M: DisplayMail>: View { Tab( image: Image(systemName: "shield"), description: "security", - content:AnyView(AttachmentsViewMain(attachments: mail.displayAttachments, dlAll: true)) + content:AnyView(SecurityBriefingView(mail: mail)) ), Tab( image: Image(systemName: "person.fill"), diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift index 627c776b..60ca018b 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift @@ -30,16 +30,7 @@ struct MessageViewMain <M: DisplayMail>: View { VStack{ Subjectbar Divider() - if mail.warnings.count > 0 { - ForEach(0..<mail.warnings.count) { index in - DialogView(option: self.mail.warnings[index], ctaAction: self.action, additionalAction: self.action, dismissAction: self.action, extend: false) - } - Divider() - MessageBody.padding(.horizontal) - } - else{ - MessageBody.padding(.horizontal) - } + MessageBody.padding(.horizontal) } } .onTapGesture { diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift new file mode 100644 index 00000000..a8417597 --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift @@ -0,0 +1,149 @@ +// +// SecurityBriefingView.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 09.04.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct SecurityBriefingView<M: DisplayMail>: View { + let mail: M + + let padding: CGFloat = 10 + @State private var showWarning = true + + var body: some View { + ScrollView { + title + if mail.warnings.count > 0 && showWarning { + ForEach(0..<mail.warnings.count) {index in + DialogView(option: self.mail.warnings[index], ctaAction: self.action, additionalAction: self.action, dismissAction: self.action, extend: false) + } + } + confidentiality + Divider() + authenticity + Divider() + actions + } + } + + func action () { + showWarning.toggle() + } + + var title: some View { + Text("ReadView.SecurityBriefing.Title") + .font(.largeTitle) + } + + var confidentiality: some View { + var stateString: LocalizedStringKey + var secure = false + switch (mail.encState, mail.transportEnc) { + case (.NoEncryption, true): stateString = "ReadView.SecurityBriefing.Conf.State.TransportEnc" + case (.NoEncryption, false): stateString = "ReadView.SecurityBriefing.Conf.State.Plain" + case (.UnableToDecrypt, _): stateString = "ReadView.SecurityBriefing.Conf.State.UnableToDecrypt" + case (.ValidEncryptedWithOldKey, _), (.ValidedEncryptedWithCurrentKey, _): stateString = "ReadView.SecurityBriefing.Conf.State.Encrypted" + secure = true + } + + return InfoView( + titleString: "ReadView.SecurityBriefing.Conf.Title", + descriptionString: "ReadView.SecurityBriefing.Conf.Description", + stateString: stateString, + padding: padding, secure: secure) + } + + var authenticity: some View { + var stateString: LocalizedStringKey + var secure = false + switch mail.signedState { + case .InvalidSignature: + stateString = "ReadView.SecurityBriefing.Auth.State.InvalidSignature" + case .NoSignature: + stateString = "ReadView.SecurityBriefing.Auth.State.UnSigned" + case .NoPublicKey: + stateString = "ReadView.SecurityBriefing.Auth.State.MissingPK" + case .ValidSignature: + stateString = "ReadView.SecurityBriefing.Auth.State.Signed" + secure = true + } + return InfoView( + titleString: "ReadView.SecurityBriefing.Auth.Title", + descriptionString: "ReadView.SecurityBriefing.Auth.Description", + stateString: stateString, + padding: padding, secure: secure) + } + + var actions: some View { + VStack { + Text("ReadView.SecurityBriefing.Actions.Title") + .font(.headline) + .padding(padding) + Text("ReadView.SecurityBriefing.Actions.Description" ) + .fontWeight(.light) + .padding(padding) + ForEach(0..<mail.buttonActions.count) {index in + Button(action: { + print("Click!") + }, label: { + Text(self.mail.buttonActions[index].title) + .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) + .addBorder(self.mail.buttonActions[index].color, width: 1, cornerRadius: 30) + // .foregroundColor(.white) + //.background(RoundedCorners(color: self.mail.buttonActions[index].color, radius: 30)) + .padding(.vertical, 10) + .padding(.horizontal, 20) + }) + } + } + } +} + +struct InfoView: View { + let titleString: LocalizedStringKey + let descriptionString: LocalizedStringKey + var stateString: LocalizedStringKey + var padding: CGFloat + var secure: Bool + + var body: some View { + VStack(alignment: .leading) { + Text(titleString) + .font(.headline) + .padding(padding) + // Text(descriptionString) + // .fontWeight(.light) + // .padding(padding) + HStack { + if secure { + Image(systemName: "checkmark") + .resizable() + .frame(width: 40, height: 40) + .foregroundColor(Color(ThemeManager.encryptedMessageColor())) + .padding(.leading, padding) + } else { + Image(systemName: "xmark.octagon.fill") + .resizable() + .frame(width: 40, height: 40) + .foregroundColor(Color(ThemeManager.troubleMessageColor())) + .padding(.leading, padding) + } + + Text(stateString) + .padding(padding) + } + } + } +} + +struct SecurityBriefingView_Previews: PreviewProvider { + static var previews: some View { + let sim = Simulators<SecurityBriefingView<PseuoMail>>() + return sim.previews(view: SecurityBriefingView(mail: DummyData.MissingPKMail)) + + } +} diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift index c2dcada8..5b9abe10 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift @@ -36,15 +36,7 @@ struct SenderViewMain <M: DisplayMail>: View { var body: some View { ScrollView { - if mail.warnings.count > 0 { - ForEach(0..<mail.warnings.count) { index in - DialogView(option: self.mail.warnings[index], ctaAction: {print("Hello")}, additionalAction: {print("Hello")}, dismissAction: {print("Hello")}, extend: (index == (self.mail.warnings.count - 1))) - } - - } else { - map - } - + map icon sender .offset(y: (-110/2 + 20)) diff --git a/enzevalos_iphone/en.lproj/Localizable.strings b/enzevalos_iphone/en.lproj/Localizable.strings index 4d30a330..b082efeb 100644 --- a/enzevalos_iphone/en.lproj/Localizable.strings +++ b/enzevalos_iphone/en.lproj/Localizable.strings @@ -383,3 +383,18 @@ "Security.Dialog.Button.Title.Invite" = "Ask to use encryption"; "Security.Dialog.Button.Title.Ask.ForPK" = "Ask to send ID"; "Security.Dialog.Button.Title.Send.PK" = "Send own public key"; +"ReadView.SecurityBriefing.Title" = "Security Briefing"; +"ReadView.SecurityBriefing.Conf.Title" = "Who can read the email?"; +"ReadView.SecurityBriefing.Conf.Description" = "Deine Mails gehen durch verschiedene Hände: Deinem Mail-Provider, dem Mail-Provider der anderen Seite und vielleicht weitere Mail-Provider als Vermittler dazwischen. Außerdem transporieren dein Internet-Provider und andere auch andere Internet-Provider deine Mail."; +"ReadView.SecurityBriefing.Conf.State.Encrypted" = "Only you, the sender and receiver know the content of these mails."; +"ReadView.SecurityBriefing.Conf.State.Plain" = "Everyone can read the content"; +"ReadView.SecurityBriefing.Conf.State.TransportEnc" = "The involved email providers know the content. You, the sender and receivers know the content, too."; +"ReadView.SecurityBriefing.Conf.State.UnableToDecrypt" = "This is a confidential mail, but it could not be decrypted. If you can read this mail on other devices, you should synchronize them. If not, the sender might have made a mistake and you can ask the sender to send the mail again."; +"ReadView.SecurityBriefing.Conf.Problem.PrivacyPolicy" = "At least one involved email provider read the mail advertising as they say in their privicy policy."; +"ReadView.SecurityBriefing.Auth.Title" = "Who is the sender?"; +"ReadView.SecurityBriefing.Auth.State.UnSigned" = "we do not know if the sender address represents the real sender. Be aware that a fraud can impersonate the sender."; +"ReadView.SecurityBriefing.Auth.State.Signed" = "The senders of these mails have an ID and we have a genuine record about previous mails of them."; +"ReadView.SecurityBriefing.Auth.State.MissingPK" = "We can not verify the sender because sender's ID is missing. But after importing sender's ID we can verify the sender."; +"ReadView.SecurityBriefing.Auth.State.InvalidSignature" = "This mail has been manipulated! If you want to read it anyway, please be cautions."; +"ReadView.SecurityBriefing.Actions.Title" = "Improving the security"; +"ReadView.SecurityBriefing.Actions.Description" = "We can improve the security of this email and other emails in the future"; -- GitLab