Commit c7ebef37 authored by Oliver Wiese's avatar Oliver Wiese

add new dialog struct and security evaluation of mail

parent af0d5b0a
......@@ -1123,6 +1123,7 @@
4764068C2416B54D00C7D426 /* SupportingViews */ = {
isa = PBXGroup;
children = (
47C8224924379EAE005BCE73 /* DialogView.swift */,
47C822612438A81C005BCE73 /* MapView.swift */,
47EABF2A2423C20C00774A93 /* LoadingBlocker.swift */,
47EABF282423C1FB00774A93 /* KeyboardChecker.swift */,
......@@ -1282,7 +1283,6 @@
47C8224824379EAE005BCE73 /* MessageViewChildren */ = {
isa = PBXGroup;
children = (
47C8224924379EAE005BCE73 /* DialogView.swift */,
47C8224A24379EAE005BCE73 /* FloatingActionButton.swift */,
);
path = MessageViewChildren;
......
......@@ -6,6 +6,188 @@
//
import Foundation
import SwiftUI
struct SecurityState <M: DisplayMail> {
enum CryptoState {
case UnableToDecrypt, InvalidSignature, NoCrypto, PlainMissingPublicKeyToVerify, PlainButValidSignature, EncValidSign, EncNoSignature, EncButMissingPublicKeyToVerify
}
let mail: M
// TODO: Handling new key attack
var title: String {
get {
var key = ""
switch evaluateSecurity() {
case (_,.NoCrypto): key = "Security.Dialog.Title.No.Crypto"
case (_, .UnableToDecrypt): key = "Security.Dialog.Title.UnableToDecrypt"
case (_, .InvalidSignature): key = "Security.Dialog.Title.InvalidSignature"
case (_, .PlainMissingPublicKeyToVerify): key = "Security.Dialog.Title.PlainMissingPublicKeyToVerify"
case (_, .PlainButValidSignature): key = "Security.Dialog.Title.Plain+Sig"
case (_, .EncValidSign): key = "Security.Dialog.Title.Enc+Sign"
case (_, .EncNoSignature): key = "Security.Dialog.Title.Enc+NoSign"
case (_, .EncButMissingPublicKeyToVerify): key = "Security.Dialog.Title.EncMissingPublicKeyToVerify"
}
return NSLocalizedString(key, comment: "")
}
}
var icon: Image {
get {
switch evaluateSecurity() {
case (_, .EncValidSign):
return StudySettings.securityIndicator.imageOfSecureIndicatorSwiftUI()
case (_, .UnableToDecrypt), (_, .InvalidSignature):
return StudySettings.securityIndicator.imageOfCorruptedIndicatorSwiftUI()
case (_, .NoCrypto), (_, .PlainMissingPublicKeyToVerify), (_, .PlainButValidSignature), (_, .EncNoSignature), (_, .EncButMissingPublicKeyToVerify):
return StudySettings.securityIndicator.imageOfInsecureIndicatorSwiftUI()
}
}
}
var dialog: DialogStruct {
get {
// TODO: Do we add new public key stuff?
var color: UIColor
var bodyKey: String
let infoTitle = NSLocalizedString("Security.Dialog.Button.Title.MoreInfo", comment: "")
var ctaButtonTitleKey: String = "Security.Dialog.Button.Title.OK"
var ctaButtonAction: ButtonAction = .OK
var moreButtons: [ButtonStruct] = []
var dismissButtonTitleKey: String?
var dismissButtonAction: ButtonAction?
switch evaluateSecurity() {
case (_, .EncValidSign):
color = ThemeManager.encryptedMessageColor()
bodyKey = "OnboardingIntroSection.Confidential.description"
// ctaButton -> Ok
case (_, .UnableToDecrypt):
color = ThemeManager.troubleMessageColor()
bodyKey = "ReceiveInsecureInfoDecryptionFailed"
// cta Button -> OK
// add -> Import Key
var btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.Import.SK", action: .AskUserToImportSK)
moreButtons.append(btn)
// add -> Ask to resend for differnet PK
btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.Ask.Resend.ForPK", action: .AskSenderToResendForPK)
moreButtons.append(btn)
case (_, .InvalidSignature):
color = ThemeManager.troubleMessageColor()
bodyKey = "ReceiveDamagedInfo"
// cta Button -> Ignore Mail
ctaButtonTitleKey = "Security.Dialog.Button.Title.Ignore.Mail"
ctaButtonAction = .IgnoreMail
// add -> ask sender
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.Confirmation", action: .AskSenderToConfirm)
moreButtons.append(btn)
// dismiss -> Ignore Warning
dismissButtonTitleKey = "Security.Dialog.Button.Title.OK"
dismissButtonAction = .IgnoreWarning
case (_, .NoCrypto):
color = ThemeManager.unencryptedMessageColor()
bodyKey = "ReceiveInsecureInfo"
// cta Button -> Invite user
ctaButtonTitleKey = "Security.Dialog.Button.Title.Invite"
ctaButtonAction = .InvitePerson
// add -> OK
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.OK", action: .OK)
moreButtons.append(btn)
case (_, .PlainMissingPublicKeyToVerify):
color = ThemeManager.unencryptedMessageColor()
bodyKey = "Security.Dialog.Body.PlainMissingPublicKeyToVerify"
// cta Button -> Ask to send PK
ctaButtonTitleKey = "Security.Dialog.Button.Title.Ask.ForPK"
ctaButtonAction = .AskSenderToSendPK
// add -> OK
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.OK", action: .OK)
moreButtons.append(btn)
case (_, .PlainButValidSignature):
color = ThemeManager.unencryptedMessageColor()
bodyKey = "ReceiveInsecureInfoVerified"
// cta Button -> send PK
ctaButtonTitleKey = "Security.Dialog.Button.Title.Send.PK"
ctaButtonAction = .SendPK
// add -> OK
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.OK", action: .OK)
moreButtons.append(btn)
case (_, .EncNoSignature):
color = ThemeManager.unencryptedMessageColor()
bodyKey = "Information.General.OnlyEncryted"
// cta button -> Ask to confirm
// add -> OK
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.OK", action: .OK)
moreButtons.append(btn)
case (_, .EncButMissingPublicKeyToVerify):
color = ThemeManager.unencryptedMessageColor()
bodyKey = "Security.Dialog.Body.EncButMissingPublicKeyToVerify"
// cta Button -> Ask to send PK
ctaButtonTitleKey = "Security.Dialog.Button.Title.Ask.ForPK"
ctaButtonAction = .AskSenderToSendPK
// add -> OK
let btn = ButtonStruct(titleKey: "Security.Dialog.Button.Title.OK", action: .OK)
moreButtons.append(btn)
}
let body = NSLocalizedString(bodyKey, comment: "")
let ctaButtonTitle = NSLocalizedString(ctaButtonTitleKey, comment: "")
var dismissButtonTitle: String?
if let key = dismissButtonTitleKey {
dismissButtonTitle = NSLocalizedString(key, comment: "")
}
return DialogStruct(dialogColor: Color(color), title: title, body: body, img: icon, messageImage: nil, ctaButtonTitle: ctaButtonTitle, ctaButtonAction: ctaButtonAction, infoButtonTitle: infoTitle, moreButtons: moreButtons, dismissButtonTitle: dismissButtonTitle, dismissButtonAction: dismissButtonAction)
}
}
var warnings: [DialogStruct] {
get {
return []
}
}
private func evaluateSecurity() -> (isPhish: Bool, cryptoState: CryptoState) {
// TODO Phishing handling
let isPhish = false
let cryptoState = evaluateCryptoState()
return (isPhish, cryptoState)
}
private func evaluateCryptoState() -> CryptoState {
switch (mail.encState, mail.signedState) {
// General error cases -> cast other states
case (.UnableToDecrypt, _): return .UnableToDecrypt
case (_, .InvalidSignature): return .InvalidSignature
case (.NoEncryption, .NoSignature): return .NoCrypto
case (.NoEncryption, .NoPublicKey): return .PlainMissingPublicKeyToVerify
case (.NoEncryption, .ValidSignature): return .PlainButValidSignature
case (.ValidEncryptedWithOldKey, .ValidSignature): return .EncValidSign
case (.ValidedEncryptedWithCurrentKey, .ValidSignature): return .EncValidSign
case (.ValidEncryptedWithOldKey, .NoSignature): return .EncNoSignature
case (.ValidEncryptedWithOldKey, .NoPublicKey): return .EncButMissingPublicKeyToVerify
case (.ValidedEncryptedWithCurrentKey, .NoSignature): return .EncNoSignature
case (.ValidedEncryptedWithCurrentKey, .NoPublicKey): return .EncButMissingPublicKeyToVerify
}
}
}
enum SignatureState: Int16 {
case NoSignature = 0 // -> no authenticity -> no actions possible
......@@ -13,7 +195,7 @@ enum SignatureState: Int16 {
case InvalidSignature = -1 // -> ERROR -> context is manipulated (either attack or MTA...)
case ValidSignature = 2
var name: String {
var loggingTag: String {
get {
switch self {
case .NoSignature:
......@@ -36,7 +218,7 @@ enum EncryptionState: Int16 {
case ValidEncryptedWithOldKey = 2
case ValidedEncryptedWithCurrentKey = 3
var name: String {
var loggingTag: String {
get {
switch self {
case .NoEncryption:
......@@ -73,6 +255,8 @@ public enum CryptoScheme {
switch i {
case 0:
return CryptoScheme.PGP
case 1:
return CryptoScheme.SMIME
default:
return CryptoScheme.UNKNOWN
}
......
......@@ -22,50 +22,7 @@ import UIKit
import SwiftUI
/* TODO: MORE DIALOGS
if mail.trouble{
Text(NSLocalizedString("corruptedHeadline", comment: "corrupted mail"))
.font(.system(size: 25))
.frame(maxWidth: .infinity)
.background(Color.yellow)
HStack{
Text("!")
.foregroundColor(Color.red)
.font(.system(size: 60))
.padding([.leading, .top, .bottom])
Text(NSLocalizedString("corruptedText", comment: "corrupted mail"))
.padding()
}
}
else if mail.isEncrypted && mail.unableToDecrypt{
if TravelHandler.instance().mode != .atHome{
Text(NSLocalizedString("couldNotDecryptTravelHeadline", comment: "couldn't decrypt message"))
.font(.system(size: 25))
.frame(maxWidth: .infinity)
.background(Color.yellow)
HStack{
Text("?")
.foregroundColor(Color.orange)
.font(.system(size: 60))
.padding([.leading, .top, .bottom])
Text(NSLocalizedString("couldNotDecryptTravelText", comment: "couldn't decrypt message"))
.padding()
}
}
else {
Text(NSLocalizedString("couldNotDecryptHeadline", comment: "couldn't decrypt message"))
.font(.system(size: 25))
.frame(maxWidth: .infinity)
.background(Color.yellow)
HStack{
Text("?")
.foregroundColor(Color.orange)
.font(.system(size: 60))
.padding([.leading, .top, .bottom])
Text(NSLocalizedString("couldNotDecryptText", comment: "couldn't decrypt message"))
.padding()
}
}
}
//else if (mail.isNewPubKey) && !(mail.deleteWhileTravel){}
// message contained new public key
else if mail.from.hasKey && !mail.isSecure{
......@@ -82,14 +39,107 @@ import SwiftUI
.padding()
}
}
//else if mail.deleteWhileTravel{}
// message not readable while traveling
}.background(Color(UIColor.systemGray5)).padding()
}
*/
enum DialogOption {
protocol Dialog {
var dialogColor: Color { get }
var title: String { get }
var body: String { get }
var img: Image { get }
var ctaButtonTitle: String? { get }
var ctaButtonAction: ButtonAction? { get }
var infoButtonTitle: String? { get }
var moreButtons: [ButtonStruct] { get }
var dismissButtonTitle: String? { get }
var dismissButtonAction: ButtonAction? { get }
}
struct ButtonStruct {
let titleKey: String
let action: ButtonAction
var title: String {
get {
return NSLocalizedString(titleKey, comment: "")
}
}
}
struct DialogStruct: Dialog {
let dialogColor: Color
let title: String
let body: String
let img: Image
let messageImage: Image?
let ctaButtonTitle: String?
let ctaButtonAction: ButtonAction?
let infoButtonTitle: String?
let moreButtons: [ButtonStruct]
let dismissButtonTitle: String?
let dismissButtonAction: ButtonAction?
}
enum ButtonAction {
case AskSenderToConfirm, AskSenderToSendPK, AskSenderToResendForPK, InvitePerson, IgnoreMail, AskUserToImportSK, ImportSK, ImportPK, MoreInformation, ExportSK, OK, IgnoreWarning, SendPK
}
enum DialogOption: Dialog {
var dialogColor: Color {
get {
return Color(color)
}
}
var body: String {
get {
return message
}
}
var img: Image {
get{
if let image = self.messageImage {
return image
}
return Image(systemName: "exclamationmark.triangle.fill")
}
}
var ctaButtonAction: ButtonAction? {
get {
return nil
}
}
var infoButtonTitle: String? {
get {
return nil
}
}
var moreButtons: [ButtonStruct] {
get {
return []
}
}
var dismissButtonAction: ButtonAction? {
get {
return nil
}
}
case postcard
case invitationCode(code: String)
......
......@@ -442,7 +442,7 @@ public class LogData {
}
private static func makeMailKey(enc: EncryptionState, sig: SignatureState, received: Bool) -> String {
var key = "\(enc.name)&\(sig.name)"
var key = "\(enc.loggingTag)&\(sig.loggingTag)"
if received {
key = "in|" + key
}
......
......@@ -20,12 +20,10 @@ import SwiftUI
struct ReadMainView <M: DisplayMail>: View {
public var mail: M
@State private var currentScreen: Int = 1 //doesnt work
public var coord: ReadViewCoordinator
@State var currentScreen: Int = 1 //doesnt work
@State var isSecIndExpanded:Bool = false
@State private var isSecIndExpanded:Bool = false
var body: some View {
//TODO: put into zstack instead
......@@ -46,7 +44,7 @@ struct ReadMainView <M: DisplayMail>: View {
// , displayMode: .inline) //TODO: make smooth or find better solution
.navigationBarItems(trailing: moreInfoButton)
//.onAppear(perform: self.coord.setup)
.onDisappear(perform: self.coord.reset)
//.onDisappear(perform: self.coord.reset)
}
//TODO: not use AnyView-workaround
......@@ -237,9 +235,7 @@ struct expandedSecInd: View {
#if DEBUG
struct Layout_Previews: PreviewProvider {
static var previews: some View {
Group {
expandedSecInd(secNum: 2)
}
ReadMainView(mail: mail)
}
}
#endif
......
......@@ -20,7 +20,6 @@ import SwiftUI
/*
TODOS:
* Remove download -> All files are allready downloaded
* Does Views disappear?
* Add Security indicator
*/
......@@ -45,7 +44,7 @@ class ReadViewCoordinator {
AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in
})
let vc = UIHostingController(rootView: ReadMainView(mail: mail, coord: self))
let vc = UIHostingController(rootView: ReadMainView(mail: mail))
readView = vc
root.pushViewController(vc, animated: true)
}
......@@ -79,9 +78,6 @@ class ReadViewCoordinator {
func pushExportKeyView() {
//TODO: make this work
let vc = mainStoryboard.instantiateViewController(identifier: "exportKeyFromReadView")
if let vc = vc as? ImportKeyOverviewController {
//vc.wasPushed = true
}
root.isToolbarHidden = false
root.pushViewController(vc, animated: true)
}
......
......@@ -8,7 +8,7 @@
import SwiftUI
struct DialogView: View {
struct DialogView : View {
let option: DialogOption
var ctaAction: (() -> Void)?
......@@ -93,8 +93,8 @@ struct DialogView: View {
}
}
struct WarningMessageView_Previews: PreviewProvider {
/*
struct DialogView_Previews: PreviewProvider {
static var previews: some View {
VStack{
DialogView(option: .postcard, ctaAction: action, additionalAction: action, dismissAction: action)
......@@ -107,6 +107,7 @@ struct WarningMessageView_Previews: PreviewProvider {
print("Button click!")
}
}
*/
extension View {
public func addBorder<S>(_ content: S, width: CGFloat = 1, cornerRadius: CGFloat) -> some View where S : ShapeStyle {
......
......@@ -65,7 +65,6 @@
"KeyIsVerified" = "The Key is verified. It was verified on ";
"KeyNotFound" = "No Key Found. This is an error, contact the developers!";
"Letter" = "Confidential and genuine mail";
"Onboarding.headline"="Welcome";
"Onboarding.loginButtonText"="Login";
"Onboarding.loginButtonTextGoogle"="with";
......@@ -82,7 +81,6 @@
"Onboarding.loginDescription" = "Enter your email address and password to log in.";
"Onboarding.enterEmail"="Your email address:";
"Onboarding.enterPassword"="Your password:";
//onbarding authenticationView
"Your Password"="Your Password";
"Username"="Username";
......@@ -123,7 +121,7 @@
"ReadView.Icon.Association.Multi" = "The person sent you %@ confidential mails before."; // NEW
"ReadView.Icon.Secure.Expert" = "For experts: This mail was encrypted and signed.";
"ReadView.Icon.Advice" = "Think twice when clicking on links.";
"ReceiveInsecureInfo" = "We do not know if the sender address represents the real sender. Be aware that a fraud can impersonate the sender. But you, the sender and all mail providers know the content of the mail.";
"ReceiveInsecureInfo" = "We do not know if the sender address represents the real sender. Be aware that a fraud can impersonate the sender. You, the sender and all mail providers know the content of the mail.";
"ReadView.Icon.Insecure.Expert" = "For experts: This mail was neither encrypted nor signed.";
"ReadView.Icon.Key" = "We know that the sender can send confidential mails.";
"ReadView.Icon.NoKey" = "We do not know if the sender can send confidential mails.";
......@@ -365,5 +363,23 @@
"Feedback.Name" = "Feedback";
"MailView.MoreMails" = "See more mails";
"Searchbar.Title" = "Search";
"Gamification.Overview.HeaderTitle" = "Badge Case";
"Security.Dialog.Title.No.Crypto" = "Insecure";
"Security.Dialog.Title.Enc+Sign" = "Confidential and genuine mail";
"Security.Dialog.Title.UnableToDecrypt" = "Not readable mail";
"Security.Dialog.Title.InvalidSignature" = "Corrupted mail";
"Security.Dialog.Title.Plain+Sig" = "Genuine but not confidential mail";
"Security.Dialog.Title.PlainMissingPublicKeyToVerify" = "Not confidential mail";
"Security.Dialog.Title.Enc+NoSign" = "Confidential but not genuine mail";
"Security.Dialog.Title.EncMissingPublicKeyToVerify" = "Confidential mail";
"Security.Dialog.Body.EncButMissingPublicKeyToVerify" = "We can not verify the sender because sender's ID is missing. \nOnly you and the sender can read the content of the email.";
"Security.Dialog.Body.PlainMissingPublicKeyToVerify" = "We can not verify the sender because sender's ID is missing. \nYou, the sender and all involed email provider can read the content of the email.";
"Security.Dialog.Button.Title.MoreInfo" = "More information";
"Security.Dialog.Button.Title.OK" = "OK";
"Security.Dialog.Button.Title.Import.SK" = "Import own key";
"Security.Dialog.Button.Title.Ask.Resend.ForPK" = "Ask to resend";
"Security.Dialog.Button.Title.Ignore.Mail" = "Ignore mail";
"Security.Dialog.Button.Title.Confirmation" = "Ask for confirmation";
"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";
......@@ -169,7 +169,7 @@
<fetchRequest name="getMailAddress" entity="Mail_Address" predicateString="address == &quot;$adr&quot;"/>
<elements>
<element name="Account" positionX="-315" positionY="-36" width="128" height="255"/>
<element name="Attachment" positionX="-315" positionY="-36" width="128" height="210"/>
<element name="Attachment" positionX="-315" positionY="-36" width="128" height="208"/>
<element name="EnzevalosContact" positionX="-209" positionY="198" width="128" height="120"/>
<element name="Folder" positionX="-297" positionY="-18" width="128" height="240"/>
<element name="KeyRecord" positionX="-315" positionY="-36" width="128" height="163"/>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment